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/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 ) 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