diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 772a5f4..7bebd62 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -30,7 +30,7 @@ jobs: - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_TEST_COVERAGE=1 -DCMAKE_PREFIX_PATH=${{github.workspace}}/build + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_TEST_COVERAGE=1 -DCMAKE_PREFIX_PATH=${{github.workspace}}/build -DUNLEASH_ENABLE_TESTING=ON - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 54290c5..a4f5ecb 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -60,7 +60,7 @@ jobs: - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_TEST_COVERAGE=1 -G Ninja -DCMAKE_PREFIX_PATH=${{github.workspace}}/build + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_TEST_COVERAGE=1 -G Ninja -DCMAKE_PREFIX_PATH=${{github.workspace}}/build -DUNLEASH_ENABLE_TESTING=ON - name: Build with sonnar wrapper run: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j10 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 7eddb52..58b1734 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -28,7 +28,7 @@ jobs: run: conan install . --output-folder=build --build=missing --settings=build_type=${{env.BUILD_TYPE}} - name: Configure CMake - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_PREFIX_PATH=${{github.workspace}}/build + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_PREFIX_PATH=${{github.workspace}}/build -DUNLEASH_ENABLE_TESTING=ON - name: Build run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j10 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 diff --git a/CMakeLists.txt b/CMakeLists.txt index 7fbfb2d..27b70ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ if(NOT CMAKE_BUILD_TYPE) RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE) -option(ENABLE_TESTING "Enable Test Builds" ON) +option(UNLEASH_ENABLE_TESTING "Enable Test Builds" ON) option(ENABLE_TEST_COVERAGE "Enable Test Coverage" OFF) find_package(cpr) @@ -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() 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 4f9c53a..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 { @@ -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..78f58f9 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,19 @@ 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 { @@ -86,7 +100,22 @@ void UnleashClient::periodicTask() { 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()); + + } + } } } }