Skip to content

Commit a252882

Browse files
feat: changes in feature decision notification (#257)
feat: changes in feature decision notification
1 parent 6e3fd0f commit a252882

File tree

8 files changed

+1126
-1187
lines changed

8 files changed

+1126
-1187
lines changed

pkg/client/client.go

Lines changed: 188 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
package client
1919

2020
import (
21+
"encoding/json"
2122
"errors"
2223
"fmt"
2324
"reflect"
@@ -120,6 +121,14 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
120121
o.logger.Info(fmt.Sprintf(`Feature "%s" is not enabled for user "%s".`, featureKey, userContext.ID))
121122
}
122123

124+
if o.notificationCenter != nil {
125+
decisionNotification := decision.FeatureNotification(featureKey, &featureDecision, &userContext)
126+
127+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
128+
o.logger.Warning("Problem with sending notification")
129+
}
130+
}
131+
123132
if featureDecision.Source == decision.FeatureTest && featureDecision.Variation != nil {
124133
// send impression event for feature tests
125134
impressionEvent := event.CreateImpressionUserEvent(decisionContext.ProjectConfig, featureDecision.Experiment, *featureDecision.Variation, userContext)
@@ -164,93 +173,230 @@ func (o *OptimizelyClient) GetEnabledFeatures(userContext entities.UserContext)
164173
}
165174

166175
// GetFeatureVariableBoolean returns the feature variable value of type bool associated with the given feature and variable keys.
167-
func (o *OptimizelyClient) GetFeatureVariableBoolean(featureKey, variableKey string, userContext entities.UserContext) (value bool, err error) {
176+
func (o *OptimizelyClient) GetFeatureVariableBoolean(featureKey, variableKey string, userContext entities.UserContext) (convertedValue bool, err error) {
177+
178+
stringValue, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
179+
defer func() {
180+
if o.notificationCenter != nil {
181+
variableMap := map[string]interface{}{
182+
"variableKey": variableKey,
183+
"variableType": variableType,
184+
"variableValue": convertedValue,
185+
}
186+
if err != nil {
187+
variableMap["variableValue"] = stringValue
188+
}
189+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
190+
decisionNotification.Type = notification.FeatureVariable
191+
192+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
193+
o.logger.Warning("Problem with sending notification")
194+
}
195+
}
196+
}()
168197

169-
val, valueType, err := o.GetFeatureVariable(featureKey, variableKey, userContext)
170198
if err != nil {
171-
return false, err
199+
return convertedValue, err
172200
}
173-
convertedValue, err := strconv.ParseBool(val)
174-
if err != nil || valueType != entities.Boolean {
201+
convertedValue, err = strconv.ParseBool(stringValue)
202+
if err != nil || variableType != entities.Boolean {
175203
return false, fmt.Errorf("variable value for key %s is invalid or wrong type", variableKey)
176204
}
177205
return convertedValue, err
178206
}
179207

180208
// GetFeatureVariableDouble returns the feature variable value of type double associated with the given feature and variable keys.
181-
func (o *OptimizelyClient) GetFeatureVariableDouble(featureKey, variableKey string, userContext entities.UserContext) (value float64, err error) {
209+
func (o *OptimizelyClient) GetFeatureVariableDouble(featureKey, variableKey string, userContext entities.UserContext) (convertedValue float64, err error) {
182210

183-
val, valueType, err := o.GetFeatureVariable(featureKey, variableKey, userContext)
211+
stringValue, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
212+
defer func() {
213+
if o.notificationCenter != nil {
214+
variableMap := map[string]interface{}{
215+
"variableKey": variableKey,
216+
"variableType": variableType,
217+
"variableValue": convertedValue,
218+
}
219+
if err != nil {
220+
variableMap["variableValue"] = stringValue
221+
}
222+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
223+
decisionNotification.Type = notification.FeatureVariable
224+
225+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
226+
o.logger.Warning("Problem with sending notification")
227+
}
228+
}
229+
}()
184230
if err != nil {
185-
return 0, err
231+
return convertedValue, err
186232
}
187-
convertedValue, err := strconv.ParseFloat(val, 64)
188-
if err != nil || valueType != entities.Double {
233+
convertedValue, err = strconv.ParseFloat(stringValue, 64)
234+
if err != nil || variableType != entities.Double {
189235
return 0, fmt.Errorf("variable value for key %s is invalid or wrong type", variableKey)
190236
}
237+
191238
return convertedValue, err
192239
}
193240

194241
// GetFeatureVariableInteger returns the feature variable value of type int associated with the given feature and variable keys.
195-
func (o *OptimizelyClient) GetFeatureVariableInteger(featureKey, variableKey string, userContext entities.UserContext) (value int, err error) {
242+
func (o *OptimizelyClient) GetFeatureVariableInteger(featureKey, variableKey string, userContext entities.UserContext) (convertedValue int, err error) {
196243

197-
val, valueType, err := o.GetFeatureVariable(featureKey, variableKey, userContext)
244+
stringValue, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
245+
defer func() {
246+
if o.notificationCenter != nil {
247+
variableMap := map[string]interface{}{
248+
"variableKey": variableKey,
249+
"variableType": variableType,
250+
"variableValue": convertedValue,
251+
}
252+
if err != nil {
253+
variableMap["variableValue"] = stringValue
254+
}
255+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
256+
decisionNotification.Type = notification.FeatureVariable
257+
258+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
259+
o.logger.Warning("Problem with sending notification")
260+
}
261+
}
262+
}()
198263
if err != nil {
199-
return 0, err
264+
return convertedValue, err
200265
}
201-
convertedValue, err := strconv.Atoi(val)
202-
if err != nil || valueType != entities.Integer {
266+
convertedValue, err = strconv.Atoi(stringValue)
267+
if err != nil || variableType != entities.Integer {
203268
return 0, fmt.Errorf("variable value for key %s is invalid or wrong type", variableKey)
204269
}
270+
205271
return convertedValue, err
206272
}
207273

208274
// GetFeatureVariableString returns the feature variable value of type string associated with the given feature and variable keys.
209-
func (o *OptimizelyClient) GetFeatureVariableString(featureKey, variableKey string, userContext entities.UserContext) (value string, err error) {
275+
func (o *OptimizelyClient) GetFeatureVariableString(featureKey, variableKey string, userContext entities.UserContext) (stringValue string, err error) {
276+
277+
stringValue, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
278+
279+
defer func() {
280+
if o.notificationCenter != nil {
281+
variableMap := map[string]interface{}{
282+
"variableKey": variableKey,
283+
"variableType": variableType,
284+
"variableValue": stringValue,
285+
}
286+
287+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
288+
decisionNotification.Type = notification.FeatureVariable
210289

211-
value, valueType, err := o.GetFeatureVariable(featureKey, variableKey, userContext)
290+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
291+
o.logger.Warning("Problem with sending notification")
292+
}
293+
}
294+
}()
212295
if err != nil {
213296
return "", err
214297
}
215-
if valueType != entities.String {
298+
if variableType != entities.String {
216299
return "", fmt.Errorf("variable value for key %s is wrong type", variableKey)
217300
}
218-
return value, err
301+
302+
return stringValue, err
219303
}
220304

221305
// GetFeatureVariableJSON returns the feature variable value of type json associated with the given feature and variable keys.
222-
func (o *OptimizelyClient) GetFeatureVariableJSON(featureKey, variableKey string, userContext entities.UserContext) (value *optimizelyjson.OptimizelyJSON, err error) {
306+
func (o *OptimizelyClient) GetFeatureVariableJSON(featureKey, variableKey string, userContext entities.UserContext) (optlyJSON *optimizelyjson.OptimizelyJSON, err error) {
223307

224-
val, valueType, err := o.GetFeatureVariable(featureKey, variableKey, userContext)
308+
stringVal, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
309+
defer func() {
310+
if o.notificationCenter != nil {
311+
var variableValue interface{}
312+
if optlyJSON != nil {
313+
variableValue = optlyJSON.ToMap()
314+
} else {
315+
variableValue = stringVal
316+
}
317+
variableMap := map[string]interface{}{
318+
"variableKey": variableKey,
319+
"variableType": variableType,
320+
"variableValue": variableValue,
321+
}
322+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
323+
decisionNotification.Type = notification.FeatureVariable
324+
325+
if e := o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
326+
o.logger.Warning("Problem with sending notification")
327+
}
328+
}
329+
}()
225330
if err != nil {
226-
return value, err
331+
return optlyJSON, err
227332
}
228333

229-
value, err = optimizelyjson.NewOptimizelyJSONfromString(val)
230-
if err != nil || valueType != entities.JSON {
231-
return nil, fmt.Errorf("variable value for key %s is invalid or wrong type", variableKey)
334+
optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(stringVal)
335+
if err != nil || variableType != entities.JSON {
336+
optlyJSON, err = nil, fmt.Errorf("variable value for key %s is invalid or wrong type", variableKey)
232337
}
233338

234-
return value, err
339+
return optlyJSON, err
235340
}
236341

237-
// GetFeatureVariable returns feature variable as a string along with it's associated type.
238-
func (o *OptimizelyClient) GetFeatureVariable(featureKey, variableKey string, userContext entities.UserContext) (value string, valueType entities.VariableType, err error) {
342+
// getFeatureVariable is a helper function, returns feature variable as a string along with it's associated type and feature decision
343+
func (o *OptimizelyClient) getFeatureVariable(featureKey, variableKey string, userContext entities.UserContext) (string, entities.VariableType, *decision.FeatureDecision, error) {
239344

240345
featureDecisionContext, featureDecision, err := o.getFeatureDecision(featureKey, variableKey, userContext)
241346
if err != nil {
242-
return "", "", err
347+
return "", "", &featureDecision, err
243348
}
244349

245350
variable := featureDecisionContext.Variable
246351

247352
if featureDecision.Variation != nil {
248353
if v, ok := featureDecision.Variation.Variables[variable.ID]; ok && featureDecision.Variation.FeatureEnabled {
249-
return v.Value, variable.Type, err
354+
return v.Value, variable.Type, &featureDecision, nil
250355
}
251356
}
252357

253-
return variable.DefaultValue, variable.Type, err
358+
return variable.DefaultValue, variable.Type, &featureDecision, nil
359+
}
360+
361+
// GetFeatureVariable returns feature variable as a string along with it's associated type.
362+
func (o *OptimizelyClient) GetFeatureVariable(featureKey, variableKey string, userContext entities.UserContext) (string, entities.VariableType, error) {
363+
364+
stringValue, variableType, featureDecision, err := o.getFeatureVariable(featureKey, variableKey, userContext)
365+
366+
func() {
367+
var convertedValue interface{}
368+
var e error
369+
370+
convertedValue = stringValue
371+
switch variableType {
372+
case entities.Integer:
373+
convertedValue, e = strconv.Atoi(stringValue)
374+
case entities.Double:
375+
convertedValue, e = strconv.ParseFloat(stringValue, 64)
376+
case entities.Boolean:
377+
convertedValue, e = strconv.ParseBool(stringValue)
378+
case entities.JSON:
379+
convertedValue = map[string]string{}
380+
e = json.Unmarshal([]byte(stringValue), &convertedValue)
381+
}
382+
if e != nil {
383+
o.logger.Warning("Problem with converting string value to proper type for notification builder")
384+
}
385+
386+
variableMap := map[string]interface{}{
387+
"variableKey": variableKey,
388+
"variableType": variableType,
389+
"variableValue": convertedValue,
390+
}
391+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, featureDecision, &userContext, variableMap)
392+
decisionNotification.Type = notification.FeatureVariable
393+
394+
if e = o.notificationCenter.Send(notification.Decision, *decisionNotification); e != nil {
395+
o.logger.Warning("Problem with sending notification")
396+
}
397+
}()
398+
399+
return stringValue, variableType, err
254400
}
255401

256402
// GetAllFeatureVariablesWithDecision returns all the variables for a given feature along with the enabled state.
@@ -297,7 +443,8 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string,
297443
out, err = strconv.Atoi(val)
298444
errs = multierror.Append(errs, err)
299445
case entities.JSON:
300-
var optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val)
446+
var optlyJSON *optimizelyjson.OptimizelyJSON
447+
optlyJSON, err = optimizelyjson.NewOptimizelyJSONfromString(val)
301448
out = optlyJSON.ToMap()
302449
errs = multierror.Append(errs, err)
303450
case entities.String:
@@ -308,6 +455,15 @@ func (o *OptimizelyClient) GetAllFeatureVariablesWithDecision(featureKey string,
308455
variableMap[v.Key] = out
309456
}
310457

458+
if o.notificationCenter != nil {
459+
decisionNotification := decision.FeatureNotificationWithVariables(featureKey, &featureDecision, &userContext,
460+
map[string]interface{}{"variableValues": variableMap})
461+
decisionNotification.Type = notification.AllFeatureVariables
462+
463+
if err = o.notificationCenter.Send(notification.Decision, *decisionNotification); err != nil {
464+
o.logger.Warning("Problem with sending notification")
465+
}
466+
}
311467
return enabled, variableMap, errs.ErrorOrNil()
312468
}
313469

0 commit comments

Comments
 (0)