11package client
22
33import (
4+ "encoding/json"
45 "errors"
56 "fmt"
67 "runtime/debug"
@@ -54,6 +55,22 @@ type TreatmentResult struct {
5455 Config * string `json:"config"`
5556}
5657
58+ type options struct {
59+ evaluationOptions * dtos.EvaluationOptions
60+ }
61+
62+ type OptFn = func (o * options )
63+
64+ func (c * SplitClient ) WithEvaluationOptions (e * dtos.EvaluationOptions ) OptFn {
65+ return func (o * options ) { o .evaluationOptions = e }
66+ }
67+
68+ func defaultOpts () options {
69+ return options {
70+ evaluationOptions : nil ,
71+ }
72+ }
73+
5774// getEvaluationResult calls evaluation for one particular feature flag
5875func (c * SplitClient ) getEvaluationResult (matchingKey string , bucketingKey * string , featureFlag string , attributes map [string ]interface {}, operation string ) * evaluator.Result {
5976 if c .isReady () {
@@ -95,7 +112,7 @@ func (c *SplitClient) getEvaluationsResult(matchingKey string, bucketingKey *str
95112}
96113
97114// createImpression creates impression to be stored and used by listener
98- func (c * SplitClient ) createImpression (featureFlag string , bucketingKey * string , evaluationLabel string , matchingKey string , treatment string , changeNumber int64 , disabled bool ) dtos.Impression {
115+ func (c * SplitClient ) createImpression (featureFlag string , bucketingKey * string , evaluationLabel string , matchingKey string , treatment string , changeNumber int64 , disabled bool , properties string ) dtos.Impression {
99116 var label string
100117 if c .factory .cfg .LabelsEnabled {
101118 label = evaluationLabel
@@ -115,6 +132,7 @@ func (c *SplitClient) createImpression(featureFlag string, bucketingKey *string,
115132 Treatment : treatment ,
116133 Time : time .Now ().UTC ().UnixNano () / int64 (time .Millisecond ), // Convert standard timestamp to java's ms timestamps
117134 Disabled : disabled ,
135+ Properties : properties ,
118136 }
119137}
120138
@@ -140,7 +158,7 @@ func (c *SplitClient) storeData(impressions []dtos.Impression, attributes map[st
140158}
141159
142160// doTreatmentCall retrieves treatments of an specific feature flag with configurations object if it is present for a certain key and set of attributes
143- func (c * SplitClient ) doTreatmentCall (key interface {}, featureFlag string , attributes map [string ]interface {}, operation string , metricsLabel string ) (t TreatmentResult ) {
161+ func (c * SplitClient ) doTreatmentCall (key interface {}, featureFlag string , attributes map [string ]interface {}, operation string , metricsLabel string , evaluationOptions * dtos. EvaluationOptions ) (t TreatmentResult ) {
144162 controlTreatment := TreatmentResult {
145163 Treatment : evaluator .Control ,
146164 Config : nil ,
@@ -184,7 +202,7 @@ func (c *SplitClient) doTreatmentCall(key interface{}, featureFlag string, attri
184202 }
185203
186204 c .storeData (
187- []dtos.Impression {c .createImpression (featureFlag , bucketingKey , evaluationResult .Label , matchingKey , evaluationResult .Treatment , evaluationResult .SplitChangeNumber , evaluationResult .ImpressionsDisabled )},
205+ []dtos.Impression {c .createImpression (featureFlag , bucketingKey , evaluationResult .Label , matchingKey , evaluationResult .Treatment , evaluationResult .SplitChangeNumber , evaluationResult .ImpressionsDisabled , serializeProperties ( evaluationOptions ) )},
188206 attributes ,
189207 metricsLabel ,
190208 evaluationResult .EvaluationTime ,
@@ -196,16 +214,42 @@ func (c *SplitClient) doTreatmentCall(key interface{}, featureFlag string, attri
196214 }
197215}
198216
217+ func serializeProperties (opts * dtos.EvaluationOptions ) string {
218+ if opts == nil {
219+ return ""
220+ }
221+ if len (opts .Properties ) == 0 {
222+ return ""
223+ }
224+
225+ properties , err := json .Marshal (opts .Properties )
226+ if err != nil {
227+ return ""
228+ }
229+
230+ return string (properties )
231+ }
232+
199233// Treatment implements the main functionality of split. Retrieve treatments of a specific feature flag
200234// for a certain key and set of attributes
201- func (c * SplitClient ) Treatment (key interface {}, featureFlagName string , attributes map [string ]interface {}) string {
202- return c .doTreatmentCall (key , featureFlagName , attributes , treatment , telemetry .Treatment ).Treatment
235+ func (c * SplitClient ) Treatment (key interface {}, featureFlagName string , attributes map [string ]interface {}, optFns ... OptFn ) string {
236+ options := getOptions (optFns ... )
237+ return c .doTreatmentCall (key , featureFlagName , attributes , treatment , telemetry .Treatment , options .evaluationOptions ).Treatment
238+ }
239+
240+ func getOptions (optFns ... OptFn ) options {
241+ options := defaultOpts ()
242+ for _ , optFn := range optFns {
243+ optFn (& options )
244+ }
245+ return options
203246}
204247
205248// TreatmentWithConfig implements the main functionality of split. Retrieves the treatment of a specific feature flag
206249// with the corresponding configuration if it is present
207- func (c * SplitClient ) TreatmentWithConfig (key interface {}, featureFlagName string , attributes map [string ]interface {}) TreatmentResult {
208- return c .doTreatmentCall (key , featureFlagName , attributes , treatmentWithConfig , telemetry .TreatmentWithConfig )
250+ func (c * SplitClient ) TreatmentWithConfig (key interface {}, featureFlagName string , attributes map [string ]interface {}, optFns ... OptFn ) TreatmentResult {
251+ options := getOptions (optFns ... )
252+ return c .doTreatmentCall (key , featureFlagName , attributes , treatmentWithConfig , telemetry .TreatmentWithConfig , options .evaluationOptions )
209253}
210254
211255// Generates control treatments
@@ -224,7 +268,7 @@ func (c *SplitClient) generateControlTreatments(featureFlagNames []string, opera
224268 return treatments
225269}
226270
227- func (c * SplitClient ) processResult (result evaluator.Results , operation string , bucketingKey * string , matchingKey string , attributes map [string ]interface {}, metricsLabel string ) (t map [string ]TreatmentResult ) {
271+ func (c * SplitClient ) processResult (result evaluator.Results , operation string , bucketingKey * string , matchingKey string , attributes map [string ]interface {}, metricsLabel string , evaluationOptions * dtos. EvaluationOptions ) (t map [string ]TreatmentResult ) {
228272 var bulkImpressions []dtos.Impression
229273 treatments := make (map [string ]TreatmentResult )
230274 for feature , evaluation := range result .Evaluations {
@@ -234,7 +278,8 @@ func (c *SplitClient) processResult(result evaluator.Results, operation string,
234278 Config : nil ,
235279 }
236280 } else {
237- bulkImpressions = append (bulkImpressions , c .createImpression (feature , bucketingKey , evaluation .Label , matchingKey , evaluation .Treatment , evaluation .SplitChangeNumber , evaluation .ImpressionsDisabled ))
281+ bulkImpressions = append (bulkImpressions , c .createImpression (feature , bucketingKey , evaluation .Label , matchingKey , evaluation .Treatment , evaluation .SplitChangeNumber , evaluation .ImpressionsDisabled , serializeProperties (evaluationOptions )))
282+ //bulkImpressions = append(bulkImpressions, c.createImpression(feature, bucketingKey, evaluation.Label, matchingKey, evaluation.Treatment, evaluation.SplitChangeNumber, evaluation.ImpressionsDisabled, ""))
238283
239284 treatments [feature ] = TreatmentResult {
240285 Treatment : evaluation .Treatment ,
@@ -247,7 +292,7 @@ func (c *SplitClient) processResult(result evaluator.Results, operation string,
247292}
248293
249294// doTreatmentsCall retrieves treatments of an specific array of feature flag names with configurations object if it is present for a certain key and set of attributes
250- func (c * SplitClient ) doTreatmentsCall (key interface {}, featureFlagNames []string , attributes map [string ]interface {}, operation string , metricsLabel string ) (t map [string ]TreatmentResult ) {
295+ func (c * SplitClient ) doTreatmentsCall (key interface {}, featureFlagNames []string , attributes map [string ]interface {}, operation string , metricsLabel string , evaluationOptions * dtos. EvaluationOptions ) (t map [string ]TreatmentResult ) {
251296 // Set up a guard deferred function to recover if the SDK starts panicking
252297 defer func () {
253298 if r := recover (); r != nil {
@@ -280,11 +325,11 @@ func (c *SplitClient) doTreatmentsCall(key interface{}, featureFlagNames []strin
280325
281326 evaluationsResult := c .getEvaluationsResult (matchingKey , bucketingKey , filteredFeatures , attributes , operation )
282327
283- return c .processResult (evaluationsResult , operation , bucketingKey , matchingKey , attributes , metricsLabel )
328+ return c .processResult (evaluationsResult , operation , bucketingKey , matchingKey , attributes , metricsLabel , evaluationOptions )
284329}
285330
286331// doTreatmentsCallByFlagSets retrieves treatments of a specific array of feature flag names, that belong to flag sets, with configurations object if it is present for a certain key and set of attributes
287- func (c * SplitClient ) doTreatmentsCallByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}, operation string , metricsLabel string ) (t map [string ]TreatmentResult ) {
332+ func (c * SplitClient ) doTreatmentsCallByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}, operation string , metricsLabel string , evaluationOptions * dtos. EvaluationOptions ) (t map [string ]TreatmentResult ) {
288333 treatments := make (map [string ]TreatmentResult )
289334
290335 // Set up a guard deferred function to recover if the SDK starts panicking
@@ -312,15 +357,16 @@ func (c *SplitClient) doTreatmentsCallByFlagSets(key interface{}, flagSets []str
312357
313358 if c .isReady () {
314359 evaluationsResult := c .evaluator .EvaluateFeatureByFlagSets (matchingKey , bucketingKey , flagSets , attributes )
315- treatments = c .processResult (evaluationsResult , operation , bucketingKey , matchingKey , attributes , metricsLabel )
360+ treatments = c .processResult (evaluationsResult , operation , bucketingKey , matchingKey , attributes , metricsLabel , evaluationOptions )
316361 }
317362 return treatments
318363}
319364
320365// Treatments evaluates multiple feature flag names for a single user and set of attributes at once
321- func (c * SplitClient ) Treatments (key interface {}, featureFlagNames []string , attributes map [string ]interface {}) map [string ]string {
366+ func (c * SplitClient ) Treatments (key interface {}, featureFlagNames []string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]string {
367+ options := getOptions (optFns ... )
322368 treatmentsResult := map [string ]string {}
323- result := c .doTreatmentsCall (key , featureFlagNames , attributes , treatments , telemetry .Treatments )
369+ result := c .doTreatmentsCall (key , featureFlagNames , attributes , treatments , telemetry .Treatments , options . evaluationOptions )
324370 for feature , treatmentResult := range result {
325371 treatmentsResult [feature ] = treatmentResult .Treatment
326372 }
@@ -348,27 +394,29 @@ func (c *SplitClient) validateSets(flagSets []string) []string {
348394}
349395
350396// Treatments evaluate multiple feature flag names belonging to a flag set for a single user and a set of attributes at once
351- func (c * SplitClient ) TreatmentsByFlagSet (key interface {}, flagSet string , attributes map [string ]interface {}) map [string ]string {
397+ func (c * SplitClient ) TreatmentsByFlagSet (key interface {}, flagSet string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]string {
398+ options := getOptions (optFns ... )
352399 treatmentsResult := map [string ]string {}
353400 sets := c .validateSets ([]string {flagSet })
354401 if sets == nil {
355402 return treatmentsResult
356403 }
357- result := c .doTreatmentsCallByFlagSets (key , sets , attributes , treatmentsByFlagSet , telemetry .TreatmentsByFlagSet )
404+ result := c .doTreatmentsCallByFlagSets (key , sets , attributes , treatmentsByFlagSet , telemetry .TreatmentsByFlagSet , options . evaluationOptions )
358405 for feature , treatmentResult := range result {
359406 treatmentsResult [feature ] = treatmentResult .Treatment
360407 }
361408 return treatmentsResult
362409}
363410
364411// Treatments evaluate multiple feature flag names belonging to flag sets for a single user and a set of attributes at once
365- func (c * SplitClient ) TreatmentsByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}) map [string ]string {
412+ func (c * SplitClient ) TreatmentsByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]string {
413+ options := getOptions (optFns ... )
366414 treatmentsResult := map [string ]string {}
367415 flagSets = c .validateSets (flagSets )
368416 if flagSets == nil {
369417 return treatmentsResult
370418 }
371- result := c .doTreatmentsCallByFlagSets (key , flagSets , attributes , treatmentsByFlagSets , telemetry .TreatmentsByFlagSets )
419+ result := c .doTreatmentsCallByFlagSets (key , flagSets , attributes , treatmentsByFlagSets , telemetry .TreatmentsByFlagSets , options . evaluationOptions )
372420 for feature , treatmentResult := range result {
373421 treatmentsResult [feature ] = treatmentResult .Treatment
374422 }
@@ -388,28 +436,31 @@ func (c *SplitClient) filterSetsAreInConfig(flagSets []string) []string {
388436}
389437
390438// TreatmentsWithConfig evaluates multiple feature flag names for a single user and set of attributes at once and returns configurations
391- func (c * SplitClient ) TreatmentsWithConfig (key interface {}, featureFlagNames []string , attributes map [string ]interface {}) map [string ]TreatmentResult {
392- return c .doTreatmentsCall (key , featureFlagNames , attributes , treatmentsWithConfig , telemetry .TreatmentsWithConfig )
439+ func (c * SplitClient ) TreatmentsWithConfig (key interface {}, featureFlagNames []string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]TreatmentResult {
440+ options := getOptions (optFns ... )
441+ return c .doTreatmentsCall (key , featureFlagNames , attributes , treatmentsWithConfig , telemetry .TreatmentsWithConfig , options .evaluationOptions )
393442}
394443
395444// TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag set for a single user and set of attributes at once and returns configurations
396- func (c * SplitClient ) TreatmentsWithConfigByFlagSet (key interface {}, flagSet string , attributes map [string ]interface {}) map [string ]TreatmentResult {
445+ func (c * SplitClient ) TreatmentsWithConfigByFlagSet (key interface {}, flagSet string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]TreatmentResult {
446+ options := getOptions (optFns ... )
397447 treatmentsResult := make (map [string ]TreatmentResult )
398448 sets := c .validateSets ([]string {flagSet })
399449 if sets == nil {
400450 return treatmentsResult
401451 }
402- return c .doTreatmentsCallByFlagSets (key , sets , attributes , treatmentsWithConfigByFlagSet , telemetry .TreatmentsWithConfigByFlagSet )
452+ return c .doTreatmentsCallByFlagSets (key , sets , attributes , treatmentsWithConfigByFlagSet , telemetry .TreatmentsWithConfigByFlagSet , options . evaluationOptions )
403453}
404454
405455// TreatmentsWithConfigByFlagSet evaluates multiple feature flag names belonging to a flag sets for a single user and set of attributes at once and returns configurations
406- func (c * SplitClient ) TreatmentsWithConfigByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}) map [string ]TreatmentResult {
456+ func (c * SplitClient ) TreatmentsWithConfigByFlagSets (key interface {}, flagSets []string , attributes map [string ]interface {}, optFns ... OptFn ) map [string ]TreatmentResult {
457+ options := getOptions (optFns ... )
407458 treatmentsResult := make (map [string ]TreatmentResult )
408459 flagSets = c .validateSets (flagSets )
409460 if flagSets == nil {
410461 return treatmentsResult
411462 }
412- return c .doTreatmentsCallByFlagSets (key , flagSets , attributes , treatmentsWithConfigByFlagSets , telemetry .TreatmentsWithConfigByFlagSets )
463+ return c .doTreatmentsCallByFlagSets (key , flagSets , attributes , treatmentsWithConfigByFlagSets , telemetry .TreatmentsWithConfigByFlagSets , options . evaluationOptions )
413464}
414465
415466// isDestroyed returns true if the client has been destroyed
0 commit comments