From 25253f6e767637fe87bc751dca7d1c9d1f8e6aa8 Mon Sep 17 00:00:00 2001 From: Mark Phelps <209477+markphelps@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:21:40 -0500 Subject: [PATCH 1/2] chore: rm clients as they are moving to seperate repo --- Cargo.toml | 3 - sdk/client/engine/Cargo.lock | 1340 --------- sdk/client/engine/Cargo.toml | 25 - sdk/client/engine/README.md | 33 - sdk/client/engine/examples/evaluation.rs | 24 - sdk/client/engine/src/evaluator/mod.rs | 2588 ----------------- sdk/client/engine/src/lib.rs | 216 -- sdk/client/engine/src/models/common/mod.rs | 75 - sdk/client/engine/src/models/flipt/mod.rs | 78 - sdk/client/engine/src/models/mod.rs | 3 - sdk/client/engine/src/models/transport/mod.rs | 84 - sdk/client/engine/src/store/mod.rs | 2 - sdk/client/engine/src/store/parsers.rs | 101 - sdk/client/engine/src/store/snapshot.rs | 369 --- sdk/client/engine/src/testdata/state.json | 105 - sdk/client/go/README.md | 54 - sdk/client/go/flipt-client-go/evaluation.go | 135 - sdk/client/go/flipt-client-go/go.mod | 3 - sdk/client/go/flipt-client-go/models.go | 39 - sdk/client/python/README.md | 30 - .../flipt_client_python/__init__.py | 81 - .../flipt_client_python/models.py | 40 - .../python/flipt-client-python/poetry.lock | 278 -- .../python/flipt-client-python/pyproject.toml | 17 - .../flipt-client-python/tests/__init__.py | 0 25 files changed, 5723 deletions(-) delete mode 100644 Cargo.toml delete mode 100644 sdk/client/engine/Cargo.lock delete mode 100644 sdk/client/engine/Cargo.toml delete mode 100644 sdk/client/engine/README.md delete mode 100644 sdk/client/engine/examples/evaluation.rs delete mode 100644 sdk/client/engine/src/evaluator/mod.rs delete mode 100644 sdk/client/engine/src/lib.rs delete mode 100644 sdk/client/engine/src/models/common/mod.rs delete mode 100644 sdk/client/engine/src/models/flipt/mod.rs delete mode 100644 sdk/client/engine/src/models/mod.rs delete mode 100644 sdk/client/engine/src/models/transport/mod.rs delete mode 100644 sdk/client/engine/src/store/mod.rs delete mode 100644 sdk/client/engine/src/store/parsers.rs delete mode 100644 sdk/client/engine/src/store/snapshot.rs delete mode 100644 sdk/client/engine/src/testdata/state.json delete mode 100644 sdk/client/go/README.md delete mode 100644 sdk/client/go/flipt-client-go/evaluation.go delete mode 100644 sdk/client/go/flipt-client-go/go.mod delete mode 100644 sdk/client/go/flipt-client-go/models.go delete mode 100644 sdk/client/python/README.md delete mode 100644 sdk/client/python/flipt-client-python/flipt_client_python/__init__.py delete mode 100644 sdk/client/python/flipt-client-python/flipt_client_python/models.py delete mode 100644 sdk/client/python/flipt-client-python/poetry.lock delete mode 100644 sdk/client/python/flipt-client-python/pyproject.toml delete mode 100644 sdk/client/python/flipt-client-python/tests/__init__.py diff --git a/Cargo.toml b/Cargo.toml deleted file mode 100644 index 05533bb902..0000000000 --- a/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[workspace] -resolver = "2" -members = ["./sdk/client/engine"] diff --git a/sdk/client/engine/Cargo.lock b/sdk/client/engine/Cargo.lock deleted file mode 100644 index 297289e965..0000000000 --- a/sdk/client/engine/Cargo.lock +++ /dev/null @@ -1,1340 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base64" -version = "0.21.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" - -[[package]] -name = "bumpalo" -version = "3.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" - -[[package]] -name = "bytes" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" - -[[package]] -name = "cc" -version = "1.0.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "encoding_rs" -version = "0.8.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "engine" -version = "0.1.0" -dependencies = [ - "chrono", - "crc32fast", - "futures", - "libc", - "reqwest", - "serde", - "serde_json", - "snafu", - "tokio", - "uuid", -] - -[[package]] -name = "errno" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "fastrand" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" - -[[package]] -name = "futures-executor" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" - -[[package]] -name = "futures-macro" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "futures-sink" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" - -[[package]] -name = "futures-task" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" - -[[package]] -name = "futures-util" -version = "0.3.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "getrandom" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "gimli" -version = "0.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" - -[[package]] -name = "h2" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.4.10", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "ipnet" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" - -[[package]] -name = "itoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" - -[[package]] -name = "js-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.150" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" - -[[package]] -name = "linux-raw-sys" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" - -[[package]] -name = "lock_api" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" - -[[package]] -name = "memchr" -version = "2.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" -dependencies = [ - "libc", - "wasi", - "windows-sys", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "num-traits" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "openssl" -version = "0.10.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dfc0783362704e97ef3bd24261995a699468440099ef95d869b4d9732f829a" -dependencies = [ - "bitflags 2.4.1", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f55da20b29f956fb01f0add8683eb26ee13ebe3ebd935e49898717c6b4b2830" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "percent-encoding" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" - -[[package]] -name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" - -[[package]] -name = "proc-macro2" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "reqwest" -version = "0.11.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustix" -version = "0.38.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" -dependencies = [ - "bitflags 2.4.1", - "errno", - "libc", - "linux-raw-sys", - "windows-sys", -] - -[[package]] -name = "ryu" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" - -[[package]] -name = "schannel" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "serde" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e422a44e74ad4001bdc8eede9a4570ab52f71190e9c076d14369f38b9200537" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.189" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e48d1f918009ce3145511378cf68d613e3b3d9137d67272562080d68a2b32d5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "serde_json" -version = "1.0.107" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" - -[[package]] -name = "snafu" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" -dependencies = [ - "doc-comment", - "snafu-derive", -] - -[[package]] -name = "snafu-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "socket2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "socket2" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall", - "rustix", - "windows-sys", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "num_cpus", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.5", - "tokio-macros", - "windows-sys", -] - -[[package]] -name = "tokio-macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "uuid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" -dependencies = [ - "getrandom", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.38", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.38", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" - -[[package]] -name = "web-sys" -version = "0.3.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-core" -version = "0.51.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "winreg" -version = "0.50.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys", -] diff --git a/sdk/client/engine/Cargo.toml b/sdk/client/engine/Cargo.toml deleted file mode 100644 index 33193827cc..0000000000 --- a/sdk/client/engine/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "flipt-client-engine" -version = "0.0.1" -edition = "2021" -authors = ["Flipt Devs "] -license = "MIT" - -[dependencies] -libc = "0.2.150" -reqwest = { version = "0.11.22", features = ["json", "blocking"] } -tokio = { version = "1.33.0", features = ["full"] } -serde = { version = "1.0.147", features = ["derive"] } -serde_json = { version = "1.0.89", features = ["raw_value"] } -uuid = { version = "1.5.0", features = ["v4"] } -crc32fast = "1.3.2" -snafu = "0.7.5" -chrono = { version = "0.4.31", features = ["serde", "rustc-serialize"] } -futures = "0.3" - -[dev-dependencies] -mockall = "0.11.4" - -[lib] -name = "engine" -crate-type = ["rlib", "dylib"] diff --git a/sdk/client/engine/README.md b/sdk/client/engine/README.md deleted file mode 100644 index 09bbd73231..0000000000 --- a/sdk/client/engine/README.md +++ /dev/null @@ -1,33 +0,0 @@ -# Flipt Client Engine - -![Status: Experimental](https://img.shields.io/badge/status-experimental-yellow) - -This is the client engine for Flipt. It is responsible for evaluating context provided by the native language client SDKs and returning the results of the evaluation. - -## Architecture - -The client engine is a Rust library responsible for evaluating context and returning the results of the evaluation. The client engine polls for evaluation state from the Flipt server and uses this state to determine the results of the evaluation. The client engine is designed to be embedded in the native language client SDKs. The native language client SDKs will send context to the client engine via [FFI](https://en.wikipedia.org/wiki/Foreign_function_interface) and receive the results of the evaluation from engine. - -This design allows for the client evaluation logic to be written once in a memory safe language and embedded in the native language client SDKs. This design also allows for the client engine to be updated independently of the native language client SDKs. - -TODO: Diagram - -## Development - -TODO: Add more details - -### Prerequisites - -- [Rust](https://www.rust-lang.org/tools/install) - -### Build - -```bash -cargo build -``` - -### Test - -```bash -cargo test -``` diff --git a/sdk/client/engine/examples/evaluation.rs b/sdk/client/engine/examples/evaluation.rs deleted file mode 100644 index eff01f8fbb..0000000000 --- a/sdk/client/engine/examples/evaluation.rs +++ /dev/null @@ -1,24 +0,0 @@ -// cargo run --example evaluation - -use engine::{self, evaluator}; -use std::collections::HashMap; - -fn main() { - let eng = engine::Engine::new(vec!["default".into()]); - let mut context: HashMap = HashMap::new(); - context.insert("fizz".into(), "buzz".into()); - - let thread = std::thread::spawn(move || loop { - std::thread::sleep(std::time::Duration::from_millis(5000)); - let variant = eng.variant(&evaluator::EvaluationRequest { - namespace_key: "default".into(), - flag_key: "flag1".into(), - entity_id: "entity".into(), - context: context.clone(), - }); - - println!("variant key {}", variant.unwrap().variant_key); - }); - - thread.join().expect("current thread panicked"); -} diff --git a/sdk/client/engine/src/evaluator/mod.rs b/sdk/client/engine/src/evaluator/mod.rs deleted file mode 100644 index ceea28bed3..0000000000 --- a/sdk/client/engine/src/evaluator/mod.rs +++ /dev/null @@ -1,2588 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::Serialize; -use snafu::{prelude::*, Whatever}; -use std::collections::HashMap; -use std::sync::{Arc, RwLock}; -use std::time::{Duration, SystemTime, SystemTimeError}; - -use crate::models::common; -use crate::models::flipt; -use crate::store::parsers; -use crate::store::snapshot::{Parser, Snapshot, Store}; - -const DEFAULT_PERCENT: f32 = 100.0; -const DEFAULT_TOTAL_BUCKET_NUMBER: u32 = 1000; -const DEFAULT_PERCENT_MULTIPIER: f32 = DEFAULT_TOTAL_BUCKET_NUMBER as f32 / DEFAULT_PERCENT; - -pub struct Evaluator { - flipt_parser: Box, - snapshot: Box, - mtx: Arc>, -} - -#[repr(C)] -pub struct EvaluationRequest { - pub namespace_key: String, - pub flag_key: String, - pub entity_id: String, - pub context: HashMap, -} - -#[derive(Serialize)] -pub struct VariantEvaluationResponse { - pub r#match: bool, - pub segment_keys: Vec, - pub reason: common::EvaluationReason, - pub flag_key: String, - pub variant_key: String, - pub variant_attachment: String, - pub request_duration_millis: f64, - pub timestamp: DateTime, -} - -#[derive(Serialize)] -pub struct BooleanEvaluationResponse { - pub enabled: bool, - pub flag_key: String, - pub reason: common::EvaluationReason, - pub request_duration_millis: f64, - pub timestamp: DateTime, -} - -pub struct ErrorEvaluationResponse { - pub flag_key: String, - pub reason: common::ErrorEvaluationReason, -} - -pub trait EvaluationResponse {} - -impl EvaluationResponse for VariantEvaluationResponse {} -impl EvaluationResponse for BooleanEvaluationResponse {} -impl EvaluationResponse for ErrorEvaluationResponse {} - -impl Default for VariantEvaluationResponse { - fn default() -> Self { - Self { - r#match: false, - segment_keys: Vec::new(), - reason: common::EvaluationReason::Unknown, - flag_key: String::from(""), - variant_key: String::from(""), - variant_attachment: String::from(""), - request_duration_millis: 0.0, - timestamp: chrono::offset::Utc::now(), - } - } -} - -impl Default for BooleanEvaluationResponse { - fn default() -> Self { - Self { - enabled: false, - flag_key: String::from(""), - reason: common::EvaluationReason::Unknown, - request_duration_millis: 0.0, - timestamp: chrono::offset::Utc::now(), - } - } -} - -impl Default for ErrorEvaluationResponse { - fn default() -> Self { - Self { - flag_key: String::from(""), - reason: common::ErrorEvaluationReason::Unknown, - } - } -} - -type VariantEvaluationResult = std::result::Result; - -type BooleanEvaluationResult = std::result::Result; - -impl Evaluator { - pub fn new(namespaces: Vec) -> Result { - let flipt_parser = parsers::FliptParser::new(namespaces.clone()); - let snap = Snapshot::build(&flipt_parser)?; - - Ok(Self { - flipt_parser: Box::new(flipt_parser), - snapshot: Box::new(snap), - mtx: Arc::new(RwLock::new(0)), - }) - } - - pub fn replace_snapshot(&mut self) { - let _w_lock = self.mtx.write().unwrap(); - let snap = Snapshot::build(self.flipt_parser.as_ref()); - self.snapshot = Box::new(snap.unwrap()); - } - - pub fn variant( - &self, - evaluation_request: &EvaluationRequest, - ) -> VariantEvaluationResult { - let _r_lock = self.mtx.read().unwrap(); - let flag = match self.snapshot.get_flag( - &evaluation_request.namespace_key, - &evaluation_request.flag_key, - ) { - Some(f) => { - if f.r#type != common::FlagType::Variant { - whatever!("{} is not a variant flag", &evaluation_request.flag_key); - } - f - } - None => whatever!( - "failed to get flag information {}/{}", - &evaluation_request.namespace_key, - &evaluation_request.flag_key - ), - }; - - self.variant_evaluation(&flag, evaluation_request) - } - - pub fn boolean( - &self, - evaluation_request: &EvaluationRequest, - ) -> BooleanEvaluationResult { - let _r_lock = self.mtx.read().unwrap(); - let flag = match self.snapshot.get_flag( - &evaluation_request.namespace_key, - &evaluation_request.flag_key, - ) { - Some(f) => { - if f.r#type != common::FlagType::Boolean { - whatever!("{} is not a boolean flag", &evaluation_request.flag_key); - } - f - } - None => whatever!( - "failed to get flag information {}/{}", - &evaluation_request.namespace_key, - &evaluation_request.flag_key - ), - }; - - self.boolean_evaluation(&flag, evaluation_request) - } - - pub fn batch( - &self, - requests: Vec, - ) -> Result>, Whatever> { - let mut evaluation_responses: Vec> = Vec::new(); - - for request in requests { - let flag = match self - .snapshot - .get_flag(&request.namespace_key, &request.flag_key) - { - Some(f) => f, - None => { - evaluation_responses.push(Box::new(ErrorEvaluationResponse { - flag_key: request.flag_key.clone(), - reason: common::ErrorEvaluationReason::NotFound, - })); - continue; - } - }; - - match flag.r#type { - common::FlagType::Boolean => { - match self.boolean_evaluation(&flag, &request) { - Ok(b) => { - evaluation_responses.push(Box::new(b)); - } - Err(e) => { - return Err(e); - } - }; - } - common::FlagType::Variant => { - match self.variant_evaluation(&flag, &request) { - Ok(v) => { - evaluation_responses.push(Box::new(v)); - } - Err(e) => { - return Err(e); - } - }; - } - } - } - - Ok(evaluation_responses) - } - - fn variant_evaluation( - &self, - flag: &flipt::Flag, - evaluation_request: &EvaluationRequest, - ) -> VariantEvaluationResult { - let now = SystemTime::now(); - let mut last_rank = 0; - - let mut variant_evaluation_response = VariantEvaluationResponse { - flag_key: flag.key.clone(), - ..Default::default() - }; - - if !flag.enabled { - variant_evaluation_response.reason = common::EvaluationReason::FlagDisabled; - variant_evaluation_response.request_duration_millis = - get_duration_millis(now.elapsed())?; - return Ok(variant_evaluation_response); - } - - let evaluation_rules = match self.snapshot.get_evaluation_rules( - &evaluation_request.namespace_key, - &evaluation_request.flag_key, - ) { - Some(evaluation_rules) => evaluation_rules, - None => whatever!( - "error getting evaluation rules for namespace {} and flag {}", - evaluation_request.namespace_key.clone(), - evaluation_request.flag_key.clone() - ), - }; - - for rule in evaluation_rules { - if rule.rank < last_rank { - whatever!("rule rank: {} detected out of order", rule.rank); - } - - last_rank = rule.rank; - - let mut segment_keys: Vec = Vec::new(); - let mut segment_matches = 0; - - for kv in &rule.segments { - let matched = match self.matches_constraints( - &evaluation_request.context, - &kv.1.constraints, - &kv.1.match_type, - ) { - Ok(b) => b, - Err(err) => return Err(err), - }; - - if matched { - segment_keys.push(kv.0.into()); - segment_matches += 1; - } - } - - if rule.segment_operator == common::SegmentOperator::Or { - if segment_matches < 1 { - continue; - } - } else if rule.segment_operator == common::SegmentOperator::And - && rule.segments.len() != segment_matches - { - continue; - } - - variant_evaluation_response.segment_keys = segment_keys; - - let distributions = match self - .snapshot - .get_evaluation_distributions(&evaluation_request.namespace_key, &rule.id) - { - Some(evaluation_distributions) => evaluation_distributions, - None => whatever!( - "error getting evaluation distributions for namespace {} and rule {}", - evaluation_request.namespace_key.clone(), - rule.id.clone() - ), - }; - - let mut valid_distributions: Vec = Vec::new(); - let mut buckets: Vec = Vec::new(); - - for distribution in distributions { - if distribution.rollout > 0.0 { - valid_distributions.push(distribution.clone()); - - if buckets.is_empty() { - let bucket = (distribution.rollout * DEFAULT_PERCENT_MULTIPIER) as i32; - buckets.push(bucket); - } else { - let bucket = buckets[buckets.len() - 1] - + (distribution.rollout * DEFAULT_PERCENT_MULTIPIER) as i32; - buckets.push(bucket); - } - } - } - - // no distributions for the rule - if valid_distributions.is_empty() { - variant_evaluation_response.r#match = true; - variant_evaluation_response.reason = common::EvaluationReason::Match; - variant_evaluation_response.request_duration_millis = - get_duration_millis(now.elapsed())?; - return Ok(variant_evaluation_response); - } - - let bucket = crc32fast::hash( - format!( - "{}{}", - evaluation_request.flag_key, evaluation_request.entity_id - ) - .as_bytes(), - ) as u32 - % DEFAULT_TOTAL_BUCKET_NUMBER; - - buckets.sort(); - - let index = match buckets.binary_search(&(bucket as i32)) { - Ok(idx) => idx, - Err(idx) => idx, - }; - - if index == valid_distributions.len() { - variant_evaluation_response.r#match = false; - variant_evaluation_response.request_duration_millis = - get_duration_millis(now.elapsed())?; - return Ok(variant_evaluation_response); - } - - let d = &valid_distributions[index]; - - variant_evaluation_response.r#match = true; - variant_evaluation_response.variant_key = d.variant_key.clone(); - variant_evaluation_response.variant_attachment = d.variant_attachment.clone(); - variant_evaluation_response.reason = common::EvaluationReason::Match; - variant_evaluation_response.request_duration_millis = - get_duration_millis(now.elapsed())?; - return Ok(variant_evaluation_response); - } - - Ok(variant_evaluation_response) - } - - fn boolean_evaluation( - &self, - flag: &flipt::Flag, - evaluation_request: &EvaluationRequest, - ) -> BooleanEvaluationResult { - let now = SystemTime::now(); - let mut last_rank = 0; - - let evaluation_rollouts = match self.snapshot.get_evaluation_rollouts( - &evaluation_request.namespace_key, - &evaluation_request.flag_key, - ) { - Some(rollouts) => rollouts, - None => whatever!( - "error getting evaluation rollouts for namespace {} and flag {}", - evaluation_request.namespace_key.clone(), - evaluation_request.flag_key.clone() - ), - }; - - for rollout in evaluation_rollouts { - if rollout.rank < last_rank { - whatever!("rollout rank: {} detected out of order", rollout.rank); - } - - last_rank = rollout.rank; - - if rollout.threshold.is_some() { - let threshold = rollout.threshold.unwrap(); - - let normalized_value = (crc32fast::hash( - format!( - "{}{}", - evaluation_request.entity_id, evaluation_request.flag_key - ) - .as_bytes(), - ) as i32 - % 100) as f32; - - if normalized_value < threshold.percentage { - return Ok(BooleanEvaluationResponse { - enabled: threshold.value, - flag_key: flag.key.clone(), - reason: common::EvaluationReason::Match, - request_duration_millis: get_duration_millis(now.elapsed())?, - timestamp: chrono::offset::Utc::now(), - }); - } - } else if rollout.segment.is_some() { - let segment = rollout.segment.unwrap(); - let mut segment_matches = 0; - - for s in &segment.segments { - let matched = match self.matches_constraints( - &evaluation_request.context, - &s.1.constraints, - &s.1.match_type, - ) { - Ok(v) => v, - Err(err) => return Err(err), - }; - - if matched { - segment_matches += 1; - } - } - - if segment.segment_operator == common::SegmentOperator::Or { - if segment_matches < 1 { - continue; - } - } else if segment.segment_operator == common::SegmentOperator::And - && segment.segments.len() != segment_matches - { - continue; - } - - return Ok(BooleanEvaluationResponse { - enabled: segment.value, - flag_key: flag.key.clone(), - reason: common::EvaluationReason::Match, - request_duration_millis: get_duration_millis(now.elapsed())?, - timestamp: chrono::offset::Utc::now(), - }); - } - } - - Ok(BooleanEvaluationResponse { - enabled: flag.enabled, - flag_key: flag.key.clone(), - reason: common::EvaluationReason::Default, - request_duration_millis: get_duration_millis(now.elapsed())?, - timestamp: chrono::offset::Utc::now(), - }) - } - - fn matches_constraints( - &self, - eval_context: &HashMap, - constraints: &Vec, - segment_match_type: &common::SegmentMatchType, - ) -> Result { - let mut constraint_matches: usize = 0; - - for constraint in constraints { - let value = match eval_context.get(&constraint.property) { - Some(v) => v, - None => continue, - }; - - let matched = match constraint.r#type { - common::ConstraintComparisonType::String => matches_string(constraint, value), - common::ConstraintComparisonType::Number => matches_number(constraint, value)?, - common::ConstraintComparisonType::Boolean => matches_boolean(constraint, value)?, - common::ConstraintComparisonType::DateTime => matches_datetime(constraint, value)?, - _ => { - return Ok(false); - } - }; - - if matched { - constraint_matches += 1; - - if segment_match_type == &common::SegmentMatchType::Any { - break; - } else { - continue; - } - } else if segment_match_type == &common::SegmentMatchType::All { - break; - } else { - continue; - } - } - - let is_match = match segment_match_type { - common::SegmentMatchType::All => constraints.len() == constraint_matches, - common::SegmentMatchType::Any => constraints.is_empty() || constraint_matches != 0, - }; - - Ok(is_match) - } -} - -fn matches_string(evaluation_constraint: &flipt::EvaluationConstraint, v: &str) -> bool { - let operator = evaluation_constraint.operator.as_str(); - - match operator { - "empty" => { - return v.is_empty(); - } - "notempty" => { - return !v.is_empty(); - } - _ => {} - } - - if v.is_empty() { - return false; - } - - let value = evaluation_constraint.value.as_str(); - match operator { - "eq" => v == value, - "neq" => v != value, - "prefix" => v.starts_with(value), - "suffix" => v.ends_with(value), - _ => false, - } -} - -fn matches_number( - evaluation_constraint: &flipt::EvaluationConstraint, - v: &str, -) -> Result { - let operator = evaluation_constraint.operator.as_str(); - - match operator { - "notpresent" => { - return Ok(v.is_empty()); - } - "present" => { - return Ok(!v.is_empty()); - } - _ => {} - } - - if v.is_empty() { - return Ok(false); - } - - let v_number = match v.parse::() { - Ok(v) => v, - Err(err) => whatever!("error parsing number {}, err: {}", v, err), - }; - - let value_number = match evaluation_constraint.value.parse::() { - Ok(v) => v, - Err(err) => whatever!( - "error parsing number {}, err: {}", - evaluation_constraint.value, - err - ), - }; - - match operator { - "eq" => Ok(v_number == value_number), - "neq" => Ok(v_number != value_number), - "lt" => Ok(v_number < value_number), - "lte" => Ok(v_number <= value_number), - "gt" => Ok(v_number > value_number), - "gte" => Ok(v_number >= value_number), - _ => Ok(false), - } -} - -fn matches_boolean( - evaluation_constraint: &flipt::EvaluationConstraint, - v: &str, -) -> Result { - let operator = evaluation_constraint.operator.as_str(); - - match operator { - "notpresent" => { - return Ok(v.is_empty()); - } - "present" => { - return Ok(!v.is_empty()); - } - _ => {} - } - - if v.is_empty() { - return Ok(false); - } - - let v_bool = match v.parse::() { - Ok(v) => v, - Err(err) => whatever!("error parsing boolean {}: err {}", v, err), - }; - - match operator { - "true" => Ok(v_bool), - "false" => Ok(!v_bool), - _ => Ok(false), - } -} - -fn matches_datetime( - evaluation_constraint: &flipt::EvaluationConstraint, - v: &str, -) -> Result { - let operator = evaluation_constraint.operator.as_str(); - - match operator { - "notpresent" => { - return Ok(v.is_empty()); - } - "present" => { - return Ok(!v.is_empty()); - } - _ => {} - } - - if v.is_empty() { - return Ok(false); - } - - let d = match DateTime::parse_from_rfc3339(v) { - Ok(t) => t.timestamp(), - Err(e) => whatever!("error parsing time {}, err: {}", v, e), - }; - - let value = match DateTime::parse_from_rfc3339(&evaluation_constraint.value) { - Ok(t) => t.timestamp(), - Err(e) => whatever!( - "error parsing time {}, err: {}", - &evaluation_constraint.value, - e - ), - }; - - match operator { - "eq" => Ok(d == value), - "neq" => Ok(d != value), - "lt" => Ok(d < value), - "lte" => Ok(d <= value), - "gt" => Ok(d > value), - "gte" => Ok(d >= value), - _ => Ok(false), - } -} - -fn get_duration_millis(elapsed: Result) -> Result { - match elapsed { - Ok(elapsed) => Ok(elapsed.as_secs_f64() * 1000.0), - Err(e) => { - whatever!("error getting duration {}", e) - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::models::common; - use crate::models::flipt; - use crate::store::parsers::TestParser; - use crate::store::snapshot::MockStore; - - macro_rules! matches_string_tests { - ($($name:ident: $value:expr,)*) => { - $( - #[test] - fn $name() { - let (first, second, expected) = $value; - assert_eq!(expected, matches_string(first, second)); - } - )* - } - } - - macro_rules! matches_datetime_tests { - ($($name:ident: $value:expr,)*) => { - $( - #[test] - fn $name() { - let (first, second, expected) = $value; - assert_eq!(expected, matches_datetime(first, second).unwrap()); - } - )* - } - } - - macro_rules! matches_number_tests { - ($($name:ident: $value:expr,)*) => { - $( - #[test] - fn $name() { - let (first, second, expected) = $value; - assert_eq!(expected, matches_number(first, second).unwrap()); - } - )* - } - } - - matches_string_tests! { - string_eq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::String, - property: String::from("number"), - operator: String::from("eq"), - value: String::from("number"), - }, "number", true), - string_neq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::String, - property: String::from("number"), - operator: String::from("neq"), - value: String::from("number"), - }, "num", true), - string_prefix: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::String, - property: String::from("number"), - operator: String::from("prefix"), - value: String::from("num"), - }, "number", true), - string_suffix: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::String, - property: String::from("number"), - operator: String::from("suffix"), - value: String::from("ber"), - }, "number", true), - } - - matches_datetime_tests! { - datetime_eq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("eq"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T15:04:05Z", true), - datetime_neq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("neq"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T15:03:05Z", true), - datetime_lt: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("lt"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T14:03:05Z", true), - datetime_gt: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("gt"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T16:03:05Z", true), - datetime_lte: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("lte"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T15:04:05Z", true), - datetime_gte: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::DateTime, - property: String::from("date"), - operator: String::from("gte"), - value: String::from("2006-01-02T15:04:05Z"), - }, "2006-01-02T16:03:05Z", true), - - } - - matches_number_tests! { - number_eq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("eq"), - value: String::from("1"), - }, "1", true), - number_neq: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("neq"), - value: String::from("1"), - }, "0", true), - number_lt: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("lt"), - value: String::from("4"), - }, "3", true), - number_gt: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("gt"), - value: String::from("3"), - }, "4", true), - number_lte: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("date"), - operator: String::from("lte"), - value: String::from("3"), - }, "3", true), - number_gte: (&flipt::EvaluationConstraint{ - r#type: common::ConstraintComparisonType::Number, - property: String::from("date"), - operator: String::from("gte"), - value: String::from("3"), - }, "4", true), - - } - - #[test] - fn test_matches_boolean_success() { - let value_one = matches_boolean( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("fizz"), - operator: String::from("true"), - value: "".into(), - }, - "true", - ) - .expect("boolean should be parsed correctly"); - - assert!(value_one); - - let value_two = matches_boolean( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("fizz"), - operator: String::from("false"), - value: "".into(), - }, - "false", - ) - .expect("boolean should be parsed correctly"); - - assert!(value_two); - } - - #[test] - fn test_matches_boolean_failure() { - let result = matches_boolean( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("fizz"), - operator: String::from("true"), - value: "".into(), - }, - "blah", - ); - - assert!(!result.is_ok()); - assert_eq!( - result.err().unwrap().to_string(), - "error parsing boolean blah: err provided string was not `true` or `false`" - ); - } - - #[test] - fn test_matches_number_failure() { - let result_one = matches_number( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("eq"), - value: String::from("9"), - }, - "notanumber", - ); - - assert!(!result_one.is_ok()); - assert_eq!( - result_one.err().unwrap().to_string(), - "error parsing number notanumber, err: invalid digit found in string" - ); - - let result_two = matches_number( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Number, - property: String::from("number"), - operator: String::from("eq"), - value: String::from("notanumber"), - }, - "9", - ); - - assert!(!result_two.is_ok()); - assert_eq!( - result_two.err().unwrap().to_string(), - "error parsing number notanumber, err: invalid digit found in string" - ); - } - - #[test] - fn test_matches_datetime_failure() { - let result_one = matches_datetime( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("date"), - operator: String::from("eq"), - value: String::from("blah"), - }, - "2006-01-02T15:04:05Z", - ); - - assert!(!result_one.is_ok()); - assert_eq!( - result_one.err().unwrap().to_string(), - "error parsing time blah, err: input contains invalid characters" - ); - - let result_two = matches_datetime( - &flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("date"), - operator: String::from("eq"), - value: String::from("2006-01-02T15:04:05Z"), - }, - "blah", - ); - - assert!(!result_two.is_ok()); - assert_eq!( - result_two.err().unwrap().to_string(), - "error parsing time blah, err: input contains invalid characters" - ); - } - - // Segment Match Type ALL - #[test] - fn test_evaluator_match_all_no_variants_no_distributions() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::Or, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| Some(vec![])); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("foo"), String::from("bar")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert_eq!(v.r#match, true); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_all_multiple_segments() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::All, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("company"), - operator: String::from("eq"), - value: String::from("flipt"), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| Some(vec![])); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("foo"), String::from("bar")); - context.insert(String::from("company"), String::from("flipt")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("boz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(!v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Unknown); - assert!(v.segment_keys.is_empty()); - } - - #[test] - fn test_evaluator_match_all_distribution_not_matched() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::All, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("admin"), - operator: String::from("true"), - value: String::from(""), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 10.0, - }]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("foo"), String::from("bar")); - context.insert(String::from("admin"), String::from("true")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("123"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(!v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Unknown); - } - - #[test] - fn test_evaluator_match_all_single_variant_distribution() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::All, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("admin"), - operator: String::from("true"), - value: String::from(""), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(r#"{"foo": "bar"}"#), - rollout: 100.0, - }]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("foo"), String::from("bar")); - context.insert(String::from("admin"), String::from("true")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("123"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.variant_attachment, String::from(r#"{"foo": "bar"}"#)); - assert!(v - .segment_keys - .iter() - .any(|segment_key| segment_key == "segment1"),); - assert!(v - .segment_keys - .iter() - .any(|segment_key| segment_key == "segment2"),); - } - - #[test] - fn test_evaluator_match_all_rollout_distribution() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("foo"), String::from("bar")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("2"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_all_rollout_distribution_multi_rule() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("premium_user"), - operator: String::from("true"), - value: String::from(""), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - let mut segments_two: HashMap = HashMap::new(); - segments_two.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::All, - constraints: vec![], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![ - flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }, - flipt::EvaluationRule { - id: String::from("2"), - flag_key: String::from("foo"), - segments: segments_two.clone(), - rank: 2, - segment_operator: common::SegmentOperator::And, - }, - ]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("premium_user"), String::from("true")); - context.insert(String::from("foo"), String::from("bar")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_all_no_constraints() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::All, - constraints: vec![], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let context: HashMap = HashMap::new(); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("10"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("01"), - context: context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - // Segment Match Type ANY - #[test] - fn test_evaluator_match_any_no_variants_no_distributions() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::Or, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| Some(vec![])); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("baz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert_eq!(v.r#match, true); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_any_multiple_segments() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("company"), - operator: String::from("eq"), - value: String::from("flipt"), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| Some(vec![])); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("company"), String::from("flipt")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - - let mut context: HashMap = HashMap::new(); - context.insert(String::from("bar"), String::from("boz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("entity"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(!v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Unknown); - assert!(v.segment_keys.is_empty()); - } - - #[test] - fn test_evaluator_match_any_distribution_not_matched() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("admin"), - operator: String::from("true"), - value: String::from(""), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 10.0, - }]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("admin"), String::from("true")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("123"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(!v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Unknown); - } - - #[test] - fn test_evaluator_match_any_single_variant_distribution() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - segments.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("admin"), - operator: String::from("true"), - value: String::from(""), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(r#"{"foo": "bar"}"#), - rollout: 100.0, - }]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - context.insert(String::from("admin"), String::from("true")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("123"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.variant_attachment, String::from(r#"{"foo": "bar"}"#)); - } - - #[test] - fn test_evaluator_match_any_rollout_distribution() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("2"), - context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_any_rollout_distribution_multi_rule() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![ - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::Boolean, - property: String::from("premium_user"), - operator: String::from("true"), - value: String::from(""), - }, - flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("foo"), - operator: String::from("eq"), - value: String::from("bar"), - }, - ], - }, - ); - - let mut segments_two: HashMap = HashMap::new(); - segments_two.insert( - String::from("segment2"), - flipt::EvaluationSegment { - segment_key: String::from("segment2"), - match_type: common::SegmentMatchType::Any, - constraints: vec![], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![ - flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }, - flipt::EvaluationRule { - id: String::from("2"), - flag_key: String::from("foo"), - segments: segments_two.clone(), - rank: 2, - segment_operator: common::SegmentOperator::And, - }, - ]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("premium_user"), String::from("true")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_match_any_no_constraints() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 50.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("10"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant1")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("01"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - - context.insert(String::from("foo"), String::from("bar")); - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("01"), - context: context, - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - // Test cases where rollouts have a zero value - #[test] - fn test_evaluator_first_rollout_rule_zero() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 0.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 100.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant2")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } - - #[test] - fn test_evaluator_multiple_zero_rollout_distributions() { - let test_parser = TestParser::new(vec!["default".into()]); - let mut mock_store = MockStore::new(); - - mock_store.expect_get_flag().returning(|_, _| { - Some(flipt::Flag { - key: String::from("foo"), - enabled: true, - r#type: common::FlagType::Variant, - }) - }); - - let mut segments: HashMap = HashMap::new(); - segments.insert( - String::from("segment1"), - flipt::EvaluationSegment { - segment_key: String::from("segment1"), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: String::from("bar"), - operator: String::from("eq"), - value: String::from("baz"), - }], - }, - ); - - mock_store - .expect_get_evaluation_rules() - .returning(move |_, _| { - Some(vec![flipt::EvaluationRule { - id: String::from("1"), - flag_key: String::from("foo"), - segments: segments.clone(), - rank: 1, - segment_operator: common::SegmentOperator::And, - }]) - }); - - mock_store - .expect_get_evaluation_distributions() - .returning(|_, _| { - Some(vec![ - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant1"), - variant_attachment: String::from(""), - rollout: 0.0, - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant2"), - rollout: 0.0, - variant_attachment: String::from(""), - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant3"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant4"), - rollout: 0.0, - variant_attachment: String::from(""), - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant5"), - rollout: 0.0, - variant_attachment: String::from(""), - }, - flipt::EvaluationDistribution { - rule_id: String::from("1"), - variant_key: String::from("variant6"), - rollout: 50.0, - variant_attachment: String::from(""), - }, - ]) - }); - - let evaluator = &Evaluator { - flipt_parser: Box::new(test_parser), - snapshot: Box::new(mock_store), - mtx: Arc::new(RwLock::new(0)), - }; - - let mut context: HashMap = HashMap::new(); - - context.insert(String::from("bar"), String::from("baz")); - - let variant = evaluator.variant(&EvaluationRequest { - namespace_key: String::from("default"), - flag_key: String::from("foo"), - entity_id: String::from("1"), - context: context.clone(), - }); - - assert!(variant.is_ok()); - - let v = variant.unwrap(); - - assert_eq!(v.flag_key, String::from("foo")); - assert!(v.r#match); - assert_eq!(v.reason, common::EvaluationReason::Match); - assert_eq!(v.variant_key, String::from("variant3")); - assert_eq!(v.segment_keys, vec![String::from("segment1")]); - } -} diff --git a/sdk/client/engine/src/lib.rs b/sdk/client/engine/src/lib.rs deleted file mode 100644 index a9b83f13dd..0000000000 --- a/sdk/client/engine/src/lib.rs +++ /dev/null @@ -1,216 +0,0 @@ -use libc::c_void; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use snafu::{prelude::*, Whatever}; -use std::collections::HashMap; -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; -use std::sync::{Arc, Mutex}; - -pub mod evaluator; -mod models; -mod store; - -#[derive(Deserialize)] -struct EvaluationReq { - namespace_key: String, - flag_key: String, - entity_id: String, - context: String, -} - -pub struct Engine { - pub evaluator: Arc>, -} - -impl Engine { - pub fn new(namespaces: Vec) -> Self { - let evaluation_engine = evaluator::Evaluator::new(namespaces); - - let mut evaluator = Self { - evaluator: Arc::new(Mutex::new(evaluation_engine.unwrap())), - }; - - evaluator.update(); - - evaluator - } - - fn update(&mut self) { - let evaluator = self.evaluator.clone(); - let update_interval = std::env::var("FLIPT_UPDATE_INTERVAL") - .unwrap_or("120".into()) - .parse::() - .unwrap_or(120); - - std::thread::spawn(move || loop { - std::thread::sleep(std::time::Duration::from_secs(update_interval)); - let mut lock = evaluator.lock().unwrap(); - lock.replace_snapshot(); - }); - } - - pub fn variant( - &self, - evaluation_request: &evaluator::EvaluationRequest, - ) -> Result { - let binding = self.evaluator.clone(); - let lock = binding.lock().unwrap(); - - lock.variant(evaluation_request) - } - - pub fn boolean( - &self, - evaluation_request: &evaluator::EvaluationRequest, - ) -> Result { - let binding = self.evaluator.clone(); - let lock = binding.lock().unwrap(); - - lock.boolean(evaluation_request) - } -} - -#[derive(Serialize)] -struct FFIResponse -where - T: Serialize, -{ - status: Status, - result: Option, - error_message: Option, -} - -#[derive(Serialize)] -enum Status { - #[serde(rename = "success")] - Success, - #[serde(rename = "failure")] - Failure, -} - -impl From> for FFIResponse -where - T: Serialize, -{ - fn from(value: Result) -> Self { - match value { - Ok(result) => FFIResponse { - status: Status::Success, - result: Some(result), - error_message: None, - }, - Err(e) => FFIResponse { - status: Status::Failure, - result: None, - error_message: Some(e.to_string()), - }, - } - } -} - -fn result_to_json_ptr(result: Result) -> *mut c_char { - let ffi_response: FFIResponse = result.into(); - let json_string = serde_json::to_string(&ffi_response).unwrap(); - CString::new(json_string).unwrap().into_raw() -} - -/// # Safety -/// -/// This function should not be called unless an Engine is initiated. It provides a helper -/// utility to retrieve an Engine instance for evaluation use. -unsafe fn get_engine<'a>(engine_ptr: *mut c_void) -> Result<&'a mut Engine, Whatever> { - if engine_ptr.is_null() { - whatever!("null pointer engine error"); - } else { - Ok(unsafe { &mut *(engine_ptr as *mut Engine) }) - } -} - -/// # Safety -/// -/// This function will initialize an Engine and return a pointer back to the caller. -#[no_mangle] -pub unsafe extern "C" fn initialize_engine(namespaces: *const *const c_char) -> *mut c_void { - let mut index = 0; - let mut namespaces_vec = Vec::new(); - - while !(*namespaces.offset(index)).is_null() { - let c_str = CStr::from_ptr(*namespaces.offset(index)); - if let Ok(rust_str) = c_str.to_str() { - namespaces_vec.push(rust_str.to_string()); - } - - index += 1; - } - - Box::into_raw(Box::new(Engine::new(namespaces_vec))) as *mut c_void -} - -/// # Safety -/// -/// This function will take in a pointer to the engine and return a variant evaluation response. -#[no_mangle] -pub unsafe extern "C" fn variant( - engine_ptr: *mut c_void, - evaluation_request: *const c_char, -) -> *const c_char { - let e = get_engine(engine_ptr).unwrap(); - let e_req = get_evaluation_request(evaluation_request); - - result_to_json_ptr(e.variant(&e_req)) -} - -/// # Safety -/// -/// This function will take in a pointer to the engine and return a boolean evaluation response. -#[no_mangle] -pub unsafe extern "C" fn boolean( - engine_ptr: *mut c_void, - evaluation_request: *const c_char, -) -> *const c_char { - let e = get_engine(engine_ptr).unwrap(); - let e_req = get_evaluation_request(evaluation_request); - - result_to_json_ptr(e.boolean(&e_req)) -} - -unsafe fn get_evaluation_request( - evaluation_request: *const c_char, -) -> evaluator::EvaluationRequest { - let evaluation_request_bytes = CStr::from_ptr(evaluation_request).to_bytes(); - let bytes_str_repr = std::str::from_utf8(evaluation_request_bytes).unwrap(); - - let client_eval_request: EvaluationReq = serde_json::from_str(bytes_str_repr).unwrap(); - - let parsed_context: serde_json::Value = - serde_json::from_str(&client_eval_request.context).unwrap(); - - let mut context_map: HashMap = HashMap::new(); - if let serde_json::Value::Object(map) = parsed_context { - for (key, value) in map { - if let Value::String(val) = value { - context_map.insert(key, val); - } - } - } - - evaluator::EvaluationRequest { - namespace_key: client_eval_request.namespace_key, - flag_key: client_eval_request.flag_key, - entity_id: client_eval_request.entity_id, - context: context_map, - } -} - -/// # Safety -/// -/// This function will free the memory occupied by the engine. -#[no_mangle] -pub unsafe extern "C" fn destroy_engine(engine_ptr: *mut c_void) { - if engine_ptr.is_null() { - return; - } - - drop(Box::from_raw(engine_ptr as *mut Engine)); -} diff --git a/sdk/client/engine/src/models/common/mod.rs b/sdk/client/engine/src/models/common/mod.rs deleted file mode 100644 index 92036bf80d..0000000000 --- a/sdk/client/engine/src/models/common/mod.rs +++ /dev/null @@ -1,75 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] -pub enum FlagType { - #[default] - #[serde(rename = "VARIANT_FLAG_TYPE")] - Variant, - #[serde(rename = "BOOLEAN_FLAG_TYPE")] - Boolean, -} - -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] -pub enum SegmentOperator { - #[default] - #[serde(rename = "OR_SEGMENT_OPERATOR")] - Or, - #[serde(rename = "AND_SEGMENT_OPERATOR")] - And, -} - -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] -pub enum SegmentMatchType { - #[default] - #[serde(rename = "ANY_SEGMENT_MATCH_TYPE")] - Any, - #[serde(rename = "ALL_SEGMENT_MATCH_TYPE")] - All, -} - -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] -pub enum ConstraintComparisonType { - #[default] - #[serde(rename = "UNKNOWN_CONSTRAINT_COMPARISON_TYPE")] - Unknown, - #[serde(rename = "STRING_CONSTRAINT_COMPARISON_TYPE")] - String, - #[serde(rename = "NUMBER_CONSTRAINT_COMPARISON_TYPE")] - Number, - #[serde(rename = "BOOLEAN_CONSTRAINT_COMPARISON_TYPE")] - Boolean, - #[serde(rename = "DATETIME_CONSTRAINT_COMPARISON_TYPE")] - DateTime, -} - -#[derive(Clone, Debug, Default, Deserialize, PartialEq)] -pub enum RolloutType { - #[default] - #[serde(rename = "UNKNOWN_ROLLOUT_TYPE")] - Unknown, - #[serde(rename = "SEGMENT_ROLLOUT_TYPE")] - Segment, - #[serde(rename = "THRESHOLD_ROLLOUT_TYPE")] - Threshold, -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] -pub enum EvaluationReason { - #[default] - #[serde(rename = "UNKNOWN_EVALUATION_REASON")] - Unknown, - #[serde(rename = "FLAG_DISABLED_EVALUATION_REASON")] - FlagDisabled, - #[serde(rename = "MATCH_EVALUATION_REASON")] - Match, - #[serde(rename = "DEFAULT_EVALUATION_REASON")] - Default, -} - -#[derive(Clone, Debug, Deserialize, PartialEq)] -pub enum ErrorEvaluationReason { - #[serde(rename = "UNKNOWN_ERROR_EVALUATION_REASON")] - Unknown, - #[serde(rename = "NOT_FOUND_ERROR_EVALUATION_REASON")] - NotFound, -} diff --git a/sdk/client/engine/src/models/flipt/mod.rs b/sdk/client/engine/src/models/flipt/mod.rs deleted file mode 100644 index 0443c3ede7..0000000000 --- a/sdk/client/engine/src/models/flipt/mod.rs +++ /dev/null @@ -1,78 +0,0 @@ -use crate::models::common; -use serde::Deserialize; -use std::collections::HashMap; - -#[derive(Clone)] -pub struct Flag { - pub key: String, - pub enabled: bool, - pub r#type: common::FlagType, -} - -#[derive(Clone, Deserialize)] -pub struct Variant { - pub key: String, - pub attachment: String, -} - -#[derive(Clone)] -pub struct Constraint { - pub segment_key: String, - pub r#type: common::ConstraintComparisonType, - pub property: String, - pub operator: String, - pub value: String, -} - -#[derive(Clone, Debug)] -pub struct EvaluationRule { - pub id: String, - pub flag_key: String, - pub segments: HashMap, - pub rank: usize, - pub segment_operator: common::SegmentOperator, -} - -#[derive(Clone, Debug)] -pub struct EvaluationDistribution { - pub rule_id: String, - pub rollout: f32, - pub variant_key: String, - pub variant_attachment: String, -} - -#[derive(Clone, Debug)] -pub struct EvaluationRollout { - pub rollout_type: common::RolloutType, - pub rank: usize, - pub segment: Option, - pub threshold: Option, -} - -#[derive(Clone, Debug)] -pub struct RolloutThreshold { - pub percentage: f32, - pub value: bool, -} - -#[derive(Clone, Debug)] -pub struct RolloutSegment { - pub value: bool, - pub segment_operator: common::SegmentOperator, - pub segments: HashMap, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct EvaluationSegment { - pub segment_key: String, - pub match_type: common::SegmentMatchType, - pub constraints: Vec, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct EvaluationConstraint { - pub r#type: common::ConstraintComparisonType, - pub property: String, - pub operator: String, - pub value: String, -} diff --git a/sdk/client/engine/src/models/mod.rs b/sdk/client/engine/src/models/mod.rs deleted file mode 100644 index 8adef94631..0000000000 --- a/sdk/client/engine/src/models/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod common; -pub mod flipt; -pub mod transport; diff --git a/sdk/client/engine/src/models/transport/mod.rs b/sdk/client/engine/src/models/transport/mod.rs deleted file mode 100644 index 9bb75ec8ad..0000000000 --- a/sdk/client/engine/src/models/transport/mod.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::models::common; -use serde::Deserialize; - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Document { - pub namespace: Namespace, - pub flags: Vec, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Namespace { - pub key: String, - pub name: Option, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Flag { - pub key: String, - pub name: String, - pub r#type: Option, - pub description: Option, - pub enabled: bool, - pub rules: Option>, - pub rollouts: Option>, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Rule { - pub distributions: Vec, - pub segments: Option>, - pub segment_operator: common::SegmentOperator, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Distribution { - pub variant_key: String, - pub rollout: f32, - pub variant_attachment: String, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Rollout { - pub description: Option, - pub segment: Option, - pub threshold: Option, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SegmentRule { - pub segment_operator: Option, - pub value: bool, - pub segments: Vec, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Threshold { - pub percentage: f32, - pub value: bool, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Segment { - pub key: String, - pub match_type: common::SegmentMatchType, - pub constraints: Vec, -} - -#[derive(Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct SegmentConstraint { - pub r#type: common::ConstraintComparisonType, - pub property: String, - pub operator: String, - pub value: String, -} diff --git a/sdk/client/engine/src/store/mod.rs b/sdk/client/engine/src/store/mod.rs deleted file mode 100644 index 641ef80e2c..0000000000 --- a/sdk/client/engine/src/store/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod parsers; -pub mod snapshot; diff --git a/sdk/client/engine/src/store/parsers.rs b/sdk/client/engine/src/store/parsers.rs deleted file mode 100644 index b411aec89d..0000000000 --- a/sdk/client/engine/src/store/parsers.rs +++ /dev/null @@ -1,101 +0,0 @@ -use snafu::{prelude::*, Whatever}; -use std::env; - -#[cfg(test)] -use std::fs; -#[cfg(test)] -use std::path::PathBuf; - -use super::snapshot::Parser; -use crate::models::transport; - -pub struct FliptParser { - namespaces: Vec, - http_client: reqwest::blocking::Client, - http_url: String, -} - -impl FliptParser { - pub fn new(namespaces: Vec) -> Self { - // We will allow the following line to panic when an error is encountered. - let http_client = reqwest::blocking::Client::builder() - .timeout(std::time::Duration::from_secs(10)) - .build() - .unwrap(); - - let http_url = - env::var("FLIPT_REMOTE_URL").unwrap_or(String::from("http://localhost:8080")); - - Self { - namespaces, - http_client, - http_url, - } - } -} - -impl Parser for FliptParser { - fn parse(&self, namespace: String) -> Result { - let response = match self - .http_client - .get(format!( - "{}/internal/v1/evaluation/snapshot/namespace/{}", - self.http_url, namespace - )) - .send() - { - Ok(resp) => resp, - Err(e) => whatever!("failed to make request: err {}", e), - }; - - let response_text = match response.text() { - Ok(t) => t, - Err(e) => whatever!("failed to get response body: err {}", e), - }; - - let document: transport::Document = match serde_json::from_str(&response_text) { - Ok(doc) => doc, - Err(e) => whatever!("failed to deserialize text into document: err {}", e), - }; - - Ok(document) - } - - fn get_namespaces(&self) -> Vec { - self.namespaces.clone() - } -} - -#[cfg(test)] -pub struct TestParser { - namespaces: Vec, -} - -#[cfg(test)] -impl TestParser { - pub fn new(namespaces: Vec) -> Self { - Self { namespaces } - } -} - -#[cfg(test)] -impl Parser for TestParser { - fn parse(&self, _: String) -> Result { - let mut d = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - d.push("src/testdata/state.json"); - - let state = - fs::read_to_string(d.display().to_string()).expect("file should have read correctly"); - - let document: transport::Document = match serde_json::from_str(&state) { - Ok(document) => document, - Err(e) => whatever!("failed to deserialize text into document: err {}", e), - }; - - Ok(document) - } - - fn get_namespaces(&self) -> Vec { - self.namespaces.clone() - } -} diff --git a/sdk/client/engine/src/store/snapshot.rs b/sdk/client/engine/src/store/snapshot.rs deleted file mode 100644 index ada146531a..0000000000 --- a/sdk/client/engine/src/store/snapshot.rs +++ /dev/null @@ -1,369 +0,0 @@ -use crate::models::common; -use crate::models::flipt; -use crate::models::transport; - -#[cfg(test)] -use mockall::automock; -use snafu::Whatever; -use std::collections::HashMap; - -pub trait Parser { - fn parse(&self, namespace: String) -> Result; - fn get_namespaces(&self) -> Vec; -} - -#[cfg_attr(test, automock)] -pub trait Store { - fn get_flag(&self, namespace_key: &str, flag_key: &str) -> Option; - fn get_evaluation_rules( - &self, - namespace_key: &str, - flag_key: &str, - ) -> Option>; - fn get_evaluation_distributions( - &self, - namespace_key: &str, - rule_id: &str, - ) -> Option>; - fn get_evaluation_rollouts( - &self, - namespace_key: &str, - flag_key: &str, - ) -> Option>; -} - -pub struct Snapshot { - namespace: HashMap, -} - -struct Namespace { - _key: String, - flags: HashMap, - eval_rules: HashMap>, - eval_rollouts: HashMap>, - eval_distributions: HashMap>, -} - -impl Snapshot { - pub fn build(parser: &dyn Parser) -> Result { - let mut ns: HashMap = HashMap::new(); - - for n in parser.get_namespaces() { - let doc = parser.parse(n.clone())?; - - let mut flags: HashMap = HashMap::new(); - let mut eval_rules: HashMap> = HashMap::new(); - let mut eval_rollouts: HashMap> = HashMap::new(); - let mut eval_dists: HashMap> = - HashMap::new(); - - for flag in doc.flags { - let f = flipt::Flag { - key: flag.key.clone(), - enabled: flag.enabled, - r#type: flag.r#type.unwrap_or(common::FlagType::Variant), - }; - - flags.insert(f.key.clone(), f); - - // Flag Rules - let mut eval_rules_collection: Vec = Vec::new(); - - let flag_rules = flag.rules.unwrap_or(vec![]); - - for (idx, rule) in flag_rules.into_iter().enumerate() { - let rule_id = uuid::Uuid::new_v4().to_string(); - let mut eval_rule = flipt::EvaluationRule { - id: rule_id.clone(), - rank: idx + 1, - flag_key: flag.key.clone(), - segments: HashMap::new(), - segment_operator: rule.segment_operator, - }; - - if rule.segments.is_some() { - let rule_segments = rule.segments.unwrap(); - - for rule_segment in rule_segments { - let mut eval_constraints: Vec = Vec::new(); - for constraint in rule_segment.constraints { - eval_constraints.push(flipt::EvaluationConstraint { - r#type: constraint.r#type, - property: constraint.property, - operator: constraint.operator, - value: constraint.value, - }); - } - - eval_rule.segments.insert( - rule_segment.key.clone(), - flipt::EvaluationSegment { - segment_key: rule_segment.key, - match_type: rule_segment.match_type, - constraints: eval_constraints, - }, - ); - } - } - - let mut evaluation_distributions: Vec = - Vec::new(); - - for distribution in rule.distributions { - evaluation_distributions.push(flipt::EvaluationDistribution { - rule_id: rule_id.clone(), - variant_key: distribution.variant_key, - variant_attachment: distribution.variant_attachment, - rollout: distribution.rollout, - }) - } - - eval_dists.insert(rule_id.clone(), evaluation_distributions); - - eval_rules_collection.push(eval_rule); - } - - eval_rules.insert(flag.key.clone(), eval_rules_collection); - - // Flag Rollouts - let mut eval_rollout_collection: Vec = Vec::new(); - let mut rollout_idx = 0; - - let flag_rollouts = flag.rollouts.unwrap_or(vec![]); - - for rollout in flag_rollouts { - rollout_idx += 1; - - let mut evaluation_rollout: flipt::EvaluationRollout = - flipt::EvaluationRollout { - rank: rollout_idx, - rollout_type: common::RolloutType::Unknown, - segment: None, - threshold: None, - }; - - evaluation_rollout.rank = rollout_idx; - - if rollout.threshold.is_some() { - let threshold = rollout.threshold.unwrap(); - evaluation_rollout.threshold = Some(flipt::RolloutThreshold { - percentage: threshold.percentage, - value: threshold.value, - }); - - evaluation_rollout.rollout_type = common::RolloutType::Threshold; - } else if rollout.segment.is_some() { - let mut evaluation_rollout_segments: HashMap< - String, - flipt::EvaluationSegment, - > = HashMap::new(); - - let segment_rule = rollout.segment.unwrap(); - - for segment in segment_rule.segments { - let mut constraints: Vec = Vec::new(); - for constraint in segment.constraints { - constraints.push(flipt::EvaluationConstraint { - r#type: constraint.r#type, - property: constraint.property, - value: constraint.value, - operator: constraint.operator, - }); - } - - evaluation_rollout_segments.insert( - segment.key.clone(), - flipt::EvaluationSegment { - segment_key: segment.key, - match_type: segment.match_type.clone(), - constraints, - }, - ); - } - - evaluation_rollout.rollout_type = common::RolloutType::Segment; - evaluation_rollout.segment = Some(flipt::RolloutSegment { - value: segment_rule.value, - segment_operator: segment_rule - .segment_operator - .unwrap_or(common::SegmentOperator::Or), - segments: evaluation_rollout_segments, - }); - } - - eval_rollout_collection.push(evaluation_rollout); - } - - eval_rollouts.insert(flag.key.clone(), eval_rollout_collection); - } - - ns.insert( - n.clone(), - Namespace { - _key: n.clone(), - flags, - eval_rules, - eval_rollouts, - eval_distributions: eval_dists, - }, - ); - } - - Ok(Self { namespace: ns }) - } -} - -impl Store for Snapshot { - fn get_flag(&self, namespace_key: &str, flag_key: &str) -> Option { - let namespace = self.namespace.get(namespace_key)?; - - let flag = namespace.flags.get(flag_key)?; - - Some(flag.clone()) - } - - fn get_evaluation_rules( - &self, - namespace_key: &str, - flag_key: &str, - ) -> Option> { - let namespace = self.namespace.get(namespace_key)?; - - let eval_rules = namespace.eval_rules.get(flag_key)?; - - Some(eval_rules.to_vec()) - } - - fn get_evaluation_distributions( - &self, - namespace_key: &str, - rule_id: &str, - ) -> Option> { - let namespace = self.namespace.get(namespace_key)?; - - let evaluation_distributions = namespace.eval_distributions.get(rule_id)?; - - Some(evaluation_distributions.to_vec()) - } - - fn get_evaluation_rollouts( - &self, - namespace_key: &str, - flag_key: &str, - ) -> Option> { - let namespace = self.namespace.get(namespace_key)?; - - let eval_rollouts = namespace.eval_rollouts.get(flag_key)?; - - Some(eval_rollouts.to_vec()) - } -} - -#[cfg(test)] -mod tests { - use super::{Snapshot, Store}; - use crate::models::common; - use crate::models::flipt; - use crate::store::parsers::TestParser; - - #[test] - fn test_snapshot() { - let tp = TestParser::new(vec!["default".into()]); - - let snapshot = match Snapshot::build(&tp) { - Ok(s) => s, - Err(e) => panic!("{}", e), - }; - - let flag_variant = snapshot - .get_flag("default", "flag1") - .expect("flag1 should exist"); - - assert_eq!(flag_variant.key, "flag1"); - assert_eq!(flag_variant.enabled, true); - assert_eq!(flag_variant.r#type, common::FlagType::Variant); - - let flag_boolean = snapshot - .get_flag("default", "flag_boolean") - .expect("flag_boolean should exist"); - - assert_eq!(flag_boolean.key, "flag_boolean"); - assert_eq!(flag_boolean.enabled, true); - assert_eq!(flag_boolean.r#type, common::FlagType::Boolean); - - let evaluation_rules = snapshot - .get_evaluation_rules("default", "flag1") - .expect("evaluation rules should exist for flag1"); - - assert_eq!(evaluation_rules.len(), 1); - assert_eq!(evaluation_rules[0].flag_key, "flag1"); - assert_eq!( - evaluation_rules[0].segment_operator, - common::SegmentOperator::Or - ); - assert_eq!(evaluation_rules[0].rank, 1); - assert_eq!(evaluation_rules[0].segments.len(), 1); - assert_eq!( - *evaluation_rules[0] - .segments - .get("segment1") - .expect("segment1 should exist"), - flipt::EvaluationSegment { - segment_key: "segment1".into(), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: "fizz".into(), - operator: "eq".into(), - value: "buzz".into(), - }], - } - ); - - let evaluation_distributions = snapshot - .get_evaluation_distributions("default", &evaluation_rules[0].id) - .expect("evaluation distributions should exists for the rule"); - assert_eq!(evaluation_distributions.len(), 1); - assert_eq!(evaluation_distributions[0].rollout, 100.0); - assert_eq!(evaluation_distributions[0].rule_id, evaluation_rules[0].id); - assert_eq!(evaluation_distributions[0].variant_key, "variant1"); - - let evaluation_rollouts = snapshot - .get_evaluation_rollouts("default", "flag_boolean") - .expect("evaluation rollouts should exist for flag_boolean"); - - assert_eq!(evaluation_rollouts.len(), 2); - assert_eq!(evaluation_rollouts[0].rank, 1); - assert_eq!( - evaluation_rollouts[0].rollout_type, - common::RolloutType::Segment - ); - - let segment_rollout = evaluation_rollouts[0] - .segment - .as_ref() - .expect("first rollout should be segment"); - - assert_eq!(segment_rollout.value, true); - assert_eq!( - segment_rollout.segment_operator, - common::SegmentOperator::Or - ); - assert_eq!( - *segment_rollout - .segments - .get("segment1") - .expect("segment1 should exist"), - flipt::EvaluationSegment { - segment_key: "segment1".into(), - match_type: common::SegmentMatchType::Any, - constraints: vec![flipt::EvaluationConstraint { - r#type: common::ConstraintComparisonType::String, - property: "fizz".into(), - operator: "eq".into(), - value: "buzz".into(), - }], - } - ); - } -} diff --git a/sdk/client/engine/src/testdata/state.json b/sdk/client/engine/src/testdata/state.json deleted file mode 100644 index 9b99e13a01..0000000000 --- a/sdk/client/engine/src/testdata/state.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "namespace": { - "key": "default", - "name": "", - "description": "", - "protected": false, - "createdAt": null, - "updatedAt": null - }, - "flags": [ - { - "key": "flag1", - "name": "flag1", - "description": "", - "enabled": true, - "type": "VARIANT_FLAG_TYPE", - "createdAt": "2023-11-06T20:12:27.831503Z", - "updatedAt": "2023-11-06T20:12:27.831503Z", - "rules": [ - { - "id": "cd6cf249-2f82-4e68-a126-37fc57e8b515", - "segments": [ - { - "key": "segment1", - "name": "", - "description": "", - "matchType": "ANY_SEGMENT_MATCH_TYPE", - "createdAt": null, - "updatedAt": null, - "constraints": [ - { - "id": "9a189a11-c5ab-4464-98ab-6742dbeab6c0", - "type": "STRING_CONSTRAINT_COMPARISON_TYPE", - "property": "fizz", - "operator": "eq", - "value": "buzz" - } - ] - } - ], - "rank": 1, - "segmentOperator": "OR_SEGMENT_OPERATOR", - "distributions": [ - { - "id": "", - "ruleId": "", - "variantId": "2f76d271-b31e-4f5c-80da-567f9aa1904c", - "variantKey": "variant1", - "variantAttachment": "", - "rollout": 100 - } - ] - } - ], - "rollouts": [] - }, - { - "key": "flag_boolean", - "name": "flag_boolean", - "description": "", - "enabled": true, - "type": "BOOLEAN_FLAG_TYPE", - "createdAt": "2023-11-06T20:12:27.834369Z", - "updatedAt": "2023-11-06T20:12:27.834369Z", - "rules": [], - "rollouts": [ - { - "type": "SEGMENT_ROLLOUT_TYPE", - "rank": 1, - "segment": { - "value": true, - "segmentOperator": "OR_SEGMENT_OPERATOR", - "segments": [ - { - "key": "segment1", - "name": "", - "description": "", - "matchType": "ANY_SEGMENT_MATCH_TYPE", - "createdAt": null, - "updatedAt": null, - "constraints": [ - { - "id": "9a189a11-c5ab-4464-98ab-6742dbeab6c0", - "type": "STRING_CONSTRAINT_COMPARISON_TYPE", - "property": "fizz", - "operator": "eq", - "value": "buzz" - } - ] - } - ] - } - }, - { - "type": "THRESHOLD_ROLLOUT_TYPE", - "rank": 2, - "threshold": { - "percentage": 50, - "value": true - } - } - ] - } - ] -} diff --git a/sdk/client/go/README.md b/sdk/client/go/README.md deleted file mode 100644 index c48f99a21c..0000000000 --- a/sdk/client/go/README.md +++ /dev/null @@ -1,54 +0,0 @@ -## Flipt Client Go - -The `flipt-client-go` directory contains the Golang source code for a Flipt evaluation client using FFI to make calls to a core built in Rust. - -### Instructions - -To use this client, you can run the following command from the root of the repository: - -```bash -cargo build -``` - -This should generate a `target/` directory in the root of this repository, which contains the dynamic linking library built for your platform. This dynamic library will contain the functionality necessary for the Golang client to make FFI calls. - -You can import the module that contains the evaluation client: `go.flipt.io/flipt/flipt-client-go` and build your Go project with the `CGO_LDFLAGS` environment variable set: - -```bash -CGO_LDFLAGS="-L/path/to/lib -lengine" -``` - -The `path/to/lib` will be the path to the dynamic library which will have the following paths depending on your platform. - -- **Linux**: `{FLIPT_REPO_ROOT}/target/debug/libengine.so` -- **Windows**: `{FLIPT_REPO_ROOT}/target/debug/libengine.dll` -- **MacOS**: `{FLIPT_REPO_ROOT}/target/debug/libengine.dylib` - -You can then use the client like so: - -```golang -package main - -import ( - "context" - "fmt" - "log" - - evaluation "go.flipt.io/flipt/flipt-client-go" -) - -func main() { - // You can initialize the client with a namespace using "WithNamespace", otherwise - // it will target the default namespace. - evaluationClient := evaluation.NewClient(evaluation.WithNamespace("staging")) - - variantResult, err := evaluationClient.Variant(context.Background(), "flag1", "someentity", map[string]string{ - "fizz": "buzz", - }) - if err != nil { - log.Fatal(err) - } - - fmt.Println(*variantResult.Result) -} -``` diff --git a/sdk/client/go/flipt-client-go/evaluation.go b/sdk/client/go/flipt-client-go/evaluation.go deleted file mode 100644 index bb7e8b65bf..0000000000 --- a/sdk/client/go/flipt-client-go/evaluation.go +++ /dev/null @@ -1,135 +0,0 @@ -package evaluation - -/* -#cgo LDFLAGS: -L. -lengine -#include -#include - -void* initialize_engine(char** namespaces); - -char* variant(void* engine, char* evaluation_request); - -char* boolean(void* engine, char* evaluation_request); - -void destroy_engine(void* engine); -*/ -import "C" -import ( - "context" - "encoding/json" - "unsafe" -) - -// Client wraps the functionality of making variant and boolean evaluation of Flipt feature flags -// using an engine that is compiled to a dynamically linked library. -type Client struct { - engine unsafe.Pointer - namespace string -} - -// NewClient constructs an Client. -func NewClient(opts ...clientOption) *Client { - client := &Client{ - namespace: "default", - } - - for _, opt := range opts { - opt(client) - } - - ns := []*C.char{C.CString(client.namespace)} - - // Free the memory of the C Strings that were created to initialize the engine. - defer func() { - for _, n := range ns { - C.free(unsafe.Pointer(n)) - } - }() - - nsPtr := (**C.char)(unsafe.Pointer(&ns[0])) - - eng := C.initialize_engine(nsPtr) - - client.engine = eng - - return client -} - -// clientOption adds additional configuraiton for Client parameters -type clientOption func(*Client) - -// WithNamespace allows for specifying which namespace the clients wants to make evaluations from. -func WithNamespace(namespace string) clientOption { - return func(c *Client) { - c.namespace = namespace - } -} - -// Variant makes an evaluation on a variant flag using the allocated Rust engine. -func (e *Client) Variant(_ context.Context, flagKey, entityID string, evalContext map[string]string) (*VariantResult, error) { - eb, err := json.Marshal(evalContext) - if err != nil { - return nil, err - } - - ereq, err := json.Marshal(evaluationRequest{ - NamespaceKey: e.namespace, - FlagKey: flagKey, - EntityId: entityID, - Context: string(eb), - }) - if err != nil { - return nil, err - } - - variant := C.variant(e.engine, C.CString(string(ereq))) - defer C.free(unsafe.Pointer(variant)) - - b := C.GoBytes(unsafe.Pointer(variant), (C.int)(C.strlen(variant))) - - var vr *VariantResult - - if err := json.Unmarshal(b, &vr); err != nil { - return nil, err - } - - return vr, nil -} - -// Boolean makes an evaluation on a boolean flag using the allocated Rust engine. -func (e *Client) Boolean(_ context.Context, flagKey, entityID string, evalContext map[string]string) (*BooleanResult, error) { - eb, err := json.Marshal(evalContext) - if err != nil { - return nil, err - } - - ereq, err := json.Marshal(evaluationRequest{ - NamespaceKey: e.namespace, - FlagKey: flagKey, - EntityId: entityID, - Context: string(eb), - }) - if err != nil { - return nil, err - } - - boolean := C.boolean(e.engine, C.CString(string(ereq))) - defer C.free(unsafe.Pointer(boolean)) - - b := C.GoBytes(unsafe.Pointer(boolean), (C.int)(C.strlen(boolean))) - - var br *BooleanResult - - if err := json.Unmarshal(b, &br); err != nil { - return nil, err - } - - return br, nil -} - -// Close cleans up the allocated engine as it was initialized in the constructor. -func (e *Client) Close() error { - // Destroy the engine to clean up allocated memory on dynamic library side. - C.destroy_engine(e.engine) - return nil -} diff --git a/sdk/client/go/flipt-client-go/go.mod b/sdk/client/go/flipt-client-go/go.mod deleted file mode 100644 index f00b877489..0000000000 --- a/sdk/client/go/flipt-client-go/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module go.flipt.io/flipt/flipt-client-go - -go 1.21.3 diff --git a/sdk/client/go/flipt-client-go/models.go b/sdk/client/go/flipt-client-go/models.go deleted file mode 100644 index ce68ef1b00..0000000000 --- a/sdk/client/go/flipt-client-go/models.go +++ /dev/null @@ -1,39 +0,0 @@ -package evaluation - -type evaluationRequest struct { - NamespaceKey string `json:"namespace_key"` - FlagKey string `json:"flag_key"` - EntityId string `json:"entity_id"` - Context string `json:"context"` -} - -type VariantEvaluationResponse struct { - Match bool `json:"match"` - SegmentKeys []string `json:"segment_keys"` - Reason string `json:"reason"` - FlagKey string `json:"flag_key"` - VariantKey string `json:"variant_key"` - VariantAttachment string `json:"variant_attachment"` - RequestDurationMillis float64 `json:"request_duration_millis"` - Timestamp string `json:"timestamp"` -} - -type BooleanEvaluationResponse struct { - Enabled bool `json:"enabled"` - FlagKey string `json:"flag_key"` - Reason string `json:"reason"` - RequestDurationMillis float64 `json:"request_duration_millis"` - Timestamp string `json:"timestamp"` -} - -type VariantResult struct { - Status string `json:"status"` - Result *VariantEvaluationResponse `json:"result,omitempty"` - ErrorMessage string `json:"error_message,omitempty"` -} - -type BooleanResult struct { - Status string `json:"status"` - Result *BooleanEvaluationResponse `json:"result,omitempty"` - ErrorMessage string `json:"error_message,omitempty"` -} diff --git a/sdk/client/python/README.md b/sdk/client/python/README.md deleted file mode 100644 index 3ec3f179f3..0000000000 --- a/sdk/client/python/README.md +++ /dev/null @@ -1,30 +0,0 @@ -## Flipt Client Python - -The `flipt-client-python` directory contains the Python source code for a Flipt evaluation client using FFI to make calls to a core built in Rust. - -### Instructions - -To use this client, you can run the following command from the root of the repository: - -```bash -cargo build -``` - -This should generate a `target/` directory in the root of this repository, which contains the dynamic linking library built for your platform. This dynamic library will contain the functionality necessary for the Python client to make FFI calls. You'll need to set the `ENGINE_LIB_PATH` environment variable depending on your platform: - -- **Linux**: `{FLIPT_REPO_ROOT}/target/debug/libengine.so` -- **Windows**: `{FLIPT_REPO_ROOT}/target/debug/libengine.dll` -- **MacOS**: `{FLIPT_REPO_ROOT}/target/debug/libengine.dylib` - -In your Python code you can import this client and use it as so: - -```python -from flipt_client_python import FliptEvaluationClient - -# namespace_key is optional here and will have a value of "default" if not specified -flipt_evaluation_client = FliptEvaluationClient(namespace="staging") - -variant_result = flipt_evaluation_client.variant(flag_key="flag1", entity_id="entity", context={"fizz": "buzz"}) - -print(variant_result) -``` diff --git a/sdk/client/python/flipt-client-python/flipt_client_python/__init__.py b/sdk/client/python/flipt-client-python/flipt_client_python/__init__.py deleted file mode 100644 index 5aaa6ad612..0000000000 --- a/sdk/client/python/flipt-client-python/flipt_client_python/__init__.py +++ /dev/null @@ -1,81 +0,0 @@ -import ctypes -import json -import os - -from .models import ( - BooleanResult, - EvaluationRequest, - VariantResult, -) - - -class FliptEvaluationClient: - def __init__(self, namespace: str = "default"): - engine_library_path = os.environ.get("ENGINE_LIB_PATH") - if engine_library_path is None: - raise Exception("ENGINE_LIB_PATH not set") - - self.namespace_key = namespace - - self.ffi_core = ctypes.CDLL(engine_library_path) - - self.ffi_core.initialize_engine.restype = ctypes.c_void_p - self.ffi_core.destroy_engine.argtypes = [ctypes.c_void_p] - - self.ffi_core.variant.argtypes = [ctypes.c_void_p, ctypes.c_char_p] - self.ffi_core.variant.restype = ctypes.c_char_p - - self.ffi_core.boolean.argtypes = [ctypes.c_void_p, ctypes.c_char_p] - self.ffi_core.boolean.restype = ctypes.c_char_p - - namespace_list = [namespace] - - ns = (ctypes.c_char_p * len(namespace_list))() - ns[:] = [s.encode("utf-8") for s in namespace_list] - - self.engine = self.ffi_core.initialize_engine(ns) - - def __del__(self): - if hasattr(self, "engine") and self.engine is not None: - self.ffi_core.destroy_engine(self.engine) - - def variant(self, flag_key: str, entity_id: str, context: dict) -> VariantResult: - response = self.ffi_core.variant( - self.engine, - serialize_evaluation_request( - self.namespace_key, flag_key, entity_id, context - ), - ) - - bytes_returned = ctypes.c_char_p(response).value - - variant_result = VariantResult.parse_raw(bytes_returned) - - return variant_result - - def boolean(self, flag_key: str, entity_id: str, context: dict) -> BooleanResult: - response = self.ffi_core.boolean( - self.engine, - serialize_evaluation_request( - self.namespace_key, flag_key, entity_id, context - ), - ) - - bytes_returned = ctypes.c_char_p(response).value - - boolean_result = BooleanResult.parse_raw(bytes_returned) - - return boolean_result - - -def serialize_evaluation_request( - namespace_key: str, flag_key: str, entity_id: str, context: dict -) -> str: - evaluation_request = EvaluationRequest( - namespace_key=namespace_key, - flag_key=flag_key, - entity_id=entity_id, - context=json.dumps(context), - ) - - return evaluation_request.json().encode("utf-8") diff --git a/sdk/client/python/flipt-client-python/flipt_client_python/models.py b/sdk/client/python/flipt-client-python/flipt_client_python/models.py deleted file mode 100644 index f76aa094a4..0000000000 --- a/sdk/client/python/flipt-client-python/flipt_client_python/models.py +++ /dev/null @@ -1,40 +0,0 @@ -from pydantic import BaseModel -from typing import List, Optional - - -class EvaluationRequest(BaseModel): - namespace_key: str - flag_key: str - entity_id: str - context: str - - -class VariantEvaluationResponse(BaseModel): - match: bool - segment_keys: List[str] - reason: str - flag_key: str - variant_key: str - variant_attachment: str - request_duration_millis: float - timestamp: str - - -class BooleanEvaluationResponse(BaseModel): - enabled: bool - flag_key: str - reason: str - request_duration_millis: float - timestamp: str - - -class VariantResult(BaseModel): - status: str - result: Optional[VariantEvaluationResponse] = None - error_message: Optional[str] = None - - -class BooleanResult(BaseModel): - status: str - result: Optional[BooleanEvaluationResponse] = None - error_message: Optional[str] = None diff --git a/sdk/client/python/flipt-client-python/poetry.lock b/sdk/client/python/flipt-client-python/poetry.lock deleted file mode 100644 index 442e0cb8bb..0000000000 --- a/sdk/client/python/flipt-client-python/poetry.lock +++ /dev/null @@ -1,278 +0,0 @@ -# This file is automatically @generated by Poetry 1.7.0 and should not be changed by hand. - -[[package]] -name = "annotated-types" -version = "0.6.0" -description = "Reusable constraint types to use with typing.Annotated" -optional = false -python-versions = ">=3.8" -files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, -] - -[[package]] -name = "black" -version = "23.11.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dbea0bb8575c6b6303cc65017b46351dc5953eea5c0a59d7b7e3a2d2f433a911"}, - {file = "black-23.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:412f56bab20ac85927f3a959230331de5614aecda1ede14b373083f62ec24e6f"}, - {file = "black-23.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d136ef5b418c81660ad847efe0e55c58c8208b77a57a28a503a5f345ccf01394"}, - {file = "black-23.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c1cac07e64433f646a9a838cdc00c9768b3c362805afc3fce341af0e6a9ae9f"}, - {file = "black-23.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cf57719e581cfd48c4efe28543fea3d139c6b6f1238b3f0102a9c73992cbb479"}, - {file = "black-23.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:698c1e0d5c43354ec5d6f4d914d0d553a9ada56c85415700b81dc90125aac244"}, - {file = "black-23.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:760415ccc20f9e8747084169110ef75d545f3b0932ee21368f63ac0fee86b221"}, - {file = "black-23.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:58e5f4d08a205b11800332920e285bd25e1a75c54953e05502052738fe16b3b5"}, - {file = "black-23.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:45aa1d4675964946e53ab81aeec7a37613c1cb71647b5394779e6efb79d6d187"}, - {file = "black-23.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4c44b7211a3a0570cc097e81135faa5f261264f4dfaa22bd5ee2875a4e773bd6"}, - {file = "black-23.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a9acad1451632021ee0d146c8765782a0c3846e0e0ea46659d7c4f89d9b212b"}, - {file = "black-23.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:fc7f6a44d52747e65a02558e1d807c82df1d66ffa80a601862040a43ec2e3142"}, - {file = "black-23.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f622b6822f02bfaf2a5cd31fdb7cd86fcf33dab6ced5185c35f5db98260b055"}, - {file = "black-23.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:250d7e60f323fcfc8ea6c800d5eba12f7967400eb6c2d21ae85ad31c204fb1f4"}, - {file = "black-23.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5133f5507007ba08d8b7b263c7aa0f931af5ba88a29beacc4b2dc23fcefe9c06"}, - {file = "black-23.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:421f3e44aa67138ab1b9bfbc22ee3780b22fa5b291e4db8ab7eee95200726b07"}, - {file = "black-23.11.0-py3-none-any.whl", hash = "sha256:54caaa703227c6e0c87b76326d0862184729a69b73d3b7305b6288e1d830067e"}, - {file = "black-23.11.0.tar.gz", hash = "sha256:4c68855825ff432d197229846f971bc4d6666ce90492e5b02013bcaca4d9ab05"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "mypy-extensions" -version = "1.0.0" -description = "Type system extensions for programs checked with the mypy type checker." -optional = false -python-versions = ">=3.5" -files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, -] - -[[package]] -name = "packaging" -version = "23.2" -description = "Core utilities for Python packages" -optional = false -python-versions = ">=3.7" -files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, -] - -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - -[[package]] -name = "platformdirs" -version = "3.11.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -optional = false -python-versions = ">=3.7" -files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, -] - -[package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] - -[[package]] -name = "pydantic" -version = "2.4.2" -description = "Data validation using Python type hints" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic-2.4.2-py3-none-any.whl", hash = "sha256:bc3ddf669d234f4220e6e1c4d96b061abe0998185a8d7855c0126782b7abc8c1"}, - {file = "pydantic-2.4.2.tar.gz", hash = "sha256:94f336138093a5d7f426aac732dcfe7ab4eb4da243c88f891d65deb4a2556ee7"}, -] - -[package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.10.1" -typing-extensions = ">=4.6.1" - -[package.extras] -email = ["email-validator (>=2.0.0)"] - -[[package]] -name = "pydantic-core" -version = "2.10.1" -description = "" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pydantic_core-2.10.1-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:d64728ee14e667ba27c66314b7d880b8eeb050e58ffc5fec3b7a109f8cddbd63"}, - {file = "pydantic_core-2.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:48525933fea744a3e7464c19bfede85df4aba79ce90c60b94d8b6e1eddd67096"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef337945bbd76cce390d1b2496ccf9f90b1c1242a3a7bc242ca4a9fc5993427a"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1392e0638af203cee360495fd2cfdd6054711f2db5175b6e9c3c461b76f5175"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0675ba5d22de54d07bccde38997e780044dcfa9a71aac9fd7d4d7a1d2e3e65f7"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:128552af70a64660f21cb0eb4876cbdadf1a1f9d5de820fed6421fa8de07c893"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f6e6aed5818c264412ac0598b581a002a9f050cb2637a84979859e70197aa9e"}, - {file = "pydantic_core-2.10.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ecaac27da855b8d73f92123e5f03612b04c5632fd0a476e469dfc47cd37d6b2e"}, - {file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b3c01c2fb081fced3bbb3da78510693dc7121bb893a1f0f5f4b48013201f362e"}, - {file = "pydantic_core-2.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:92f675fefa977625105708492850bcbc1182bfc3e997f8eecb866d1927c98ae6"}, - {file = "pydantic_core-2.10.1-cp310-none-win32.whl", hash = "sha256:420a692b547736a8d8703c39ea935ab5d8f0d2573f8f123b0a294e49a73f214b"}, - {file = "pydantic_core-2.10.1-cp310-none-win_amd64.whl", hash = "sha256:0880e239827b4b5b3e2ce05e6b766a7414e5f5aedc4523be6b68cfbc7f61c5d0"}, - {file = "pydantic_core-2.10.1-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:073d4a470b195d2b2245d0343569aac7e979d3a0dcce6c7d2af6d8a920ad0bea"}, - {file = "pydantic_core-2.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:600d04a7b342363058b9190d4e929a8e2e715c5682a70cc37d5ded1e0dd370b4"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39215d809470f4c8d1881758575b2abfb80174a9e8daf8f33b1d4379357e417c"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eeb3d3d6b399ffe55f9a04e09e635554012f1980696d6b0aca3e6cf42a17a03b"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a7a7902bf75779bc12ccfc508bfb7a4c47063f748ea3de87135d433a4cca7a2f"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3625578b6010c65964d177626fde80cf60d7f2e297d56b925cb5cdeda6e9925a"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:caa48fc31fc7243e50188197b5f0c4228956f97b954f76da157aae7f67269ae8"}, - {file = "pydantic_core-2.10.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:07ec6d7d929ae9c68f716195ce15e745b3e8fa122fc67698ac6498d802ed0fa4"}, - {file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6f31a17acede6a8cd1ae2d123ce04d8cca74056c9d456075f4f6f85de055607"}, - {file = "pydantic_core-2.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d8f1ebca515a03e5654f88411420fea6380fc841d1bea08effb28184e3d4899f"}, - {file = "pydantic_core-2.10.1-cp311-none-win32.whl", hash = "sha256:6db2eb9654a85ada248afa5a6db5ff1cf0f7b16043a6b070adc4a5be68c716d6"}, - {file = "pydantic_core-2.10.1-cp311-none-win_amd64.whl", hash = "sha256:4a5be350f922430997f240d25f8219f93b0c81e15f7b30b868b2fddfc2d05f27"}, - {file = "pydantic_core-2.10.1-cp311-none-win_arm64.whl", hash = "sha256:5fdb39f67c779b183b0c853cd6b45f7db84b84e0571b3ef1c89cdb1dfc367325"}, - {file = "pydantic_core-2.10.1-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1f22a9ab44de5f082216270552aa54259db20189e68fc12484873d926426921"}, - {file = "pydantic_core-2.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8572cadbf4cfa95fb4187775b5ade2eaa93511f07947b38f4cd67cf10783b118"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:db9a28c063c7c00844ae42a80203eb6d2d6bbb97070cfa00194dff40e6f545ab"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e2a35baa428181cb2270a15864ec6286822d3576f2ed0f4cd7f0c1708472aff"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05560ab976012bf40f25d5225a58bfa649bb897b87192a36c6fef1ab132540d7"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d6495008733c7521a89422d7a68efa0a0122c99a5861f06020ef5b1f51f9ba7c"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ac492c686defc8e6133e3a2d9eaf5261b3df26b8ae97450c1647286750b901"}, - {file = "pydantic_core-2.10.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8282bab177a9a3081fd3d0a0175a07a1e2bfb7fcbbd949519ea0980f8a07144d"}, - {file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:aafdb89fdeb5fe165043896817eccd6434aee124d5ee9b354f92cd574ba5e78f"}, - {file = "pydantic_core-2.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f6defd966ca3b187ec6c366604e9296f585021d922e666b99c47e78738b5666c"}, - {file = "pydantic_core-2.10.1-cp312-none-win32.whl", hash = "sha256:7c4d1894fe112b0864c1fa75dffa045720a194b227bed12f4be7f6045b25209f"}, - {file = "pydantic_core-2.10.1-cp312-none-win_amd64.whl", hash = "sha256:5994985da903d0b8a08e4935c46ed8daf5be1cf217489e673910951dc533d430"}, - {file = "pydantic_core-2.10.1-cp312-none-win_arm64.whl", hash = "sha256:0d8a8adef23d86d8eceed3e32e9cca8879c7481c183f84ed1a8edc7df073af94"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:9badf8d45171d92387410b04639d73811b785b5161ecadabf056ea14d62d4ede"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:ebedb45b9feb7258fac0a268a3f6bec0a2ea4d9558f3d6f813f02ff3a6dc6698"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfe1090245c078720d250d19cb05d67e21a9cd7c257698ef139bc41cf6c27b4f"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e357571bb0efd65fd55f18db0a2fb0ed89d0bb1d41d906b138f088933ae618bb"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b3dcd587b69bbf54fc04ca157c2323b8911033e827fffaecf0cafa5a892a0904"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c120c9ce3b163b985a3b966bb701114beb1da4b0468b9b236fc754783d85aa3"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15d6bca84ffc966cc9976b09a18cf9543ed4d4ecbd97e7086f9ce9327ea48891"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5cabb9710f09d5d2e9e2748c3e3e20d991a4c5f96ed8f1132518f54ab2967221"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:82f55187a5bebae7d81d35b1e9aaea5e169d44819789837cdd4720d768c55d15"}, - {file = "pydantic_core-2.10.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:1d40f55222b233e98e3921df7811c27567f0e1a4411b93d4c5c0f4ce131bc42f"}, - {file = "pydantic_core-2.10.1-cp37-none-win32.whl", hash = "sha256:14e09ff0b8fe6e46b93d36a878f6e4a3a98ba5303c76bb8e716f4878a3bee92c"}, - {file = "pydantic_core-2.10.1-cp37-none-win_amd64.whl", hash = "sha256:1396e81b83516b9d5c9e26a924fa69164156c148c717131f54f586485ac3c15e"}, - {file = "pydantic_core-2.10.1-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6835451b57c1b467b95ffb03a38bb75b52fb4dc2762bb1d9dbed8de31ea7d0fc"}, - {file = "pydantic_core-2.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b00bc4619f60c853556b35f83731bd817f989cba3e97dc792bb8c97941b8053a"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa467fd300a6f046bdb248d40cd015b21b7576c168a6bb20aa22e595c8ffcdd"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d99277877daf2efe074eae6338453a4ed54a2d93fb4678ddfe1209a0c93a2468"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa7db7558607afeccb33c0e4bf1c9a9a835e26599e76af6fe2fcea45904083a6"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aad7bd686363d1ce4ee930ad39f14e1673248373f4a9d74d2b9554f06199fb58"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:443fed67d33aa85357464f297e3d26e570267d1af6fef1c21ca50921d2976302"}, - {file = "pydantic_core-2.10.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:042462d8d6ba707fd3ce9649e7bf268633a41018d6a998fb5fbacb7e928a183e"}, - {file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ecdbde46235f3d560b18be0cb706c8e8ad1b965e5c13bbba7450c86064e96561"}, - {file = "pydantic_core-2.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ed550ed05540c03f0e69e6d74ad58d026de61b9eaebebbaaf8873e585cbb18de"}, - {file = "pydantic_core-2.10.1-cp38-none-win32.whl", hash = "sha256:8cdbbd92154db2fec4ec973d45c565e767ddc20aa6dbaf50142676484cbff8ee"}, - {file = "pydantic_core-2.10.1-cp38-none-win_amd64.whl", hash = "sha256:9f6f3e2598604956480f6c8aa24a3384dbf6509fe995d97f6ca6103bb8c2534e"}, - {file = "pydantic_core-2.10.1-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:655f8f4c8d6a5963c9a0687793da37b9b681d9ad06f29438a3b2326d4e6b7970"}, - {file = "pydantic_core-2.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e570ffeb2170e116a5b17e83f19911020ac79d19c96f320cbfa1fa96b470185b"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64322bfa13e44c6c30c518729ef08fda6026b96d5c0be724b3c4ae4da939f875"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:485a91abe3a07c3a8d1e082ba29254eea3e2bb13cbbd4351ea4e5a21912cc9b0"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7c2b8eb9fc872e68b46eeaf835e86bccc3a58ba57d0eedc109cbb14177be531"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5cb87bdc2e5f620693148b5f8f842d293cae46c5f15a1b1bf7ceeed324a740c"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25bd966103890ccfa028841a8f30cebcf5875eeac8c4bde4fe221364c92f0c9a"}, - {file = "pydantic_core-2.10.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f323306d0556351735b54acbf82904fe30a27b6a7147153cbe6e19aaaa2aa429"}, - {file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0c27f38dc4fbf07b358b2bc90edf35e82d1703e22ff2efa4af4ad5de1b3833e7"}, - {file = "pydantic_core-2.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:f1365e032a477c1430cfe0cf2856679529a2331426f8081172c4a74186f1d595"}, - {file = "pydantic_core-2.10.1-cp39-none-win32.whl", hash = "sha256:a1c311fd06ab3b10805abb72109f01a134019739bd3286b8ae1bc2fc4e50c07a"}, - {file = "pydantic_core-2.10.1-cp39-none-win_amd64.whl", hash = "sha256:ae8a8843b11dc0b03b57b52793e391f0122e740de3df1474814c700d2622950a"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d43002441932f9a9ea5d6f9efaa2e21458221a3a4b417a14027a1d530201ef1b"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:fcb83175cc4936a5425dde3356f079ae03c0802bbdf8ff82c035f8a54b333521"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:962ed72424bf1f72334e2f1e61b68f16c0e596f024ca7ac5daf229f7c26e4208"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2cf5bb4dd67f20f3bbc1209ef572a259027c49e5ff694fa56bed62959b41e1f9"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e544246b859f17373bed915182ab841b80849ed9cf23f1f07b73b7c58baee5fb"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c0877239307b7e69d025b73774e88e86ce82f6ba6adf98f41069d5b0b78bd1bf"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:53df009d1e1ba40f696f8995683e067e3967101d4bb4ea6f667931b7d4a01357"}, - {file = "pydantic_core-2.10.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a1254357f7e4c82e77c348dabf2d55f1d14d19d91ff025004775e70a6ef40ada"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:524ff0ca3baea164d6d93a32c58ac79eca9f6cf713586fdc0adb66a8cdeab96a"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f0ac9fb8608dbc6eaf17956bf623c9119b4db7dbb511650910a82e261e6600f"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:320f14bd4542a04ab23747ff2c8a778bde727158b606e2661349557f0770711e"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:63974d168b6233b4ed6a0046296803cb13c56637a7b8106564ab575926572a55"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:417243bf599ba1f1fef2bb8c543ceb918676954734e2dcb82bf162ae9d7bd514"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dda81e5ec82485155a19d9624cfcca9be88a405e2857354e5b089c2a982144b2"}, - {file = "pydantic_core-2.10.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:14cfbb00959259e15d684505263d5a21732b31248a5dd4941f73a3be233865b9"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:631cb7415225954fdcc2a024119101946793e5923f6c4d73a5914d27eb3d3a05"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:bec7dd208a4182e99c5b6c501ce0b1f49de2802448d4056091f8e630b28e9a52"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:149b8a07712f45b332faee1a2258d8ef1fb4a36f88c0c17cb687f205c5dc6e7d"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d966c47f9dd73c2d32a809d2be529112d509321c5310ebf54076812e6ecd884"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7eb037106f5c6b3b0b864ad226b0b7ab58157124161d48e4b30c4a43fef8bc4b"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:154ea7c52e32dce13065dbb20a4a6f0cc012b4f667ac90d648d36b12007fa9f7"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e562617a45b5a9da5be4abe72b971d4f00bf8555eb29bb91ec2ef2be348cd132"}, - {file = "pydantic_core-2.10.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:f23b55eb5464468f9e0e9a9935ce3ed2a870608d5f534025cd5536bca25b1402"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:e9121b4009339b0f751955baf4543a0bfd6bc3f8188f8056b1a25a2d45099934"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:0523aeb76e03f753b58be33b26540880bac5aa54422e4462404c432230543f33"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0e2959ef5d5b8dc9ef21e1a305a21a36e254e6a34432d00c72a92fdc5ecda5"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da01bec0a26befab4898ed83b362993c844b9a607a86add78604186297eb047e"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f2e9072d71c1f6cfc79a36d4484c82823c560e6f5599c43c1ca6b5cdbd54f881"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f36a3489d9e28fe4b67be9992a23029c3cec0babc3bd9afb39f49844a8c721c5"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f64f82cc3443149292b32387086d02a6c7fb39b8781563e0ca7b8d7d9cf72bd7"}, - {file = "pydantic_core-2.10.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b4a6db486ac8e99ae696e09efc8b2b9fea67b63c8f88ba7a1a16c24a057a0776"}, - {file = "pydantic_core-2.10.1.tar.gz", hash = "sha256:0f8682dbdd2f67f8e1edddcbffcc29f60a6182b4901c367fc8c1c40d30bb0a82"}, -] - -[package.dependencies] -typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" - -[[package]] -name = "typing-extensions" -version = "4.8.0" -description = "Backported and Experimental Type Hints for Python 3.8+" -optional = false -python-versions = ">=3.8" -files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, -] - -[metadata] -lock-version = "2.0" -python-versions = "^3.11" -content-hash = "642cc7ff3f4fb97e5a8c0216b99ec7db2fd36afc281ded839ec27e2be702d09d" diff --git a/sdk/client/python/flipt-client-python/pyproject.toml b/sdk/client/python/flipt-client-python/pyproject.toml deleted file mode 100644 index 9ebf300c6c..0000000000 --- a/sdk/client/python/flipt-client-python/pyproject.toml +++ /dev/null @@ -1,17 +0,0 @@ -[tool.poetry] -name = "flipt-client-python" -version = "0.0.1" -description = "" -authors = ["Flipt Devs "] - -[tool.poetry.dependencies] -python = "^3.11" -pydantic = "^2.4.2" - - -[tool.poetry.group.dev.dependencies] -black = "^23.11.0" - -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" diff --git a/sdk/client/python/flipt-client-python/tests/__init__.py b/sdk/client/python/flipt-client-python/tests/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 From 121c01aed0bccf65ff4d6d7d1c284093534a46f6 Mon Sep 17 00:00:00 2001 From: Mark Phelps <209477+markphelps@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:22:32 -0500 Subject: [PATCH 2/2] chore: rm go client sdk --- go.work | 1 - 1 file changed, 1 deletion(-) diff --git a/go.work b/go.work index 229a0a02ca..63d6397409 100644 --- a/go.work +++ b/go.work @@ -8,5 +8,4 @@ use ( ./internal/cmd/protoc-gen-go-flipt-sdk ./rpc/flipt ./sdk/go - ./sdk/client/go/flipt-client-go )