1
1
/****************************************************************************
2
- * Copyright 2020, Optimizely, Inc. and contributors *
2
+ * Copyright 2020-2021 , Optimizely, Inc. and contributors *
3
3
* *
4
4
* Licensed under the Apache License, Version 2.0 (the "License"); *
5
5
* you may not use this file except in compliance with the License. *
@@ -21,6 +21,7 @@ import (
21
21
"sync"
22
22
23
23
"github.com/optimizely/go-sdk/pkg/decide"
24
+ "github.com/optimizely/go-sdk/pkg/decision"
24
25
"github.com/optimizely/go-sdk/pkg/entities"
25
26
)
26
27
@@ -29,23 +30,24 @@ type OptimizelyUserContext struct {
29
30
UserID string `json:"userId"`
30
31
Attributes map [string ]interface {} `json:"attributes"`
31
32
32
- optimizely * OptimizelyClient
33
- mutex * sync.RWMutex
33
+ optimizely * OptimizelyClient
34
+ forcedDecisionService * decision.ForcedDecisionService
35
+ mutex * sync.RWMutex
34
36
}
35
37
36
38
// returns an instance of the optimizely user context.
37
- func newOptimizelyUserContext (optimizely * OptimizelyClient , userID string , attributes map [string ]interface {}) OptimizelyUserContext {
39
+ func newOptimizelyUserContext (optimizely * OptimizelyClient , userID string , attributes map [string ]interface {}, forcedDecisionService * decision. ForcedDecisionService ) OptimizelyUserContext {
38
40
// store a copy of the provided attributes so it isn't affected by changes made afterwards.
39
41
if attributes == nil {
40
42
attributes = map [string ]interface {}{}
41
43
}
42
44
attributesCopy := copyUserAttributes (attributes )
43
-
44
45
return OptimizelyUserContext {
45
- UserID : userID ,
46
- Attributes : attributesCopy ,
47
- optimizely : optimizely ,
48
- mutex : new (sync.RWMutex ),
46
+ UserID : userID ,
47
+ Attributes : attributesCopy ,
48
+ optimizely : optimizely ,
49
+ forcedDecisionService : forcedDecisionService ,
50
+ mutex : new (sync.RWMutex ),
49
51
}
50
52
}
51
53
@@ -66,6 +68,13 @@ func (o OptimizelyUserContext) GetUserAttributes() map[string]interface{} {
66
68
return copyUserAttributes (o .Attributes )
67
69
}
68
70
71
+ func (o OptimizelyUserContext ) getForcedDecisionService () * decision.ForcedDecisionService {
72
+ if o .forcedDecisionService != nil {
73
+ return o .forcedDecisionService .CreateCopy ()
74
+ }
75
+ return nil
76
+ }
77
+
69
78
// SetAttribute sets an attribute for a given key.
70
79
func (o * OptimizelyUserContext ) SetAttribute (key string , value interface {}) {
71
80
o .mutex .Lock ()
@@ -80,21 +89,21 @@ func (o *OptimizelyUserContext) SetAttribute(key string, value interface{}) {
80
89
// all data required to deliver the flag or experiment.
81
90
func (o * OptimizelyUserContext ) Decide (key string , options []decide.OptimizelyDecideOptions ) OptimizelyDecision {
82
91
// use a copy of the user context so that any changes to the original context are not reflected inside the decision
83
- userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes ())
92
+ userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes (), o . getForcedDecisionService () )
84
93
return o .optimizely .decide (userContextCopy , key , convertDecideOptions (options ))
85
94
}
86
95
87
96
// DecideAll returns a key-map of decision results for all active flag keys with options.
88
97
func (o * OptimizelyUserContext ) DecideAll (options []decide.OptimizelyDecideOptions ) map [string ]OptimizelyDecision {
89
98
// use a copy of the user context so that any changes to the original context are not reflected inside the decision
90
- userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes ())
99
+ userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes (), o . getForcedDecisionService () )
91
100
return o .optimizely .decideAll (userContextCopy , convertDecideOptions (options ))
92
101
}
93
102
94
103
// DecideForKeys returns a key-map of decision results for multiple flag keys and options.
95
104
func (o * OptimizelyUserContext ) DecideForKeys (keys []string , options []decide.OptimizelyDecideOptions ) map [string ]OptimizelyDecision {
96
105
// use a copy of the user context so that any changes to the original context are not reflected inside the decision
97
- userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes ())
106
+ userContextCopy := newOptimizelyUserContext (o .GetOptimizely (), o .GetUserID (), o .GetUserAttributes (), o . getForcedDecisionService () )
98
107
return o .optimizely .decideForKeys (userContextCopy , keys , convertDecideOptions (options ))
99
108
}
100
109
@@ -108,6 +117,55 @@ func (o *OptimizelyUserContext) TrackEvent(eventKey string, eventTags map[string
108
117
return o .optimizely .Track (eventKey , userContext , eventTags )
109
118
}
110
119
120
+ // SetForcedDecision sets the forced decision (variation key) for a given flag and an optional rule.
121
+ // returns true if the forced decision has been set successfully.
122
+ func (o * OptimizelyUserContext ) SetForcedDecision (flagKey , ruleKey , variationKey string ) bool {
123
+ if _ , err := o .optimizely .getProjectConfig (); err != nil {
124
+ o .optimizely .logger .Error ("Optimizely instance is not valid, failing setForcedDecision call." , err )
125
+ return false
126
+ }
127
+ if o .forcedDecisionService == nil {
128
+ o .forcedDecisionService = decision .NewForcedDecisionService (o .GetUserID ())
129
+ }
130
+ return o .forcedDecisionService .SetForcedDecision (flagKey , ruleKey , variationKey )
131
+ }
132
+
133
+ // GetForcedDecision returns the forced decision for a given flag and an optional rule
134
+ func (o * OptimizelyUserContext ) GetForcedDecision (flagKey , ruleKey string ) string {
135
+ if _ , err := o .optimizely .getProjectConfig (); err != nil {
136
+ o .optimizely .logger .Error ("Optimizely instance is not valid, failing getForcedDecision call." , err )
137
+ return ""
138
+ }
139
+ if o .forcedDecisionService == nil {
140
+ return ""
141
+ }
142
+ return o .forcedDecisionService .GetForcedDecision (flagKey , ruleKey )
143
+ }
144
+
145
+ // RemoveForcedDecision removes the forced decision for a given flag and an optional rule.
146
+ func (o * OptimizelyUserContext ) RemoveForcedDecision (flagKey , ruleKey string ) bool {
147
+ if _ , err := o .optimizely .getProjectConfig (); err != nil {
148
+ o .optimizely .logger .Error ("Optimizely instance is not valid, failing removeForcedDecision call." , err )
149
+ return false
150
+ }
151
+ if o .forcedDecisionService == nil {
152
+ return false
153
+ }
154
+ return o .forcedDecisionService .RemoveForcedDecision (flagKey , ruleKey )
155
+ }
156
+
157
+ // RemoveAllForcedDecisions removes all forced decisions bound to this user context.
158
+ func (o * OptimizelyUserContext ) RemoveAllForcedDecisions () bool {
159
+ if _ , err := o .optimizely .getProjectConfig (); err != nil {
160
+ o .optimizely .logger .Error ("Optimizely instance is not valid, failing removeForcedDecision call." , err )
161
+ return false
162
+ }
163
+ if o .forcedDecisionService == nil {
164
+ return true
165
+ }
166
+ return o .forcedDecisionService .RemoveAllForcedDecisions ()
167
+ }
168
+
111
169
func copyUserAttributes (attributes map [string ]interface {}) (attributesCopy map [string ]interface {}) {
112
170
if attributes != nil {
113
171
attributesCopy = make (map [string ]interface {})
0 commit comments