Skip to content

Commit 356bde1

Browse files
authored
feat: foundation of an event processor (#16)
* Add various Event definitions (feature events, debug, identify, etc.) * Add IEventProcessor and an implementation based on boost::asio (AsioEventProcessor) * add config builders for events * add tag_invoke for EvaluationReason * fix compilation due to unknown header in backoff.hpp * add missing <functional> header to backoff.hpp
1 parent 9931b96 commit 356bde1

40 files changed

+1237
-24
lines changed

libs/common/include/config/client.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ using SDK = config::detail::ClientSDK;
1212
using ApplicationInfo = config::detail::ApplicationInfo;
1313
using Endpoints = config::detail::EndpointsBuilder<SDK>;
1414
using ConfigBuilder = config::detail::ConfigBuilder<SDK>;
15+
using EventsBuilder = config::detail::EventsBuilder<SDK>;
1516
using Config = config::detail::Config<SDK>;
1617

1718
} // namespace launchdarkly::client

libs/common/include/config/detail/config.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include "config/detail/endpoints_builder.hpp"
4+
#include "config/detail/events_builder.hpp"
45

56
namespace launchdarkly::config::detail {
67

@@ -15,9 +16,11 @@ struct Config {
1516
bool offline;
1617
detail::EndpointsBuilder<SDK> service_endpoints_builder;
1718
std::optional<std::string> application_tag;
19+
detail::EventsBuilder<SDK> events_builder;
1820
Config(std::string sdk_key,
1921
bool offline,
2022
detail::EndpointsBuilder<SDK> service_endpoints_builder,
23+
detail::EventsBuilder<SDK> events_builder,
2124
std::optional<std::string> application_tag);
2225
};
2326

libs/common/include/config/detail/config_builder.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "config/detail/application_info.hpp"
66
#include "config/detail/config.hpp"
77
#include "config/detail/endpoints_builder.hpp"
8+
#include "config/detail/events_builder.hpp"
89
#include "logger.hpp"
910

1011
namespace launchdarkly::config::detail {
@@ -18,6 +19,7 @@ template <typename SDK>
1819
class ConfigBuilder {
1920
public:
2021
using EndpointsBuilder = detail::EndpointsBuilder<SDK>;
22+
using EventsBuilder = detail::EventsBuilder<SDK>;
2123
using ConfigType = detail::Config<SDK>;
2224
/**
2325
* A minimal configuration consists of a LaunchDarkly SDK Key.
@@ -31,7 +33,7 @@ class ConfigBuilder {
3133
* @param builder An EndpointsBuilder.
3234
* @return Reference to this builder.
3335
*/
34-
ConfigBuilder& service_endpoints(detail::EndpointsBuilder<SDK> builder);
36+
ConfigBuilder& service_endpoints(EndpointsBuilder builder);
3537

3638
/**
3739
* To include metadata about the application that is utilizing the SDK,
@@ -49,6 +51,14 @@ class ConfigBuilder {
4951
*/
5052
ConfigBuilder& offline(bool offline);
5153

54+
/**
55+
* To tune settings related to event generation and delivery, pass an
56+
* EventsBuilder.
57+
* @param builder An EventsBuilder.
58+
* @return Reference to this builder.
59+
*/
60+
ConfigBuilder& events(EventsBuilder builder);
61+
5262
/**
5363
* Builds a Configuration, suitable for passing into an instance of Client.
5464
* @return
@@ -60,6 +70,7 @@ class ConfigBuilder {
6070
std::optional<bool> offline_;
6171
std::optional<EndpointsBuilder> service_endpoints_builder_;
6272
std::optional<ApplicationInfo> application_info_builder_;
73+
std::optional<EventsBuilder> events_builder_;
6374
};
6475

6576
} // namespace launchdarkly::config::detail

libs/common/include/config/detail/defaults.hpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
#pragma once
22

3+
#include "config/detail/events.hpp"
34
#include "config/detail/http_properties.hpp"
45
#include "config/detail/sdks.hpp"
5-
#include "service_endpoints.hpp"
6+
#include "config/detail/service_endpoints.hpp"
67

78
namespace launchdarkly::config::detail {
89

@@ -30,6 +31,11 @@ struct Defaults<ClientSDK> {
3031
"https://mobile.launchdarkly.com"};
3132
}
3233

34+
static Events events() {
35+
return {100, std::chrono::seconds(30), "/mobile", false,
36+
AttributeReference::SetType()};
37+
}
38+
3339
static HttpProperties http_properties() {
3440
return {std::chrono::milliseconds{10000},
3541
std::chrono::milliseconds{10000},
@@ -48,6 +54,11 @@ struct Defaults<ServerSDK> {
4854
"https://events.launchdarkly.com"};
4955
}
5056

57+
static Events events() {
58+
return {10000, std::chrono::seconds(5), "/bulk", false,
59+
AttributeReference::SetType()};
60+
}
61+
5162
static HttpProperties http_properties() {
5263
return {std::chrono::milliseconds{2000},
5364
std::chrono::milliseconds{10000},

libs/common/include/config/detail/endpoints_builder.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ class EndpointsBuilder {
6363

6464
/**
6565
* Builds a ServiceEndpoints if the configuration is valid. If not,
66-
* returns nullptr.
67-
* @return Unique pointer to ServiceEndpoints, or nullptr.
66+
* returns an error.
67+
* @return Unique pointer to ServiceEndpoints, or error.
6868
*/
6969
[[nodiscard]] tl::expected<ServiceEndpoints, Error> build();
7070

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#pragma once
2+
3+
#include <chrono>
4+
#include <cstddef>
5+
#include <string>
6+
#include <unordered_map>
7+
#include "attribute_reference.hpp"
8+
namespace launchdarkly::config::detail {
9+
10+
struct Events {
11+
public:
12+
template <typename SDK>
13+
friend class EventsBuilder;
14+
/**
15+
* Constructs configuration for the event subsystem.
16+
* @param capacity How many events can queue in memory before new events
17+
* are dropped.
18+
* @param flush_interval How often events are automatically flushed to
19+
* LaunchDarkly.
20+
* @param path The path component of the LaunchDarkly event delivery
21+
* endpoint.
22+
* @param all_attributes_private Whether all attributes should be treated as
23+
* private or not.
24+
* @param private_attrs Which attributes should be treated as private, if
25+
* all_attributes_private is false.
26+
* @param security Whether a plaintext or encrypted client should be used
27+
* for event delivery.
28+
*/
29+
Events(std::size_t capacity,
30+
std::chrono::milliseconds flush_interval,
31+
std::string path,
32+
bool all_attributes_private,
33+
AttributeReference::SetType private_attrs);
34+
35+
/**
36+
* Capacity of the event processor.
37+
*/
38+
[[nodiscard]] std::size_t capacity() const;
39+
40+
/**
41+
* Flush interval of the event processor, in milliseconds.
42+
*/
43+
[[nodiscard]] std::chrono::milliseconds flush_interval() const;
44+
45+
/**
46+
* Path component of the LaunchDarkly event delivery endpoint.
47+
*/
48+
[[nodiscard]] std::string const& path() const;
49+
50+
/**
51+
* Whether all attributes should be considered private or not.
52+
*/
53+
[[nodiscard]] bool all_attributes_private() const;
54+
55+
/**
56+
* Set of individual attributes that should be considered private.
57+
*/
58+
[[nodiscard]] AttributeReference::SetType const& private_attributes() const;
59+
60+
private:
61+
std::size_t capacity_;
62+
std::chrono::milliseconds flush_interval_;
63+
std::string path_;
64+
bool all_attributes_private_;
65+
AttributeReference::SetType private_attributes_;
66+
};
67+
68+
bool operator==(Events const& lhs, Events const& rhs);
69+
70+
} // namespace launchdarkly::config::detail
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#pragma once
2+
3+
#include <tl/expected.hpp>
4+
#include "attribute_reference.hpp"
5+
#include "config/detail/events.hpp"
6+
#include "error.hpp"
7+
8+
#include <memory>
9+
#include <optional>
10+
#include <string>
11+
#include <unordered_map>
12+
13+
namespace launchdarkly::config::detail {
14+
15+
template <typename SDK>
16+
class EventsBuilder;
17+
18+
template <typename SDK>
19+
bool operator==(EventsBuilder<SDK> const& lhs, EventsBuilder<SDK> const& rhs);
20+
21+
/**
22+
* EventsBuilder allows for specification of parameters related to the
23+
* SDK's event processor.
24+
*
25+
* @tparam SDK Type of SDK, such as ClientSDK or ServerSDK.
26+
*/
27+
template <typename SDK>
28+
class EventsBuilder {
29+
public:
30+
friend bool operator==
31+
<SDK>(EventsBuilder<SDK> const& lhs, EventsBuilder<SDK> const& rhs);
32+
/**
33+
* Constructs an EventsBuilder.
34+
*/
35+
EventsBuilder();
36+
37+
/**
38+
* Sets the capacity of the event processor. When more events are generated
39+
* within the processor's flush interval than this value, events will be
40+
* dropped.
41+
* @param capacity Event queue capacity.
42+
* @return Reference to this builder.
43+
*/
44+
EventsBuilder& capacity(std::size_t capacity);
45+
46+
/**
47+
* Sets the flush interval of the event processor. The processor queues
48+
* outgoing events based on the capacity parameter; these events are then
49+
* delivered based on the flush interval.
50+
* @param interval Interval between automatic flushes.
51+
* @return Reference to this builder.
52+
*/
53+
EventsBuilder& flush_interval(std::chrono::milliseconds interval);
54+
55+
/**
56+
* Attribute privacy indicates whether or not attributes should be
57+
* retained by LaunchDarkly after being sent upon initialization,
58+
* and if attributes should later be sent in events.
59+
*
60+
* Attribute privacy may be specified in 3 ways:
61+
*
62+
* (1) To specify that all attributes should be considered private - not
63+
* just those designated private on a per-context basis - call this method
64+
* with true as the parameter.
65+
*
66+
* (2) To specify that a specific set of attributes should be considered
67+
* private - in addition to those designated private on a per-context basis
68+
* - call @ref private_attributes.
69+
*
70+
* (3) To specify private attributes on a per-context basis, it is not
71+
* necessary to call either of these methods, as the default behavior is to
72+
* treat all attributes as non-private unless otherwise specified.
73+
*
74+
* @param value True for behavior of (1), false for default behavior of (2)
75+
* or (3).
76+
* @return Reference to this builder.
77+
*/
78+
EventsBuilder& all_attributes_private(bool);
79+
80+
/**
81+
* Specify that a set of attributes are private.
82+
* @return Reference to this builder.
83+
*/
84+
EventsBuilder& private_attributes(
85+
AttributeReference::SetType private_attrs);
86+
87+
/**
88+
* Builds Events configuration, if the configuration is valid.
89+
* @return Events config, or error.
90+
*/
91+
[[nodiscard]] tl::expected<Events, Error> build();
92+
93+
private:
94+
Events config_;
95+
};
96+
97+
} // namespace launchdarkly::config::detail

libs/common/include/config/server.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ using SDK = config::detail::ServerSDK;
1212
using ApplicationInfo = config::detail::ApplicationInfo;
1313
using Endpoints = config::detail::EndpointsBuilder<SDK>;
1414
using ConfigBuilder = config::detail::ConfigBuilder<SDK>;
15+
using EventsBuilder = config::detail::EventsBuilder<SDK>;
1516
using Config = config::detail::Config<SDK>;
1617

1718
} // namespace launchdarkly::server

libs/common/include/context.hpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ class Context final {
7676
*
7777
* @return Returns a map of kinds to keys.
7878
*/
79-
[[nodiscard]] std::map<std::string, std::string> const&
80-
keys_and_kinds() const;
79+
[[nodiscard]] std::map<std::string, std::string> const& kinds_to_keys()
80+
const;
8181

8282
/**
8383
* Get a string containing errors the context encountered during
@@ -114,7 +114,6 @@ class Context final {
114114
Context& operator=(Context const&) = default;
115115
Context& operator=(Context&&) = default;
116116

117-
118117
private:
119118
/**
120119
* Create an invalid context with the given error message.
@@ -129,7 +128,7 @@ class Context final {
129128

130129
std::map<std::string, Attributes> attributes_;
131130
std::vector<std::string> kinds_;
132-
std::map<std::string, std::string> keys_and_kinds_;
131+
std::map<std::string, std::string> kinds_to_keys_;
133132
bool valid_ = false;
134133
std::string errors_;
135134
std::string canonical_key_;

libs/common/include/data/evaluation_result.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class EvaluationResult {
3636

3737
/**
3838
* A timestamp, which if the current time is before, a client SDK
39-
* should send debug events for the flag.
39+
* should AsyncSend debug events for the flag.
4040
* @return
4141
*/
4242
[[nodiscard]] std::optional<

libs/common/include/error.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ enum class Error : std::uint32_t {
1818
kConfig_ApplicationInfo_InvalidKeyCharacters = 202,
1919
kConfig_ApplicationInfo_InvalidValueCharacters = 203,
2020

21+
kConfig_Events_ZeroCapacity = 300,
22+
2123
/* Client-side errors: 10000-19999 */
2224
/* Server-side errors: 20000-29999 */
2325

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include "events/common_events.hpp"
4+
5+
namespace launchdarkly::events::client {
6+
7+
struct IdentifyEventParams {
8+
Date creation_date;
9+
Context context;
10+
};
11+
12+
struct IdentifyEvent {
13+
Date creation_date;
14+
EventContext context;
15+
};
16+
17+
struct FeatureEventParams {
18+
Date creation_date;
19+
std::string key;
20+
Context context;
21+
EvaluationResult eval_result;
22+
};
23+
24+
struct FeatureEventBase {
25+
Date creation_date;
26+
std::string key;
27+
Version version;
28+
std::optional<VariationIndex> variation;
29+
Value value;
30+
std::optional<Reason> reason;
31+
Value default_;
32+
};
33+
34+
struct FeatureEvent : public FeatureEventBase {
35+
ContextKeys context_keys;
36+
};
37+
38+
struct DebugEvent : public FeatureEventBase {
39+
EventContext context;
40+
};
41+
42+
} // namespace launchdarkly::events::client

0 commit comments

Comments
 (0)