From 119cc3a48706201476f5024480ad7ad9fea2c25f Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Thu, 28 Dec 2023 09:35:22 +0100 Subject: [PATCH 01/27] Read and write file --- include/unleash/unleashclient.h | 2 ++ src/unleashclient.cpp | 43 ++++++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 4f9c53a..dde5851 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -42,6 +42,7 @@ class UNLEASH_EXPORT UnleashClient { std::string m_environment; std::string m_authentication; bool m_registration = false; + std::string m_cacheFilePath; unsigned int m_refreshInterval = 15000; std::thread m_thread; bool m_stopThread = false; @@ -65,6 +66,7 @@ class UNLEASH_EXPORT UnleashClientBuilder { UnleashClientBuilder &apiClient(std::shared_ptr apiClient); UnleashClientBuilder &authentication(std::string authentication); UnleashClientBuilder ®istration(bool registration); + UnleashClientBuilder &cacheFilePath(std::string cacheFilePath); private: UnleashClient unleashClient; diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index e62034a..38f6b41 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -2,6 +2,8 @@ #include "unleash/api/cprclient.h" #include "unleash/strategies/strategy.h" #include +#include +#include namespace unleash { @@ -45,6 +47,11 @@ UnleashClientBuilder &UnleashClientBuilder::registration(bool registration) { return *this; } +UnleashClientBuilder &UnleashClientBuilder::cacheFilePath(std::string cacheFilePath) { + unleashClient.m_cacheFilePath = std::move(cacheFilePath); + return *this; +} + void UnleashClient::initializeClient() { if (!m_isInitialized) { // Set-up Unleash API client @@ -61,12 +68,20 @@ void UnleashClient::initializeClient() { // Initial fetch of feature flags auto apiFeatures = m_apiClient->features(); if (apiFeatures.empty()) { - std::cerr << "Attempted to initialize an Unleash Client instance " - "without server response." - << std::endl; - return; + std::cerr << "Attempted to initialize an Unleash Client instance without server response." << std::endl; + + std::ifstream cacheFile(m_cacheFilePath, std::fstream::in); + if (cacheFile.is_open()){ + std::cout << "Reading configuration from cached file " << m_cacheFilePath << std::endl; + std::stringstream features_buffer; + features_buffer << cacheFile.rdbuf(); + cacheFile.close(); + m_features = loadFeatures(features_buffer.str()); + } else + std::cout << "Could not open cache file '" << m_cacheFilePath << "' for reading." << std::endl; + } else { + m_features = loadFeatures(apiFeatures); } - m_features = loadFeatures(apiFeatures); m_thread = std::thread(&UnleashClient::periodicTask, this); m_isInitialized = true; } else { @@ -85,8 +100,24 @@ void UnleashClient::periodicTask() { globalTimer += k_pollInterval; if (globalTimer >= m_refreshInterval) { globalTimer = 0; + auto features_response = m_apiClient->features(); - if (!features_response.empty()) m_features = loadFeatures(features_response); + if (!features_response.empty()){ + std::ofstream cacheFile(m_cacheFilePath); + if (cacheFile.is_open()) + cacheFile << features_response; + cacheFile.close(); + m_features = loadFeatures(features_response); + } else { + std::ifstream cacheFile(m_cacheFilePath); + if(cacheFile.is_open()){ + std::stringstream features_buffer; + features_buffer << cacheFile.rdbuf(); + cacheFile.close(); + m_features = loadFeatures(features_buffer.str()); + + } + } } } } From 1293581c3bfadda3703d12d7cdfd6e63e545c56b Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Thu, 28 Dec 2023 15:27:45 +0100 Subject: [PATCH 02/27] cleanup --- src/unleashclient.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index 38f6b41..78f58f9 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -69,7 +69,6 @@ void UnleashClient::initializeClient() { auto apiFeatures = m_apiClient->features(); if (apiFeatures.empty()) { std::cerr << "Attempted to initialize an Unleash Client instance without server response." << std::endl; - std::ifstream cacheFile(m_cacheFilePath, std::fstream::in); if (cacheFile.is_open()){ std::cout << "Reading configuration from cached file " << m_cacheFilePath << std::endl; @@ -100,7 +99,6 @@ void UnleashClient::periodicTask() { globalTimer += k_pollInterval; if (globalTimer >= m_refreshInterval) { globalTimer = 0; - auto features_response = m_apiClient->features(); if (!features_response.empty()){ std::ofstream cacheFile(m_cacheFilePath); From 85a55520e84c5bdbe9112e67edd1ac58de9334f2 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Tue, 9 Jan 2024 16:30:16 +0100 Subject: [PATCH 03/27] android fix 1 --- client-specification | 2 +- include/unleash/context.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client-specification b/client-specification index c0169d7..1a17ee9 160000 --- a/client-specification +++ b/client-specification @@ -1 +1 @@ -Subproject commit c0169d7ace35db66cdf41a7b1b4e390a4a843c3b +Subproject commit 1a17ee9087cae54c9b63a8ce92706b9a4663482e diff --git a/include/unleash/context.h b/include/unleash/context.h index dad7a6f..7c5829a 100644 --- a/include/unleash/context.h +++ b/include/unleash/context.h @@ -4,7 +4,7 @@ #include namespace unleash { -struct Context { +class Context { std::string userId; std::string sessionId; std::string remoteAddress; From 1037a1a418188cb0ac859fb2fe579f2e00c96973 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Tue, 9 Jan 2024 16:40:42 +0100 Subject: [PATCH 04/27] update url --- .gitmodules | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitmodules b/.gitmodules index aa94f51..79a1373 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "client-specification"] path = client-specification - url = git@github.com:Unleash/client-specification.git + url = https://github.com/Unleash/client-specification.git From 761ee424135350c2ca53676d1e48b7d26d01d0a8 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Tue, 9 Jan 2024 16:46:38 +0100 Subject: [PATCH 05/27] submodule update --- client-specification | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client-specification b/client-specification index 1a17ee9..c0169d7 160000 --- a/client-specification +++ b/client-specification @@ -1 +1 @@ -Subproject commit 1a17ee9087cae54c9b63a8ce92706b9a4663482e +Subproject commit c0169d7ace35db66cdf41a7b1b4e390a4a843c3b From 2d63c768cb40c4c8460c9dc8bfbf30fc359e338c Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Wed, 10 Jan 2024 17:04:06 +0100 Subject: [PATCH 06/27] make context a struct --- include/unleash/context.h | 2 +- include/unleash/feature.h | 2 +- include/unleash/unleashclient.h | 2 +- include/unleash/variants/variant.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/unleash/context.h b/include/unleash/context.h index 7c5829a..dad7a6f 100644 --- a/include/unleash/context.h +++ b/include/unleash/context.h @@ -4,7 +4,7 @@ #include namespace unleash { -class Context { +struct Context { std::string userId; std::string sessionId; std::string remoteAddress; diff --git a/include/unleash/feature.h b/include/unleash/feature.h index f49c6d6..7af90c1 100644 --- a/include/unleash/feature.h +++ b/include/unleash/feature.h @@ -7,7 +7,7 @@ #include namespace unleash { -class Context; +struct Context; class Feature { public: Feature(std::string name, std::vector> strategies, bool enable); diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index dde5851..e4456ff 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -13,7 +13,7 @@ namespace unleash { class UnleashClientBuilder; -class Context; +struct Context; struct variant_t; class UNLEASH_EXPORT UnleashClient { diff --git a/include/unleash/variants/variant.h b/include/unleash/variants/variant.h index 4a52bfd..d649221 100644 --- a/include/unleash/variants/variant.h +++ b/include/unleash/variants/variant.h @@ -5,7 +5,7 @@ namespace unleash { -class Context; +struct Context; struct Override { std::string contextName; From 412ba85d3f2f3b86188c236b29d7b7dda3a9f459 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Thu, 11 Jan 2024 13:31:08 +0100 Subject: [PATCH 07/27] Make testing flag specific --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fbfb2d..1f02bc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ endif() # Create the main unleash library target add_subdirectory(src) -if(ENABLE_TESTING) +if(UNLEASH_ENABLE_TESTING) enable_testing() add_subdirectory(test) endif() From 8cb1676e3fa7c4f3eddd97ff87861568647ca446 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 14:43:37 +0100 Subject: [PATCH 08/27] expose the feature flags keys list --- include/unleash/unleashclient.h | 1 + src/unleashclient.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 4f9c53a..14aa01f 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -26,6 +26,7 @@ class UNLEASH_EXPORT UnleashClient { friend UNLEASH_EXPORT std::ostream &operator<<(std::ostream &os, const UnleashClient &obj); static UnleashClientBuilder create(std::string name, std::string url); void initializeClient(); + featuresMap_t featuresMap() const; bool isEnabled(const std::string &flag); bool isEnabled(const std::string &flag, const Context &context); variant_t variant(const std::string &flag, const Context &context); diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index e62034a..b9387d0 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -96,6 +96,15 @@ UnleashClient::~UnleashClient() { if (m_thread.joinable()) m_thread.join(); } +std::vector UnleashClient::featureFlags() const { + if (m_isInitialized) { + if (auto search = m_features.find(flag); search != m_features.end()) { + return m_features.at(flag).isEnabled(context); + } + } + return featuresMap_t(); +} + bool UnleashClient::isEnabled(const std::string &flag) { Context context; return isEnabled(flag, context); From 6adeef18f15be76634ce455216304592cc8b25dc Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 16:47:13 +0100 Subject: [PATCH 09/27] =?UTF-8?q?add=20comment=C2=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/unleashclient.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index b9387d0..d1ca1aa 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -97,12 +97,14 @@ UnleashClient::~UnleashClient() { } std::vector UnleashClient::featureFlags() const { + std::vector featureFlags; + // test if (m_isInitialized) { - if (auto search = m_features.find(flag); search != m_features.end()) { - return m_features.at(flag).isEnabled(context); + for (auto it = m_features.begin(); it != m_features.end(); it++) { + featureFlags.push_back(it->first); } } - return featuresMap_t(); + return featureFlags } bool UnleashClient::isEnabled(const std::string &flag) { From 5b3acf82ca918bcefa9501c10280a07ecb5929f5 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 16:47:54 +0100 Subject: [PATCH 10/27] =?UTF-8?q?remove=20comment=C2=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/unleashclient.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index d1ca1aa..af60115 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -98,7 +98,6 @@ UnleashClient::~UnleashClient() { std::vector UnleashClient::featureFlags() const { std::vector featureFlags; - // test if (m_isInitialized) { for (auto it = m_features.begin(); it != m_features.end(); it++) { featureFlags.push_back(it->first); From 392d9ea0901a69fb9ea3b460794ca09a7df27807 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 16:49:29 +0100 Subject: [PATCH 11/27] fix --- src/unleashclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index af60115..5074390 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -103,7 +103,7 @@ std::vector UnleashClient::featureFlags() const { featureFlags.push_back(it->first); } } - return featureFlags + return featureFlags; } bool UnleashClient::isEnabled(const std::string &flag) { From 001604780516165200b7e7a264a8008bde577975 Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 16:52:12 +0100 Subject: [PATCH 12/27] add comment --- include/unleash/unleashclient.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 14aa01f..2118d54 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -26,7 +26,8 @@ class UNLEASH_EXPORT UnleashClient { friend UNLEASH_EXPORT std::ostream &operator<<(std::ostream &os, const UnleashClient &obj); static UnleashClientBuilder create(std::string name, std::string url); void initializeClient(); - featuresMap_t featuresMap() const; + // test + std::vector featureFlags() const; bool isEnabled(const std::string &flag); bool isEnabled(const std::string &flag, const Context &context); variant_t variant(const std::string &flag, const Context &context); From b40ed9c4e8d8e322dc3aef10fb5a630fff8497cc Mon Sep 17 00:00:00 2001 From: Kelly Date: Thu, 11 Jan 2024 16:52:37 +0100 Subject: [PATCH 13/27] remove comment --- include/unleash/unleashclient.h | 1 - 1 file changed, 1 deletion(-) diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 2118d54..8842fb3 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -26,7 +26,6 @@ class UNLEASH_EXPORT UnleashClient { friend UNLEASH_EXPORT std::ostream &operator<<(std::ostream &os, const UnleashClient &obj); static UnleashClientBuilder create(std::string name, std::string url); void initializeClient(); - // test std::vector featureFlags() const; bool isEnabled(const std::string &flag); bool isEnabled(const std::string &flag, const Context &context); From 63f116b0cc695b727c41f1565d45eac433563917 Mon Sep 17 00:00:00 2001 From: Antonio Ruiz Date: Thu, 11 Jan 2024 19:13:38 +0100 Subject: [PATCH 14/27] Update README with WIP and future dev --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0cf664b..5b2e524 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,9 @@ The below table shows what features the SDKs support or plan to support. - [x] Strategy constrains - [x] Application registration - [x] Variants +- [ ] Custom stickiness (WIP) +- [ ] Bootstraping - [ ] Usage Metrics -- [ ] Custom stickiness ## Requirements From 36841d047e8e0e5102977f354c1479685eda7946 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Tue, 16 Jan 2024 15:34:00 +0100 Subject: [PATCH 15/27] Temporarily disable SSL verification to make Android work again --- src/api/cprclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 8dc3c8b..09ebc00 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -12,7 +12,7 @@ CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string CprClient::features() { auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, - {"Authorization", m_authentication}}); + {"Authorization", m_authentication}}, cpr::VerifySsl(0)); if (response.status_code == 0) { std::cerr << response.error.message << std::endl; return std::string{}; From f3952802fd774c3fcde8c25bb88fa42fe8cb0022 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Wed, 17 Jan 2024 09:05:26 +0100 Subject: [PATCH 16/27] Only read from file if nothing has been read yet --- src/unleashclient.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index 87cd35a..6fc7dae 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -101,12 +101,12 @@ void UnleashClient::periodicTask() { globalTimer = 0; auto features_response = m_apiClient->features(); if (!features_response.empty()){ + m_features = loadFeatures(features_response); std::ofstream cacheFile(m_cacheFilePath); if (cacheFile.is_open()) cacheFile << features_response; cacheFile.close(); - m_features = loadFeatures(features_response); - } else { + } else if (m_features.empty()) { std::ifstream cacheFile(m_cacheFilePath); if(cacheFile.is_open()){ std::stringstream features_buffer; From 275f1df89b17141b429144254d278fb21c9cd259 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Thu, 18 Jan 2024 08:47:55 +0100 Subject: [PATCH 17/27] Enable SSL in curl again --- src/api/cprclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 09ebc00..8dc3c8b 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -12,7 +12,7 @@ CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string CprClient::features() { auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, - {"Authorization", m_authentication}}, cpr::VerifySsl(0)); + {"Authorization", m_authentication}}); if (response.status_code == 0) { std::cerr << response.error.message << std::endl; return std::string{}; From 0988b3366fbb727d047b410f81c5db2246122e4b Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Thu, 18 Jan 2024 14:56:21 +0100 Subject: [PATCH 18/27] Minor fixes --- src/unleashclient.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index 6fc7dae..22179d1 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -103,9 +103,10 @@ void UnleashClient::periodicTask() { if (!features_response.empty()){ m_features = loadFeatures(features_response); std::ofstream cacheFile(m_cacheFilePath); - if (cacheFile.is_open()) + if (cacheFile.is_open()){ cacheFile << features_response; - cacheFile.close(); + cacheFile.close(); + } } else if (m_features.empty()) { std::ifstream cacheFile(m_cacheFilePath); if(cacheFile.is_open()){ @@ -113,7 +114,6 @@ void UnleashClient::periodicTask() { features_buffer << cacheFile.rdbuf(); cacheFile.close(); m_features = loadFeatures(features_buffer.str()); - } } } From 7f125f6fbed19f5eb4cabbd2a3e89ea7852d3928 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Fri, 19 Jan 2024 15:07:29 +0100 Subject: [PATCH 19/27] Temporarily disable SSL again --- src/api/cprclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 8dc3c8b..09ebc00 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -12,7 +12,7 @@ CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string CprClient::features() { auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, - {"Authorization", m_authentication}}); + {"Authorization", m_authentication}}, cpr::VerifySsl(0)); if (response.status_code == 0) { std::cerr << response.error.message << std::endl; return std::string{}; From 868ad12413c96bcc9839abd9b754af7b629e9220 Mon Sep 17 00:00:00 2001 From: Michele Bolognini Date: Wed, 31 Jan 2024 12:10:23 +0100 Subject: [PATCH 20/27] Add constraint evaluation to maintained strategies --- src/strategies/applicationhostname.cpp | 6 +++--- src/strategies/flexiblerollout.cpp | 10 +++++----- src/strategies/remoteaddress.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/strategies/applicationhostname.cpp b/src/strategies/applicationhostname.cpp index 4f3d33e..2f6c43d 100644 --- a/src/strategies/applicationhostname.cpp +++ b/src/strategies/applicationhostname.cpp @@ -47,8 +47,8 @@ bool ApplicationHostname::isEnabled(const Context &context) { getHostname(hostnameC); if (std::string hostname{hostnameC}; std::find(m_applicationHostnames.begin(), m_applicationHostnames.end(), - hostname) != m_applicationHostnames.end()) - return true; - return false; + hostname) == m_applicationHostnames.end()) + return false; + return meetConstraints(context); } } // namespace unleash \ No newline at end of file diff --git a/src/strategies/flexiblerollout.cpp b/src/strategies/flexiblerollout.cpp index 89f59fb..0ec0710 100644 --- a/src/strategies/flexiblerollout.cpp +++ b/src/strategies/flexiblerollout.cpp @@ -27,19 +27,19 @@ bool FlexibleRollout::isEnabled(const Context &context) { } if (stickinessConfiguration == "userId") { if (context.userId.empty()) return false; - return normalizedMurmur3(m_groupId + ":" + context.userId) <= m_rollout; + if (normalizedMurmur3(m_groupId + ":" + context.userId) > m_rollout) return false; } else if (stickinessConfiguration == "sessionId") { - return normalizedMurmur3(m_groupId + ":" + context.sessionId) <= m_rollout; + if (normalizedMurmur3(m_groupId + ":" + context.sessionId) > m_rollout) return false; } else if (stickinessConfiguration == "random") { std::random_device dev; std::mt19937 rng(dev()); std::uniform_int_distribution dist6(1, 100); - return dist6(rng) <= m_rollout; + if (dist6(rng) > m_rollout) return false; } else { auto customFieldIt = context.properties.find(stickinessConfiguration); if (customFieldIt == context.properties.end()) return false; - return normalizedMurmur3(m_groupId + ":" + customFieldIt->second) <= m_rollout; + if (normalizedMurmur3(m_groupId + ":" + customFieldIt->second) > m_rollout) return false; } - return false; + return meetConstraints(context); } } // namespace unleash \ No newline at end of file diff --git a/src/strategies/remoteaddress.cpp b/src/strategies/remoteaddress.cpp index bb35b69..bce007a 100644 --- a/src/strategies/remoteaddress.cpp +++ b/src/strategies/remoteaddress.cpp @@ -16,7 +16,7 @@ RemoteAddress::RemoteAddress(std::string_view parameters, std::string_view const } bool RemoteAddress::isEnabled(const Context &context) { - if (std::find(m_ips.begin(), m_ips.end(), context.remoteAddress) != m_ips.end()) return true; - return false; + if (std::find(m_ips.begin(), m_ips.end(), context.remoteAddress) == m_ips.end()) return false; + return meetConstraints(context); } } // namespace unleash \ No newline at end of file From 85cd79f468df5254f92f69b4fb6cffadd4ace3b4 Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Tue, 23 Jan 2024 08:44:06 +0100 Subject: [PATCH 21/27] Enable SSLVerification for calls --- src/api/cprclient.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 09ebc00..8dc3c8b 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -12,7 +12,7 @@ CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string CprClient::features() { auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, - {"Authorization", m_authentication}}, cpr::VerifySsl(0)); + {"Authorization", m_authentication}}); if (response.status_code == 0) { std::cerr << response.error.message << std::endl; return std::string{}; From 1725f6dfd0c7ff508e3803f33673850c078cc288 Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Fri, 26 Jan 2024 15:35:25 +0100 Subject: [PATCH 22/27] Pass certifcate bundle --- include/unleash/api/cprclient.h | 1 + src/api/cprclient.cpp | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/unleash/api/cprclient.h b/include/unleash/api/cprclient.h index 1d23cb1..5e50b65 100644 --- a/include/unleash/api/cprclient.h +++ b/include/unleash/api/cprclient.h @@ -10,6 +10,7 @@ class CprClient : public ApiClient { std::string features() override; bool registration(unsigned int refreshInterval) override; + private: std::string m_url; std::string m_instanceId; diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 8dc3c8b..c035500 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -1,6 +1,7 @@ #include "unleash/api/cprclient.h" #include #include +#include #include #include @@ -10,9 +11,12 @@ CprClient::CprClient(std::string url, std::string name, std::string instanceId, m_authentication(std::move(authentication)) {} std::string CprClient::features() { - auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, - {"UNLEASH-APPNAME", m_name}, - {"Authorization", m_authentication}}); + auto sslOptions = cpr::Ssl(cpr::ssl::CaInfo{"assets:/cacerts.pem"}); + auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, + cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, + {"UNLEASH-APPNAME", m_name}, + {"Authorization", m_authentication}}, + sslOptions); if (response.status_code == 0) { std::cerr << response.error.message << std::endl; return std::string{}; From f8327e89333979fe16a1548025ad70bbd475b496 Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Fri, 26 Jan 2024 15:44:30 +0100 Subject: [PATCH 23/27] Pass ca information as raw buffer --- include/unleash/api/cprclient.h | 4 +++- src/api/cprclient.cpp | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/unleash/api/cprclient.h b/include/unleash/api/cprclient.h index 5e50b65..06a2559 100644 --- a/include/unleash/api/cprclient.h +++ b/include/unleash/api/cprclient.h @@ -6,7 +6,8 @@ namespace unleash { class CprClient : public ApiClient { public: - CprClient(std::string url, std::string name, std::string instanceId, std::string authentication = std::string()); + CprClient(std::string url, std::string name, std::string instanceId, std::string authentication = std::string(), + std::string caBuffer = std::string()); std::string features() override; bool registration(unsigned int refreshInterval) override; @@ -16,6 +17,7 @@ class CprClient : public ApiClient { std::string m_instanceId; std::string m_name; std::string m_authentication; + std::string m_caBuffer; }; } // namespace unleash #endif //UNLEASH_CPRCLIENT_H diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index c035500..227d3c2 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -6,12 +6,15 @@ #include namespace unleash { -CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string authentication) +CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string authentication, + std::string caBuffer) : m_url(std::move(url)), m_instanceId(std::move(instanceId)), m_name(std::move(name)), - m_authentication(std::move(authentication)) {} + m_authentication(std::move(authentication)), m_caBuffer(std::move(caBuffer)) {} std::string CprClient::features() { - auto sslOptions = cpr::Ssl(cpr::ssl::CaInfo{"assets:/cacerts.pem"}); + cpr::SslOptions sslOptions; + + if (!m_caBuffer.empty()) { sslOptions.ca_buffer = m_caBuffer; } auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, From 22e13d0d4f9dbd5ecc2d8f70a79dea7f7188696a Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Fri, 26 Jan 2024 15:54:59 +0100 Subject: [PATCH 24/27] Add setter for ca_buffer --- include/unleash/api/cprclient.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/unleash/api/cprclient.h b/include/unleash/api/cprclient.h index 06a2559..0cb1294 100644 --- a/include/unleash/api/cprclient.h +++ b/include/unleash/api/cprclient.h @@ -11,6 +11,7 @@ class CprClient : public ApiClient { std::string features() override; bool registration(unsigned int refreshInterval) override; + void setCABuffer(std::string caBuffer) { m_caBuffer = caBuffer; }; private: std::string m_url; From 07d69f63b5ce5a0628caa8915dc700772225175d Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Wed, 7 Feb 2024 14:19:48 +0100 Subject: [PATCH 25/27] Expose caBuffer to unleashclient --- include/unleash/unleashclient.h | 2 ++ src/unleashclient.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 02918e8..10fe5e6 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -44,6 +44,7 @@ class UNLEASH_EXPORT UnleashClient { std::string m_authentication; bool m_registration = false; std::string m_cacheFilePath; + std::string m_caBuffer; unsigned int m_refreshInterval = 15000; std::thread m_thread; bool m_stopThread = false; @@ -68,6 +69,7 @@ class UNLEASH_EXPORT UnleashClientBuilder { UnleashClientBuilder &authentication(std::string authentication); UnleashClientBuilder ®istration(bool registration); UnleashClientBuilder &cacheFilePath(std::string cacheFilePath); + UnleashClientBuilder &caBuffer(std::string caBuffer); private: UnleashClient unleashClient; diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index 22179d1..aca0ada 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -52,11 +52,16 @@ UnleashClientBuilder &UnleashClientBuilder::cacheFilePath(std::string cacheFileP return *this; } +UnleashClientBuilder &UnleashClientBuilder::caBuffer(std::string caBuffer) { + unleashClient.m_caBuffer = std::move(caBuffer); + return *this; +} + void UnleashClient::initializeClient() { if (!m_isInitialized) { // Set-up Unleash API client if (m_apiClient == nullptr) { - m_apiClient = std::make_unique(m_url, m_name, m_instanceId, m_authentication); + m_apiClient = std::make_unique(m_url, m_name, m_instanceId, m_authentication, m_caBuffer); } // Register the Client From 4cbfe18d71373cb605eea73a8a290758c8f1c44f Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Wed, 7 Feb 2024 14:50:00 +0100 Subject: [PATCH 26/27] Pass sslOptions to post request as well --- src/api/cprclient.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index 227d3c2..cfb13bc 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -31,15 +31,18 @@ std::string CprClient::features() { } bool CprClient::registration(unsigned int refreshInterval) { + cpr::SslOptions sslOptions; + + if (!m_caBuffer.empty()) { sslOptions.ca_buffer = m_caBuffer; } nlohmann::json payload; payload["appName"] = m_name; payload["interval"] = refreshInterval; payload["started"] = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); payload["strategies"] = {"default", "userWithId", "flexibleRollout", "remoteAddress", "applicationHostname"}; - if (auto response = - cpr::Post(cpr::Url{m_url + "/client/register"}, cpr::Body{payload.dump()}, - cpr::Header{{"Authorization", m_authentication}, {"Content-Type", "application/json"}}); + if (auto response = cpr::Post( + cpr::Url{m_url + "/client/register"}, cpr::Body{payload.dump()}, + cpr::Header{{"Authorization", m_authentication}, {"Content-Type", "application/json"}}, sslOptions); response.status_code == 0) { std::cerr << response.error.message << std::endl; } else if (response.status_code >= 400) { From 36b0f2f9175c88bcea0bf12f02ba512c2981f721 Mon Sep 17 00:00:00 2001 From: Dominik Berner Date: Mon, 12 Feb 2024 09:31:52 +0100 Subject: [PATCH 27/27] Set CaInfo for calls if non-empty --- include/unleash/api/cprclient.h | 6 ++---- include/unleash/unleashclient.h | 4 ++-- src/api/cprclient.cpp | 20 ++++++++++++++++---- src/unleashclient.cpp | 6 +++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/include/unleash/api/cprclient.h b/include/unleash/api/cprclient.h index 0cb1294..2866780 100644 --- a/include/unleash/api/cprclient.h +++ b/include/unleash/api/cprclient.h @@ -7,18 +7,16 @@ namespace unleash { class CprClient : public ApiClient { public: CprClient(std::string url, std::string name, std::string instanceId, std::string authentication = std::string(), - std::string caBuffer = std::string()); + std::string caInfo = std::string()); std::string features() override; bool registration(unsigned int refreshInterval) override; - void setCABuffer(std::string caBuffer) { m_caBuffer = caBuffer; }; - private: std::string m_url; std::string m_instanceId; std::string m_name; std::string m_authentication; - std::string m_caBuffer; + std::string m_caInfo; }; } // namespace unleash #endif //UNLEASH_CPRCLIENT_H diff --git a/include/unleash/unleashclient.h b/include/unleash/unleashclient.h index 10fe5e6..975de8c 100644 --- a/include/unleash/unleashclient.h +++ b/include/unleash/unleashclient.h @@ -44,7 +44,7 @@ class UNLEASH_EXPORT UnleashClient { std::string m_authentication; bool m_registration = false; std::string m_cacheFilePath; - std::string m_caBuffer; + std::string m_caInfo; unsigned int m_refreshInterval = 15000; std::thread m_thread; bool m_stopThread = false; @@ -69,7 +69,7 @@ class UNLEASH_EXPORT UnleashClientBuilder { UnleashClientBuilder &authentication(std::string authentication); UnleashClientBuilder ®istration(bool registration); UnleashClientBuilder &cacheFilePath(std::string cacheFilePath); - UnleashClientBuilder &caBuffer(std::string caBuffer); + UnleashClientBuilder &caInfo(std::string caInfo); private: UnleashClient unleashClient; diff --git a/src/api/cprclient.cpp b/src/api/cprclient.cpp index cfb13bc..927e5e3 100644 --- a/src/api/cprclient.cpp +++ b/src/api/cprclient.cpp @@ -7,14 +7,20 @@ namespace unleash { CprClient::CprClient(std::string url, std::string name, std::string instanceId, std::string authentication, - std::string caBuffer) + std::string caInfo) : m_url(std::move(url)), m_instanceId(std::move(instanceId)), m_name(std::move(name)), - m_authentication(std::move(authentication)), m_caBuffer(std::move(caBuffer)) {} + m_authentication(std::move(authentication)), m_caInfo(std::move(caInfo)) {} std::string CprClient::features() { cpr::SslOptions sslOptions; - if (!m_caBuffer.empty()) { sslOptions.ca_buffer = m_caBuffer; } + + if (!m_caInfo.empty()) { + // since CaInfo takes an rvalue reference and we don't want to move the m_caInfo in + // we create a copy of it and move it in + std::string copyOfCaInfo = m_caInfo; + sslOptions = cpr::Ssl(cpr::ssl::CaInfo{std::move(copyOfCaInfo)}); + } auto response = cpr::Get(cpr::Url{m_url + "/client/features"}, cpr::Header{{"UNLEASH-INSTANCEID", m_instanceId}, {"UNLEASH-APPNAME", m_name}, @@ -33,7 +39,13 @@ std::string CprClient::features() { bool CprClient::registration(unsigned int refreshInterval) { cpr::SslOptions sslOptions; - if (!m_caBuffer.empty()) { sslOptions.ca_buffer = m_caBuffer; } + + if (!m_caInfo.empty()) { + // since CaInfo takes an rvalue reference and we don't want to move the m_caInfo in + // we create a copy of it and move it in + std::string copyOfCaInfo = m_caInfo; + sslOptions = cpr::Ssl(cpr::ssl::CaInfo{std::move(copyOfCaInfo)}); + } nlohmann::json payload; payload["appName"] = m_name; payload["interval"] = refreshInterval; diff --git a/src/unleashclient.cpp b/src/unleashclient.cpp index aca0ada..bf968ca 100644 --- a/src/unleashclient.cpp +++ b/src/unleashclient.cpp @@ -52,8 +52,8 @@ UnleashClientBuilder &UnleashClientBuilder::cacheFilePath(std::string cacheFileP return *this; } -UnleashClientBuilder &UnleashClientBuilder::caBuffer(std::string caBuffer) { - unleashClient.m_caBuffer = std::move(caBuffer); +UnleashClientBuilder &UnleashClientBuilder::caInfo(std::string caInfo) { + unleashClient.m_caInfo = std::move(caInfo); return *this; } @@ -61,7 +61,7 @@ void UnleashClient::initializeClient() { if (!m_isInitialized) { // Set-up Unleash API client if (m_apiClient == nullptr) { - m_apiClient = std::make_unique(m_url, m_name, m_instanceId, m_authentication, m_caBuffer); + m_apiClient = std::make_unique(m_url, m_name, m_instanceId, m_authentication, m_caInfo); } // Register the Client