-
Notifications
You must be signed in to change notification settings - Fork 3
feat: implement Client type #21
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
Changes from all commits
e12fa25
074be16
6b31874
317fba8
5639ece
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,2 @@ | ||
| #include "launchdarkly/client_side/api.hpp" | ||
| #include <launchdarkly/api.h> | ||
|
|
||
| bool launchdarkly_foo(int32_t* out_result) { | ||
| if (auto val = launchdarkly::foo()) { | ||
| *out_result = *val; | ||
| return true; | ||
| } | ||
| return false; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,56 @@ | ||
| #pragma once | ||
|
|
||
| #include "cstdint" | ||
| #include "optional" | ||
| #include <boost/asio/io_context.hpp> | ||
| #include <cstdint> | ||
| #include <memory> | ||
| #include <optional> | ||
| #include <thread> | ||
| #include <tl/expected.hpp> | ||
| #include "config/client.hpp" | ||
| #include "context.hpp" | ||
| #include "error.hpp" | ||
| #include "events/event_processor.hpp" | ||
| #include "logger.hpp" | ||
| #include "value.hpp" | ||
|
|
||
| namespace launchdarkly { | ||
| std::optional<std::int32_t> foo(); | ||
| } // namespace launchdarkly | ||
| namespace launchdarkly::client_side { | ||
| class Client { | ||
| public: | ||
| Client(client::Config config, Context context); | ||
|
|
||
| using FlagKey = std::string; | ||
| [[nodiscard]] std::unordered_map<FlagKey, Value> AllFlags() const; | ||
|
|
||
| void Track(std::string event_name, Value data, double metric_value); | ||
|
|
||
| void Track(std::string event_name, Value data); | ||
|
|
||
| void Track(std::string event_name); | ||
|
|
||
| void AsyncFlush(); | ||
|
|
||
| void AsyncIdentify(Context context); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Presumably we'll want synchronous flush and identify.. these are always problematic. I'm hoping we can pull some asio magic and allow for either using the CompletionTokens. |
||
|
|
||
| bool BoolVariation(FlagKey const& key, bool default_value); | ||
|
|
||
| std::string StringVariation(FlagKey const& key, std::string default_value); | ||
|
|
||
| double DoubleVariation(FlagKey const& key, double default_value); | ||
|
|
||
| int IntVariation(FlagKey const& key, int default_value); | ||
|
|
||
| Value JsonVariation(FlagKey const& key, Value default_value); | ||
|
|
||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Didn't add any of *Detail methods yet.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After this PR I will update it to add a data source, I've not made the |
||
| private: | ||
| void TrackInternal(std::string event_name, | ||
| std::optional<Value> data, | ||
| std::optional<double> metric_value); | ||
|
|
||
| Logger logger_; | ||
| std::thread thread_; | ||
| boost::asio::io_context ioc_; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lots of design points to think about here related to the io_context. For now, I've just constructed one inside the Client. I'll pose some questions without adding any of my half-baked answers. Do we construct the Probably need to use the SDK in a couple scenarios to really determine these more confidently. |
||
| Context context_; | ||
| std::unique_ptr<events::IEventProcessor> event_processor_; | ||
| }; | ||
|
|
||
| } // namespace launchdarkly::client_side | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,78 @@ | ||
| #include "launchdarkly/client_side/api.hpp" | ||
|
|
||
| #include <cstdint> | ||
| #include <chrono> | ||
| #include <optional> | ||
| #include <utility> | ||
|
|
||
| #include "console_backend.hpp" | ||
| #include "events/client_events.hpp" | ||
| #include "events/detail/asio_event_processor.hpp" | ||
|
|
||
| namespace launchdarkly { | ||
| namespace launchdarkly::client_side { | ||
|
|
||
| auto const kAnswerToLifeTheUniverseAndEverything = 42; | ||
| Client::Client(client::Config config, Context context) | ||
| : logger_(config.take_logger()), | ||
| context_(std::move(context)), | ||
| event_processor_( | ||
| std::make_unique<launchdarkly::events::detail::AsioEventProcessor>( | ||
| ioc_.get_executor(), | ||
| config.events_config(), | ||
| config.service_endpoints(), | ||
| config.sdk_key(), | ||
| logger_)) {} | ||
|
|
||
| std::unordered_map<Client::FlagKey, Value> Client::AllFlags() const { | ||
| return {}; | ||
| } | ||
|
|
||
| std::optional<std::int32_t> foo() { | ||
| return kAnswerToLifeTheUniverseAndEverything; | ||
| void Client::TrackInternal(std::string event_name, | ||
| std::optional<Value> data, | ||
| std::optional<double> metric_value) { | ||
| event_processor_->AsyncSend(events::TrackEventParams{ | ||
| std::chrono::system_clock::now(), std::move(event_name), | ||
| context_.kinds_to_keys(), std::move(data), metric_value}); | ||
| } | ||
| } // namespace launchdarkly | ||
|
|
||
| void Client::Track(std::string event_name, Value data, double metric_value) { | ||
| this->TrackInternal(std::move(event_name), data, metric_value); | ||
| } | ||
|
|
||
| void Client::Track(std::string event_name, Value data) { | ||
| this->TrackInternal(std::move(event_name), data, std::nullopt); | ||
| } | ||
|
|
||
| void Client::Track(std::string event_name) { | ||
| this->TrackInternal(std::move(event_name), std::nullopt, std::nullopt); | ||
| } | ||
|
|
||
| void Client::AsyncFlush() { | ||
| event_processor_->AsyncFlush(); | ||
| } | ||
|
|
||
| void Client::AsyncIdentify(Context context) { | ||
| event_processor_->AsyncSend(events::client::IdentifyEventParams{ | ||
| std::chrono::system_clock::now(), std::move(context)}); | ||
| } | ||
|
|
||
| bool Client::BoolVariation(Client::FlagKey const& key, bool default_value) { | ||
| return default_value; | ||
| } | ||
|
|
||
| std::string Client::StringVariation(Client::FlagKey const& key, | ||
| std::string default_value) { | ||
| return default_value; | ||
| } | ||
|
|
||
| double Client::DoubleVariation(Client::FlagKey const& key, | ||
| double default_value) { | ||
| return default_value; | ||
| } | ||
|
|
||
| int Client::IntVariation(Client::FlagKey const& key, int default_value) { | ||
| return default_value; | ||
| } | ||
|
|
||
| Value Client::JsonVariation(Client::FlagKey const& key, Value default_value) { | ||
| return default_value; | ||
| } | ||
|
|
||
| } // namespace launchdarkly::client_side |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| #include <gtest/gtest.h> | ||
| #include <launchdarkly/client_side/api.hpp> | ||
| #include "context_builder.hpp" | ||
| using namespace launchdarkly; | ||
|
|
||
| TEST(ClientTest, ConstructClientWithConfig) { | ||
| tl::expected<client::Config, Error> config = | ||
| client::ConfigBuilder("sdk-123").build(); | ||
|
|
||
| ASSERT_TRUE(config); | ||
|
|
||
| auto context = ContextBuilder().kind("cat", "shadow").build(); | ||
|
|
||
| client_side::Client client(std::move(*config), context); | ||
|
|
||
| ASSERT_TRUE(client.AllFlags().empty()); | ||
| ASSERT_TRUE(client.BoolVariation("cat-food", true)); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
| #include "config/detail/endpoints_builder.hpp" | ||
| #include "config/detail/events_builder.hpp" | ||
| #include "config/detail/http_properties.hpp" | ||
| #include "logger.hpp" | ||
|
|
||
| namespace launchdarkly::config::detail { | ||
|
|
||
|
|
@@ -14,20 +15,41 @@ namespace launchdarkly::config::detail { | |
| */ | ||
| template <typename SDK> | ||
| struct Config { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed I think that makes sense since we can use |
||
| std::string sdk_key; | ||
| bool offline; | ||
| 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; | ||
| public: | ||
| Config(std::string sdk_key, | ||
| bool offline, | ||
| detail::EndpointsBuilder<SDK> service_endpoints_builder, | ||
| detail::EventsBuilder<SDK> events_builder, | ||
| launchdarkly::Logger logger, | ||
| ServiceEndpoints endpoints, | ||
| Events events, | ||
| std::optional<std::string> application_tag, | ||
| DataSourceConfig<SDK> data_source_config, | ||
| detail::HttpProperties http_properties); | ||
|
|
||
| std::string const& sdk_key() const; | ||
|
|
||
| ServiceEndpoints const& service_endpoints() const; | ||
|
|
||
| Events const& events_config() const; | ||
|
|
||
| std::optional<std::string> const& application_tag() const; | ||
|
|
||
| DataSourceConfig<SDK> const& data_source_config() const; | ||
|
|
||
| HttpProperties const& http_properties() const; | ||
|
|
||
| bool offline() const; | ||
|
|
||
| Logger take_logger(); | ||
|
|
||
| private: | ||
| std::string sdk_key_; | ||
| bool offline_; | ||
| launchdarkly::Logger logger_; | ||
| ServiceEndpoints service_endpoints_; | ||
| std::optional<std::string> application_tag_; | ||
| Events events_; | ||
| DataSourceConfig<SDK> data_source_config_; | ||
| detail::HttpProperties http_properties_; | ||
| }; | ||
|
|
||
| } // namespace launchdarkly::config::detail | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we use promises for the async methods?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Forgot to submit my self-review, which addresses this. I think I'll try using CompletionToken first, so can satisfy all the use-cases.