@@ -41,7 +41,8 @@ Client::Client(Config config, Context context)
41
41
flag_updater_,
42
42
status_manager_,
43
43
logger_)),
44
- initialized_(false ) {
44
+ initialized_(false ),
45
+ eval_reasons_available_(config.DataSourceConfig().with_reasons) {
45
46
if (config.Events ().Enabled ()) {
46
47
event_processor_ = std::make_unique<detail::EventProcessor>(
47
48
ioc_.get_executor (), config, logger_);
@@ -67,6 +68,11 @@ Client::Client(Config config, Context context)
67
68
run_thread_ = std::move (std::thread ([&]() { ioc_.run (); }));
68
69
}
69
70
71
+ bool Client::Initialized () const {
72
+ std::unique_lock lock (init_mutex_);
73
+ return initialized_;
74
+ }
75
+
70
76
std::unordered_map<Client::FlagKey, Value> Client::AllFlags () const {
71
77
return {};
72
78
}
@@ -100,34 +106,150 @@ void Client::AsyncIdentify(Context context) {
100
106
std::chrono::system_clock::now (), std::move (context)});
101
107
}
102
108
103
- Value Client::VariationInternal (FlagKey const & key, Value default_value) {
104
- auto res = flag_manager_.Get (key);
105
- if (res && res->flag ) {
106
- return res->flag ->detail ().value ();
109
+ // TODO(cwaldren): refactor VariationInternal so it isn't so long and mixing up
110
+ // multiple concerns.
111
+ template <typename T>
112
+ EvaluationDetail<T> Client::VariationInternal (FlagKey const & key,
113
+ Value default_value,
114
+ bool check_type,
115
+ bool detailed) {
116
+ auto desc = flag_manager_.Get (key);
117
+
118
+ events::client::FeatureEventParams event = {
119
+ std::chrono::system_clock::now (),
120
+ key,
121
+ context_,
122
+ default_value,
123
+ default_value,
124
+ std::nullopt,
125
+ std::nullopt,
126
+ std::nullopt,
127
+ false ,
128
+ std::nullopt,
129
+ };
130
+
131
+ if (!desc || !desc->flag ) {
132
+ if (!Initialized ()) {
133
+ LD_LOG (logger_, LogLevel::kWarn )
134
+ << " LaunchDarkly client has not yet been initialized. "
135
+ " Returning default value" ;
136
+
137
+ // TODO: SC-199918
138
+ auto error_reason = EvaluationReason (" CLIENT_NOT_READY" );
139
+ if (eval_reasons_available_) {
140
+ event.reason = error_reason;
141
+ }
142
+ event_processor_->AsyncSend (std::move (event));
143
+ return EvaluationDetail<T>(default_value, std::nullopt,
144
+ std::move (error_reason));
145
+ }
146
+
147
+ LD_LOG (logger_, LogLevel::kInfo )
148
+ << " Unknown feature flag " << key << " ; returning default value" ;
149
+
150
+ auto error_reason = EvaluationReason (" FLAG_NOT_FOUND" );
151
+ if (eval_reasons_available_) {
152
+ event.reason = error_reason;
153
+ }
154
+ event_processor_->AsyncSend (std::move (event));
155
+ return EvaluationDetail<T>(default_value, std::nullopt,
156
+ std::move (error_reason));
157
+
158
+ } else if (!Initialized ()) {
159
+ LD_LOG (logger_, LogLevel::kWarn )
160
+ << " LaunchDarkly client has not yet been initialized. "
161
+ " Returning cached value" ;
162
+ }
163
+
164
+ assert (desc->flag );
165
+
166
+ auto const & flag = *(desc->flag );
167
+ auto const & detail = flag.detail ();
168
+
169
+ if (check_type && default_value.type () != Value::Type::kNull &&
170
+ detail.value ().type () != default_value.type ()) {
171
+ auto error_reason = EvaluationReason (" WRONG_TYPE" );
172
+ if (eval_reasons_available_) {
173
+ event.reason = error_reason;
174
+ }
175
+ event_processor_->AsyncSend (std::move (event));
176
+ return EvaluationDetail<T>(default_value, std::nullopt, error_reason);
177
+ }
178
+
179
+ event.value = detail.value ();
180
+ event.variation = detail.variation_index ();
181
+
182
+ if (detailed || flag.track_reason ()) {
183
+ event.reason = detail.reason ();
184
+ }
185
+
186
+ event.version = flag.flag_version ().value_or (flag.version ());
187
+ event.require_full_event = flag.track_events ();
188
+ if (auto date = flag.debug_events_until_date ()) {
189
+ event.debug_events_until_date = events::Date{*date};
107
190
}
108
- return default_value;
191
+
192
+ event_processor_->AsyncSend (std::move (event));
193
+
194
+ // TODO: this isn't a valid error, figure out how to handle if reason is
195
+ // missing.
196
+ EvaluationReason returned_reason (" UNKNOWN" );
197
+ if (detail.reason ()) {
198
+ returned_reason = detail.reason ()->get ();
199
+ }
200
+ return EvaluationDetail<T>(detail.value (), detail.variation_index (),
201
+ returned_reason);
202
+ }
203
+
204
+ EvaluationDetail<bool > Client::BoolVariationDetail (Client::FlagKey const & key,
205
+ bool default_value) {
206
+ return VariationInternal<bool >(key, default_value, true , true );
109
207
}
110
208
111
209
bool Client::BoolVariation (Client::FlagKey const & key, bool default_value) {
112
- return VariationInternal (key, default_value).as_bool ();
210
+ return *VariationInternal<bool >(key, default_value, true , false );
211
+ }
212
+
213
+ EvaluationDetail<std::string> Client::StringVariationDetail (
214
+ Client::FlagKey const & key,
215
+ std::string default_value) {
216
+ return VariationInternal<std::string>(key, std::move (default_value), true ,
217
+ true );
113
218
}
114
219
115
220
std::string Client::StringVariation (Client::FlagKey const & key,
116
221
std::string default_value) {
117
- return VariationInternal (key, std::move (default_value)).as_string ();
222
+ return *VariationInternal<std::string>(key, std::move (default_value), true ,
223
+ false );
224
+ }
225
+
226
+ EvaluationDetail<double > Client::DoubleVariationDetail (
227
+ Client::FlagKey const & key,
228
+ double default_value) {
229
+ return VariationInternal<double >(key, default_value, true , true );
118
230
}
119
231
120
232
double Client::DoubleVariation (Client::FlagKey const & key,
121
233
double default_value) {
122
- return VariationInternal (key, default_value). as_double ( );
234
+ return * VariationInternal< double > (key, default_value, true , false );
123
235
}
124
236
237
+ EvaluationDetail<int > Client::IntVariationDetail (Client::FlagKey const & key,
238
+ int default_value) {
239
+ return VariationInternal<int >(key, default_value, true , true );
240
+ }
125
241
int Client::IntVariation (Client::FlagKey const & key, int default_value) {
126
- return VariationInternal (key, default_value).as_int ();
242
+ return *VariationInternal<int >(key, default_value, true , false );
243
+ }
244
+
245
+ EvaluationDetail<Value> Client::JsonVariationDetail (Client::FlagKey const & key,
246
+ Value default_value) {
247
+ return VariationInternal<Value>(key, std::move (default_value), false , true );
127
248
}
128
249
129
250
Value Client::JsonVariation (Client::FlagKey const & key, Value default_value) {
130
- return VariationInternal (key, std::move (default_value));
251
+ return *VariationInternal<Value>(key, std::move (default_value), false ,
252
+ false );
131
253
}
132
254
133
255
data_sources::IDataSourceStatusProvider& Client::DataSourceStatus () {
0 commit comments