Skip to content

feat: Implement data source configuration. #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion libs/common/include/config/detail/config.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include "config/detail/data_source_config.hpp"
#include "config/detail/endpoints_builder.hpp"
#include "config/detail/events_builder.hpp"
#include "config/detail/http_properties.hpp"

namespace launchdarkly::config::detail {

Expand All @@ -17,11 +19,15 @@ struct Config {
detail::EndpointsBuilder<SDK> service_endpoints_builder;
std::optional<std::string> application_tag;
detail::EventsBuilder<SDK> events_builder;
DataSourceConfig<SDK> data_source_config;
detail::HttpProperties http_properties;
Config(std::string sdk_key,
bool offline,
detail::EndpointsBuilder<SDK> service_endpoints_builder,
detail::EventsBuilder<SDK> events_builder,
std::optional<std::string> application_tag);
std::optional<std::string> application_tag,
DataSourceConfig<SDK> data_source_config,
detail::HttpProperties http_properties);
};

} // namespace launchdarkly::config::detail
22 changes: 22 additions & 0 deletions libs/common/include/config/detail/config_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
#include <string>
#include "config/detail/application_info.hpp"
#include "config/detail/config.hpp"
#include "config/detail/data_source_builder.hpp"
#include "config/detail/endpoints_builder.hpp"
#include "config/detail/events_builder.hpp"
#include "config/detail/http_properties_builder.hpp"
#include "logger.hpp"

namespace launchdarkly::config::detail {
Expand All @@ -21,6 +23,8 @@ class ConfigBuilder {
using EndpointsBuilder = detail::EndpointsBuilder<SDK>;
using EventsBuilder = detail::EventsBuilder<SDK>;
using ConfigType = detail::Config<SDK>;
using DataSourceBuilder = detail::DataSourceBuilder<SDK>;
using HttpPropertiesBuilder = detail::HttpPropertiesBuilder<SDK>;
/**
* A minimal configuration consists of a LaunchDarkly SDK Key.
* @param sdk_key SDK Key.
Expand Down Expand Up @@ -59,6 +63,22 @@ class ConfigBuilder {
*/
ConfigBuilder& events(EventsBuilder builder);

/**
* Sets the configuration of the component that receives feature flag data
* from LaunchDarkly.
* @param builder A DataSourceConfig builder.
* @return Reference to this builder.
*/
ConfigBuilder& data_source(detail::DataSourceBuilder<SDK> builder);

/**
* Sets the SDK's networking configuration, using an HttpPropertiesBuilder.
* The builder has methods for setting individual HTTP-related properties.
* @param builder A HttpPropertiesBuilder builder.
* @return Reference to this builder.
*/
ConfigBuilder& http_properties(detail::HttpPropertiesBuilder<SDK> builder);

/**
* Builds a Configuration, suitable for passing into an instance of Client.
* @return
Expand All @@ -71,6 +91,8 @@ class ConfigBuilder {
std::optional<EndpointsBuilder> service_endpoints_builder_;
std::optional<ApplicationInfo> application_info_builder_;
std::optional<EventsBuilder> events_builder_;
std::optional<DataSourceBuilder> data_source_builder_;
std::optional<HttpPropertiesBuilder> http_properties_builder_;
};

} // namespace launchdarkly::config::detail
212 changes: 212 additions & 0 deletions libs/common/include/config/detail/data_source_builder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#pragma once

#include <chrono>
#include <optional>
#include <type_traits>

#include "config/detail/data_source_config.hpp"
#include "config/detail/defaults.hpp"
#include "config/detail/sdks.hpp"

#include <boost/variant.hpp>

namespace launchdarkly::config::detail {

/**
* Used to construct a DataSourceConfiguration for the specified SDK type.
* @tparam SDK ClientSDK or ServerSDK.
*/
template <typename SDK>
class DataSourceBuilder;

/**
* Builds a configuration for a streaming data source.
*/
class StreamingBuilder {
public:
StreamingBuilder();

/**
* Sets the initial reconnect delay for the streaming connection.
*
* The streaming service uses a backoff algorithm (with jitter) every time
* the connection needs to be reestablished.The delay for the first
* reconnection will start near this value, and then increase exponentially
* for any subsequent connection failures.
*
* @param initial_reconnect_delay The initial delay for a reconnection
* attempt.
* @return Reference to this builder.
*/
StreamingBuilder& initial_reconnect_delay(
std::chrono::milliseconds initial_reconnect_delay);

/**
* Build the streaming config. Used internal to the SDK.
* @return The built config.
*/
[[nodiscard]] StreamingConfig build() const;

private:
StreamingConfig config_;
};

/**
* Contains methods for configuring the polling data source.
*/
class PollingBuilder {
public:
PollingBuilder();

/**
* Sets the interval at which the SDK will poll for feature flag updates.
* @param poll_interval The polling interval.
* @return Reference to this builder.
*/
PollingBuilder& poll_interval(std::chrono::seconds poll_interval);

/**
* Build the polling config. Used internal to the SDK.
* @return The built config.
*/
[[nodiscard]] PollingConfig build() const;

private:
PollingConfig config_;
};

/**
* The method visitor is only needed inside this file
*/
namespace {
struct MethodVisitor {
boost::variant<StreamingConfig, PollingConfig> operator()(
StreamingBuilder streaming) {
return streaming.build();
}
boost::variant<StreamingConfig, PollingConfig> operator()(
PollingBuilder polling) {
return polling.build();
}
};
} // namespace

template <>
class DataSourceBuilder<ClientSDK> {
public:
using Streaming = StreamingBuilder;
using Polling = PollingBuilder;

DataSourceBuilder();

/**
* Whether LaunchDarkly should provide additional information about how flag
* values were calculated.
*
* The additional information will then be available through the client's
* {TODO variation detail} method. Since this increases the size of network
* requests, such information is not sent unless you set this option to
* true.
* @param value True to enable reasons.
* @return Reference to this builder.
*/
DataSourceBuilder& with_reasons(bool value);

/**
* Whether or not to use the REPORT verb to fetch flag settings.
*
* If this is true, flag settings will be fetched with a REPORT request
* including a JSON entity body with the context object.
*
* Otherwise (by default) a GET request will be issued with the context
* passed as a base64 URL-encoded path parameter.
*
* Do not use unless advised by LaunchDarkly.
* @param value True to enable using the REPORT verb.
* @return Reference to this builder.
*/
DataSourceBuilder& use_report(bool value);

/**
* Set the streaming configuration for the builder.
*
* A data source may either be streaming or polling. Setting a streaming
* builder indicates the data source will use streaming. Setting a polling
* builder will indicate the use of polling.
*
* @param stream_builder The streaming builder.
* @return Reference to this builder.
*/
DataSourceBuilder& method(Streaming stream_builder);

/**
* Set the polling configuration for the builder.
*
* A data source may either be streaming or polling. Setting a stream
* builder indicates the data source will use streaming. Setting a polling
* builder will indicate the use of polling.
*
* @param polling_builder The polling builder.
* @return Reference to this builder.
*/
DataSourceBuilder& method(Polling polling_builder);

/**
* Build a data source config. This is used internal to the SDK.
*
* @return The built config.
*/
[[nodiscard]] DataSourceConfig<ClientSDK> build() const;

private:
boost::variant<Streaming, Polling> method_;
bool with_reasons_;
bool use_report_;
};

template <>
class DataSourceBuilder<ServerSDK> {
public:
using Streaming = StreamingBuilder;
using Polling = PollingBuilder;

DataSourceBuilder();

/**
* Set the streaming configuration for the builder.
*
* A data source may either be streaming or polling. Setting a streaming
* builder indicates the data source will use streaming. Setting a polling
* builder will indicate the use of polling.
*
* @param stream_builder The streaming builder.
* @return Reference to this builder.
*/
DataSourceBuilder& method(Streaming builder);

/**
* Set the polling configuration for the builder.
*
* A data source may either be streaming or polling. Setting a stream
* builder indicates the data source will use streaming. Setting a polling
* builder will indicate the use of polling.
*
* @param polling_builder The polling builder.
* @return Reference to this builder.
*/
DataSourceBuilder& method(Polling builder);

/**
* Build a data source config. This is used internal to the SDK.
*
* @return The built config.
*/
[[nodiscard]] DataSourceConfig<ServerSDK> build() const;

private:
boost::variant<Streaming, Polling> method_;
bool with_reasons_;
bool use_report_;
};

} // namespace launchdarkly::config::detail
35 changes: 35 additions & 0 deletions libs/common/include/config/detail/data_source_config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include <boost/variant.hpp>
#include <chrono>
#include <optional>
#include <type_traits>
#include "config/detail/sdks.hpp"

namespace launchdarkly::config::detail {

struct StreamingConfig {
std::chrono::milliseconds initial_reconnect_delay;
};

struct PollingConfig {
std::chrono::seconds poll_interval;
};

template <typename SDK>
struct DataSourceConfig;

template <>
struct DataSourceConfig<ClientSDK> {
boost::variant<StreamingConfig, PollingConfig> method;

bool with_reasons;
bool use_report;
};

template <>
struct DataSourceConfig<ServerSDK> {
boost::variant<StreamingConfig, PollingConfig> method;
};

} // namespace launchdarkly::config::detail
18 changes: 18 additions & 0 deletions libs/common/include/config/detail/defaults.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "config/detail/data_source_config.hpp"
#include "config/detail/events.hpp"
#include "config/detail/http_properties.hpp"
#include "config/detail/sdks.hpp"
Expand All @@ -19,6 +20,15 @@ struct Defaults {
* @return
*/
static bool offline() { return false; }

static StreamingConfig streaming_config() {
return {std::chrono::milliseconds{1000}};
}

static PollingConfig polling_config() {
// Default to 5 minutes;
return {std::chrono::seconds{5 * 60}};
}
};

template <>
Expand All @@ -42,6 +52,10 @@ struct Defaults<ClientSDK> {
sdk_name() + "/" + sdk_version(),
std::map<std::string, std::string>()};
}

static DataSourceConfig<ClientSDK> data_source_config() {
return {Defaults<AnySDK>::streaming_config(), false, false};
}
};

template <>
Expand All @@ -65,6 +79,10 @@ struct Defaults<ServerSDK> {
sdk_name() + "/" + sdk_version(),
std::map<std::string, std::string>()};
}

static DataSourceConfig<ServerSDK> data_source_config() {
return {Defaults<AnySDK>::streaming_config()};
}
};

} // namespace launchdarkly::config::detail
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class HttpPropertiesBuilder {
HttpPropertiesBuilder& custom_headers(
std::map<std::string, std::string> base_headers);

HttpProperties build() const;
[[nodiscard]] HttpProperties build() const;

private:
std::chrono::milliseconds connect_timeout_{};
Expand Down
1 change: 1 addition & 0 deletions libs/common/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ add_library(${LIBNAME}
events/conn_pool.cpp
events/summary_state.cpp
config/http_properties.cpp
config/data_source_builder.cpp
config/http_properties_builder.cpp)


Expand Down
Loading