@@ -45,34 +45,7 @@ type OptimizelyClient struct {
45
45
// IsFeatureEnabled returns true if the feature is enabled for the given user
46
46
func (o * OptimizelyClient ) IsFeatureEnabled (featureKey string , userContext entities.UserContext ) (result bool , err error ) {
47
47
48
- defer func () {
49
- if r := recover (); r != nil {
50
- errorMessage := fmt .Sprintf (`Optimizely SDK is panicking with the error "%s"` , string (debug .Stack ()))
51
- err = errors .New (errorMessage )
52
- logger .Error (errorMessage , err )
53
- }
54
- }()
55
-
56
- projectConfig , err := o .GetProjectConfig ()
57
- if err != nil {
58
- logger .Error ("Error retrieving feature" , err )
59
- return false , err
60
- }
61
-
62
- feature , err := projectConfig .GetFeatureByKey (featureKey )
63
- if err != nil {
64
- logger .Error ("Error retrieving feature" , err )
65
- return result , err
66
- }
67
- featureDecisionContext := decision.FeatureDecisionContext {
68
- Feature : & feature ,
69
- ProjectConfig : projectConfig ,
70
- }
71
-
72
- userID := userContext .ID
73
- logger .Debug (fmt .Sprintf (`Evaluating feature "%s" for user "%s".` , featureKey , userID ))
74
- featureDecision , err := o .decisionService .GetFeatureDecision (featureDecisionContext , userContext )
75
-
48
+ context , featureDecision , err := o .getFeatureDecision (featureKey , userContext )
76
49
if err != nil {
77
50
logger .Error ("received an error while computing feature decision" , err )
78
51
return result , err
@@ -85,17 +58,17 @@ func (o *OptimizelyClient) IsFeatureEnabled(featureKey string, userContext entit
85
58
}
86
59
87
60
if result {
88
- logger .Info (fmt .Sprintf (`Feature "%s" is enabled for user "%s".` , featureKey , userID ))
61
+ logger .Info (fmt .Sprintf (`Feature "%s" is enabled for user "%s".` , featureKey , userContext . ID ))
89
62
} else {
90
- logger .Info (fmt .Sprintf (`Feature "%s" is not enabled for user "%s".` , featureKey , userID ))
63
+ logger .Info (fmt .Sprintf (`Feature "%s" is not enabled for user "%s".` , featureKey , userContext . ID ))
91
64
}
92
65
93
66
if featureDecision .Source == decision .FeatureTest {
94
67
// send impression event for feature tests
95
- impressionEvent := event .CreateImpressionUserEvent (projectConfig , featureDecision .Experiment , * featureDecision .Variation , userContext )
68
+ impressionEvent := event .CreateImpressionUserEvent (context . ProjectConfig , featureDecision .Experiment , * featureDecision .Variation , userContext )
96
69
o .eventProcessor .ProcessEvent (impressionEvent )
97
70
}
98
- return result , nil
71
+ return result , err
99
72
}
100
73
101
74
// GetEnabledFeatures returns an array containing the keys of all features in the project that are enabled for the given user.
@@ -124,7 +97,7 @@ func (o *OptimizelyClient) GetEnabledFeatures(userContext entities.UserContext)
124
97
}
125
98
}
126
99
127
- return enabledFeatures , nil
100
+ return enabledFeatures , err
128
101
}
129
102
130
103
// Track take and event key with event tags and if the event is part of the config, send to events backend.
@@ -155,12 +128,12 @@ func (o *OptimizelyClient) Track(eventKey string, userContext entities.UserConte
155
128
return err
156
129
}
157
130
158
- return nil
131
+ return err
159
132
}
160
133
161
134
// GetFeatureVariableBoolean returns boolean feature variable value
162
135
func (o * OptimizelyClient ) GetFeatureVariableBoolean (featureKey , variableKey string , userContext entities.UserContext ) (value bool , err error ) {
163
- val , valueType , err := o .getFeatureVariable (featureKey , variableKey , userContext )
136
+ val , valueType , err := o .GetFeatureVariable (featureKey , variableKey , userContext )
164
137
if err != nil {
165
138
return false , err
166
139
}
@@ -173,7 +146,7 @@ func (o *OptimizelyClient) GetFeatureVariableBoolean(featureKey, variableKey str
173
146
174
147
// GetFeatureVariableDouble returns double feature variable value
175
148
func (o * OptimizelyClient ) GetFeatureVariableDouble (featureKey , variableKey string , userContext entities.UserContext ) (value float64 , err error ) {
176
- val , valueType , err := o .getFeatureVariable (featureKey , variableKey , userContext )
149
+ val , valueType , err := o .GetFeatureVariable (featureKey , variableKey , userContext )
177
150
if err != nil {
178
151
return 0 , err
179
152
}
@@ -186,7 +159,7 @@ func (o *OptimizelyClient) GetFeatureVariableDouble(featureKey, variableKey stri
186
159
187
160
// GetFeatureVariableInteger returns integer feature variable value
188
161
func (o * OptimizelyClient ) GetFeatureVariableInteger (featureKey , variableKey string , userContext entities.UserContext ) (value int , err error ) {
189
- val , valueType , err := o .getFeatureVariable (featureKey , variableKey , userContext )
162
+ val , valueType , err := o .GetFeatureVariable (featureKey , variableKey , userContext )
190
163
if err != nil {
191
164
return 0 , err
192
165
}
@@ -199,7 +172,7 @@ func (o *OptimizelyClient) GetFeatureVariableInteger(featureKey, variableKey str
199
172
200
173
// GetFeatureVariableString returns string feature variable value
201
174
func (o * OptimizelyClient ) GetFeatureVariableString (featureKey , variableKey string , userContext entities.UserContext ) (value string , err error ) {
202
- value , valueType , err := o .getFeatureVariable (featureKey , variableKey , userContext )
175
+ value , valueType , err := o .GetFeatureVariable (featureKey , variableKey , userContext )
203
176
if err != nil {
204
177
return "" , err
205
178
}
@@ -209,50 +182,98 @@ func (o *OptimizelyClient) GetFeatureVariableString(featureKey, variableKey stri
209
182
return value , err
210
183
}
211
184
212
- func (o * OptimizelyClient ) getFeatureVariable (featureKey , variableKey string , userContext entities.UserContext ) (value string , valueType entities.VariableType , err error ) {
185
+ // GetFeatureVariable returns feature as a string along with it's associated type
186
+ func (o * OptimizelyClient ) GetFeatureVariable (featureKey , variableKey string , userContext entities.UserContext ) (value string , valueType entities.VariableType , err error ) {
187
+
188
+ context , featureDecision , err := o .getFeatureDecision (featureKey , userContext )
189
+ if err != nil {
190
+ return "" , "" , err
191
+ }
192
+
193
+ variable , err := context .ProjectConfig .GetVariableByKey (featureKey , variableKey )
194
+ if err != nil {
195
+ return "" , "" , err
196
+ }
197
+
198
+ if featureDecision .Variation != nil {
199
+ if v , ok := featureDecision .Variation .Variables [variable .ID ]; ok && featureDecision .Variation .FeatureEnabled {
200
+ return v .Value , variable .Type , err
201
+ }
202
+ }
203
+
204
+ return variable .DefaultValue , variable .Type , err
205
+ }
206
+
207
+ // GetAllFeatureVariables returns all the variables for a given feature along with the enabled state
208
+ func (o * OptimizelyClient ) GetAllFeatureVariables (featureKey string , userContext entities.UserContext ) (enabled bool , variableMap map [string ]string , err error ) {
209
+ variableMap = make (map [string ]string )
210
+ decisionContext , featureDecision , err := o .getFeatureDecision (featureKey , userContext )
211
+ if err != nil {
212
+ logger .Error ("Optimizely SDK tracking error" , err )
213
+ return enabled , variableMap , err
214
+ }
215
+
216
+ feature := decisionContext .Feature
217
+ if featureDecision .Variation != nil {
218
+ enabled = featureDecision .Variation .FeatureEnabled
219
+ }
220
+
221
+ for _ , v := range feature .Variables {
222
+ variableMap [v .Key ] = v .DefaultValue
223
+
224
+ if enabled {
225
+ if variable , ok := featureDecision .Variation .Variables [v .ID ]; ok {
226
+ variableMap [v .Key ] = variable .Value
227
+ }
228
+ }
229
+ }
230
+
231
+ return enabled , variableMap , err
232
+ }
233
+
234
+ func (o * OptimizelyClient ) getFeatureDecision (featureKey string , userContext entities.UserContext ) (decisionContext decision.FeatureDecisionContext , featureDecision decision.FeatureDecision , err error ) {
213
235
214
236
defer func () {
215
237
if r := recover (); r != nil {
216
238
errorMessage := fmt .Sprintf (`optimizely SDK is panicking with the error "%s"` , string (debug .Stack ()))
217
- err = errors .New (errorMessage )
218
239
logger .Error (errorMessage , err )
240
+
241
+ // If we have a feature, then we can recover w/o throwing
242
+ if decisionContext .Feature == nil {
243
+ err = errors .New (errorMessage )
244
+ }
219
245
}
220
246
}()
221
247
248
+ userID := userContext .ID
249
+ logger .Debug (fmt .Sprintf (`Evaluating feature "%s" for user "%s".` , featureKey , userID ))
250
+
222
251
projectConfig , err := o .GetProjectConfig ()
223
252
if err != nil {
224
- logger .Error ("Error calling getFeatureVariable " , err )
225
- return "" , "" , err
253
+ logger .Error ("Error calling getFeatureDecision " , err )
254
+ return decisionContext , featureDecision , err
226
255
}
227
256
228
257
feature , err := projectConfig .GetFeatureByKey (featureKey )
229
258
if err != nil {
230
- logger .Error ("Error calling getFeatureVariable" , err )
231
- return "" , "" , err
232
- }
233
-
234
- variable , err := projectConfig .GetVariableByKey (featureKey , variableKey )
235
- if err != nil {
236
- logger .Error ("Error calling getFeatureVariable" , err )
237
- return "" , "" , err
259
+ logger .Error ("Error calling getFeatureDecision" , err )
260
+ return decisionContext , featureDecision , err
238
261
}
239
262
240
- featureValue := variable .DefaultValue
241
-
242
- featureDecisionContext := decision.FeatureDecisionContext {
263
+ decisionContext = decision.FeatureDecisionContext {
243
264
Feature : & feature ,
244
265
ProjectConfig : projectConfig ,
245
266
}
246
267
247
- featureDecision , err : = o .decisionService .GetFeatureDecision (featureDecisionContext , userContext )
248
- if err == nil && featureDecision . Variation != nil {
249
- if v , ok := featureDecision . Variation . Variables [ variable . ID ]; ok && featureDecision . Variation . FeatureEnabled {
250
- featureValue = v . Value
251
- }
268
+ featureDecision , err = o .decisionService .GetFeatureDecision (decisionContext , userContext )
269
+ if err != nil {
270
+ err = nil
271
+ logger . Warning ( "error making a decision" )
272
+ return decisionContext , featureDecision , err
252
273
}
253
274
254
275
// @TODO(yasir): send decision notification
255
- return featureValue , variable . Type , nil
276
+ return decisionContext , featureDecision , err
256
277
}
257
278
258
279
// GetProjectConfig returns the current ProjectConfig or nil if the instance is not valid
0 commit comments