@@ -42,6 +42,41 @@ type OptimizelyClient struct {
4242 executionCtx utils.ExecutionCtx
4343}
4444
45+ // Activate returns the key of the variation the user is bucketed into and sends an impression event to the Optimizely log endpoint
46+ func (o * OptimizelyClient ) Activate (experimentKey string , userContext entities.UserContext ) (result string , err error ) {
47+
48+ defer func () {
49+ if r := recover (); r != nil {
50+ switch t := r .(type ) {
51+ case error :
52+ err = t
53+ case string :
54+ err = errors .New (t )
55+ default :
56+ err = errors .New ("unexpected error" )
57+ }
58+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
59+ logger .Error (errorMessage , err )
60+ logger .Debug (string (debug .Stack ()))
61+ }
62+ }()
63+
64+ decisionContext , experimentDecision , err := o .getExperimentDecision (experimentKey , userContext )
65+ if err != nil {
66+ logger .Error ("received an error while computing experiment decision" , err )
67+ return result , err
68+ }
69+
70+ if experimentDecision .Variation != nil {
71+ // send an impression event
72+ result = experimentDecision .Variation .Key
73+ impressionEvent := event .CreateImpressionUserEvent (decisionContext .ProjectConfig , * decisionContext .Experiment , * experimentDecision .Variation , userContext )
74+ o .EventProcessor .ProcessEvent (impressionEvent )
75+ }
76+
77+ return result , err
78+ }
79+
4580// IsFeatureEnabled returns true if the feature is enabled for the given user
4681func (o * OptimizelyClient ) IsFeatureEnabled (featureKey string , userContext entities.UserContext ) (result bool , err error ) {
4782
@@ -124,45 +159,6 @@ func (o *OptimizelyClient) GetEnabledFeatures(userContext entities.UserContext)
124159 return enabledFeatures , err
125160}
126161
127- // Track take and event key with event tags and if the event is part of the config, send to events backend.
128- func (o * OptimizelyClient ) Track (eventKey string , userContext entities.UserContext , eventTags map [string ]interface {}) (err error ) {
129-
130- defer func () {
131- if r := recover (); r != nil {
132- switch t := r .(type ) {
133- case error :
134- err = t
135- case string :
136- err = errors .New (t )
137- default :
138- err = errors .New ("unexpected error" )
139- }
140- errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
141- logger .Error (errorMessage , err )
142- logger .Debug (string (debug .Stack ()))
143- }
144- }()
145-
146- projectConfig , err := o .GetProjectConfig ()
147- if err != nil {
148- logger .Error ("Optimizely SDK tracking error" , err )
149- return err
150- }
151-
152- configEvent , err := projectConfig .GetEventByKey (eventKey )
153-
154- if err == nil {
155- userEvent := event .CreateConversionUserEvent (projectConfig , configEvent , userContext , eventTags )
156- o .EventProcessor .ProcessEvent (userEvent )
157- } else {
158- errorMessage := fmt .Sprintf (`optimizely SDK track: error getting event with key "%s"` , eventKey )
159- logger .Error (errorMessage , err )
160- return err
161- }
162-
163- return err
164- }
165-
166162// GetFeatureVariableBoolean returns boolean feature variable value
167163func (o * OptimizelyClient ) GetFeatureVariableBoolean (featureKey , variableKey string , userContext entities.UserContext ) (value bool , err error ) {
168164
@@ -364,43 +360,106 @@ func (o *OptimizelyClient) GetAllFeatureVariables(featureKey string, userContext
364360 return enabled , variableMap , err
365361}
366362
367- func (o * OptimizelyClient ) getFeatureDecision (featureKey string , userContext entities.UserContext ) (decisionContext decision.FeatureDecisionContext , featureDecision decision.FeatureDecision , err error ) {
363+ // GetVariation returns the key of the variation the user is bucketed into
364+ func (o * OptimizelyClient ) GetVariation (experimentKey string , userContext entities.UserContext ) (result string , err error ) {
368365
369366 defer func () {
370- var e error
371367 if r := recover (); r != nil {
372368 switch t := r .(type ) {
373369 case error :
374- e = t
370+ err = t
375371 case string :
376- e = errors .New (t )
372+ err = errors .New (t )
377373 default :
378- e = errors .New ("unexpected error" )
374+ err = errors .New ("unexpected error" )
379375 }
380376 errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
381- logger .Error (errorMessage , e )
377+ logger .Error (errorMessage , err )
382378 logger .Debug (string (debug .Stack ()))
379+ }
380+ }()
383381
384- // If we have a feature, then we can recover w/o throwing
385- if decisionContext .Feature == nil {
386- err = e
382+ _ , experimentDecision , err := o .getExperimentDecision (experimentKey , userContext )
383+ if err != nil {
384+ logger .Error ("received an error while computing experiment decision" , err )
385+ }
386+
387+ if experimentDecision .Variation != nil {
388+ result = experimentDecision .Variation .Key
389+ }
390+
391+ return result , err
392+ }
393+
394+ // Track take and event key with event tags and if the event is part of the config, send to events backend.
395+ func (o * OptimizelyClient ) Track (eventKey string , userContext entities.UserContext , eventTags map [string ]interface {}) (err error ) {
396+
397+ defer func () {
398+ if r := recover (); r != nil {
399+ switch t := r .(type ) {
400+ case error :
401+ err = t
402+ case string :
403+ err = errors .New (t )
404+ default :
405+ err = errors .New ("unexpected error" )
406+ }
407+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
408+ logger .Error (errorMessage , err )
409+ logger .Debug (string (debug .Stack ()))
410+ }
411+ }()
412+
413+ projectConfig , e := o .GetProjectConfig ()
414+ if e != nil {
415+ logger .Error ("Optimizely SDK tracking error" , e )
416+ return e
417+ }
418+
419+ configEvent , e := projectConfig .GetEventByKey (eventKey )
420+
421+ if e != nil {
422+ errorMessage := fmt .Sprintf (`optimizely SDK track: error getting event with key "%s"` , eventKey )
423+ logger .Error (errorMessage , e )
424+ return e
425+ }
426+
427+ userEvent := event .CreateConversionUserEvent (projectConfig , configEvent , userContext , eventTags )
428+ o .EventProcessor .ProcessEvent (userEvent )
429+ return nil
430+ }
431+
432+ func (o * OptimizelyClient ) getFeatureDecision (featureKey string , userContext entities.UserContext ) (decisionContext decision.FeatureDecisionContext , featureDecision decision.FeatureDecision , err error ) {
433+
434+ defer func () {
435+ if r := recover (); r != nil {
436+ switch t := r .(type ) {
437+ case error :
438+ err = t
439+ case string :
440+ err = errors .New (t )
441+ default :
442+ err = errors .New ("unexpected error" )
387443 }
444+ errorMessage := fmt .Sprintf ("optimizely SDK is panicking with the error:" )
445+ logger .Error (errorMessage , err )
446+ logger .Debug (string (debug .Stack ()))
388447 }
389448 }()
390449
391450 userID := userContext .ID
392451 logger .Debug (fmt .Sprintf (`Evaluating feature "%s" for user "%s".` , featureKey , userID ))
393452
394- projectConfig , err := o .GetProjectConfig ()
395- if err != nil {
396- logger .Error ("Error calling getFeatureDecision" , err )
397- return decisionContext , featureDecision , err
453+ projectConfig , e := o .GetProjectConfig ()
454+ if e != nil {
455+ logger .Error ("Error calling getFeatureDecision" , e )
456+ return decisionContext , featureDecision , e
398457 }
399458
400- feature , err := projectConfig .GetFeatureByKey (featureKey )
401- if err != nil {
402- logger .Error ("Error calling getFeatureDecision" , err )
403- return decisionContext , featureDecision , err
459+ feature , e := projectConfig .GetFeatureByKey (featureKey )
460+ if e != nil {
461+ logger .Error ("Error calling getFeatureDecision" , e )
462+ return decisionContext , featureDecision , e
404463 }
405464
406465 decisionContext = decision.FeatureDecisionContext {
@@ -410,15 +469,51 @@ func (o *OptimizelyClient) getFeatureDecision(featureKey string, userContext ent
410469
411470 featureDecision , err = o .DecisionService .GetFeatureDecision (decisionContext , userContext )
412471 if err != nil {
413- err = nil
414472 logger .Warning ("error making a decision" )
415473 return decisionContext , featureDecision , err
416474 }
417475
418- // @TODO(yasir): send decision notification
419476 return decisionContext , featureDecision , err
420477}
421478
479+ func (o * OptimizelyClient ) getExperimentDecision (experimentKey string , userContext entities.UserContext ) (decisionContext decision.ExperimentDecisionContext , experimentDecision decision.ExperimentDecision , err error ) {
480+
481+ userID := userContext .ID
482+ logger .Debug (fmt .Sprintf (`Evaluating experiment "%s" for user "%s".` , experimentKey , userID ))
483+
484+ projectConfig , e := o .GetProjectConfig ()
485+ if e != nil {
486+ logger .Error ("Error calling getExperimentDecision" , e )
487+ return decisionContext , experimentDecision , e
488+ }
489+
490+ experiment , e := projectConfig .GetExperimentByKey (experimentKey )
491+ if e != nil {
492+ logger .Error ("Error calling getExperimentDecision" , e )
493+ return decisionContext , experimentDecision , e
494+ }
495+
496+ decisionContext = decision.ExperimentDecisionContext {
497+ Experiment : & experiment ,
498+ ProjectConfig : projectConfig ,
499+ }
500+
501+ experimentDecision , err = o .DecisionService .GetExperimentDecision (decisionContext , userContext )
502+ if err != nil {
503+ logger .Warning (fmt .Sprintf (`error making a decision for experiment "%s"` , experimentKey ))
504+ return decisionContext , experimentDecision , err
505+ }
506+
507+ if experimentDecision .Variation != nil {
508+ result := experimentDecision .Variation .Key
509+ logger .Info (fmt .Sprintf (`User "%s" is bucketed into variation "%s" of experiment "%s".` , userContext .ID , result , experimentKey ))
510+ } else {
511+ logger .Info (fmt .Sprintf (`User "%s" is not bucketed into any variation for experiment "%s".` , userContext .ID , experimentKey ))
512+ }
513+
514+ return decisionContext , experimentDecision , err
515+ }
516+
422517// GetProjectConfig returns the current ProjectConfig or nil if the instance is not valid
423518func (o * OptimizelyClient ) GetProjectConfig () (projectConfig optimizely.ProjectConfig , err error ) {
424519
0 commit comments