1 package ldmodel 2 3 import ( 4 "github.com/launchdarkly/go-sdk-common/v3/ldattr" 5 "github.com/launchdarkly/go-sdk-common/v3/ldcontext" 6 "github.com/launchdarkly/go-sdk-common/v3/ldtime" 7 "github.com/launchdarkly/go-sdk-common/v3/ldvalue" 8 ) 9 10 // FeatureFlag describes an individual feature flag. 11 // 12 // The fields of this struct are exported for use by LaunchDarkly internal components. Application code 13 // should normally not reference FeatureFlag fields directly; flag data normally comes from LaunchDarkly 14 // SDK endpoints in JSON form and can be deserialized using the DataModelSerialization interface. 15 type FeatureFlag struct { 16 // Key is the unique string key of the feature flag. 17 Key string 18 // On is true if targeting is turned on for this flag. 19 // 20 // If On is false, the evaluator always uses OffVariation and ignores all other fields. 21 On bool 22 // Prerequisites is a list of feature flag conditions that are prerequisites for this flag. 23 // 24 // If any prerequisite is not met, the flag behaves as if targeting is turned off. 25 Prerequisites []Prerequisite 26 // Targets contains sets of individually targeted users for the default context kind (user). 27 // 28 // Targets take precedence over Rules: if a user is matched by any Target, the Rules are ignored. 29 // Targets are ignored if targeting is turned off. 30 Targets []Target 31 // ContextTargets contains sets of individually targeted users for specific context kinds. 32 // 33 // Targets take precedence over Rules: if a user is matched by any Target, the Rules are ignored. 34 // Targets are ignored if targeting is turned off. 35 ContextTargets []Target 36 // Rules is a list of rules that may match a user. 37 // 38 // If a user is matched by a Rule, all subsequent Rules in the list are skipped. Rules are ignored 39 // if targeting is turned off. 40 Rules []FlagRule 41 // Fallthrough defines the flag's behavior if targeting is turned on but the user is not matched 42 // by any Target or Rule. 43 Fallthrough VariationOrRollout 44 // OffVariation specifies the variation index to use if targeting is turned off. 45 // 46 // If this is undefined (ldvalue.OptionalInt{}), Evaluate returns undefined for the variation 47 // index and ldvalue.Null() for the value. 48 OffVariation ldvalue.OptionalInt 49 // Variations is the list of all allowable variations for this flag. The variation index in a 50 // Target or Rule is a zero-based index to this list. 51 Variations []ldvalue.Value 52 // ClientSideAvailability indicates whether a flag is available using each of the client-side 53 // authentication methods. 54 ClientSideAvailability ClientSideAvailability 55 // Salt is a randomized value assigned to this flag when it is created. 56 // 57 // The hash function used for calculating percentage rollouts uses this as a salt to ensure that 58 // rollouts are consistent within each flag but not predictable from one flag to another. 59 Salt string 60 // TrackEvents is used internally by the SDK analytics event system. 61 // 62 // This field is true if the current LaunchDarkly account has data export enabled, and has turned on 63 // the "send detailed event information for this flag" option for this flag. This tells the SDK to 64 // send full event data for each flag evaluation, rather than only aggregate data in a summary event. 65 // 66 // The go-server-sdk-evaluation package does not implement that behavior; it is only in the data 67 // model for use by the SDK. 68 TrackEvents bool 69 // TrackEventsFallthrough is used internally by the SDK analytics event system. 70 // 71 // This field is true if the current LaunchDarkly account has experimentation enabled, has associated 72 // this flag with an experiment, and has enabled "default rule" for the experiment. This tells the 73 // SDK to send full event data for any evaluation where this flag had targeting turned on but the 74 // user did not match any targets or rules. 75 // 76 // The go-server-sdk-evaluation package does not implement that behavior; it is only in the data 77 // model for use by the SDK. 78 TrackEventsFallthrough bool 79 // DebugEventsUntilDate is used internally by the SDK analytics event system. 80 // 81 // This field is non-zero if debugging for this flag has been turned on temporarily in the 82 // LaunchDarkly dashboard. Debugging always is for a limited time, so the field specifies a Unix 83 // millisecond timestamp when this mode should expire. Until then, the SDK will send full event data 84 // for each evaluation of this flag. 85 // 86 // The go-server-sdk-evaluation package does not implement that behavior; it is only in the data 87 // model for use by the SDK. 88 DebugEventsUntilDate ldtime.UnixMillisecondTime 89 // Version is an integer that is incremented by LaunchDarkly every time the configuration of the flag is 90 // changed. 91 Version int 92 // Deleted is true if this is not actually a feature flag but rather a placeholder (tombstone) for a 93 // deleted flag. This is only relevant in data store implementations. The SDK does not evaluate 94 // deleted flags. 95 Deleted bool 96 } 97 98 // FlagRule describes a single rule within a feature flag. 99 // 100 // A rule consists of a set of ANDed matching conditions (Clause) for a user, along with either a fixed 101 // variation or a set of rollout percentages to use if the user matches all of the clauses. 102 type FlagRule struct { 103 // VariationRollout properties for a FlagRule define what variation to return if the user matches 104 // this rule. 105 VariationOrRollout 106 // ID is a randomized identifier assigned to each rule when it is created. 107 // 108 // This is used to populate the RuleID property of ldreason.EvaluationReason. 109 ID string 110 // Clauses is a list of test conditions that make up the rule. These are ANDed: every Clause must 111 // match in order for the FlagRule to match. 112 Clauses []Clause 113 // TrackEvents is used internally by the SDK analytics event system. 114 // 115 // This field is true if the current LaunchDarkly account has experimentation enabled, has associated 116 // this flag with an experiment, and has enabled this rule for the experiment. This tells the SDK to 117 // send full event data for any evaluation that matches this rule. 118 // 119 // The go-server-sdk-evaluation package does not implement that behavior; it is only in the data 120 // model for use by the SDK. 121 TrackEvents bool 122 } 123 124 // RolloutKind describes whether a rollout is a simple percentage rollout or represents an experiment. Experiments have 125 // different behaviour for tracking and variation bucketing. 126 type RolloutKind string 127 128 const ( 129 // RolloutKindRollout represents a simple percentage rollout. This is the default rollout kind, and will be assumed if 130 // not otherwise specified. 131 RolloutKindRollout RolloutKind = "rollout" 132 // RolloutKindExperiment represents an experiment. Experiments have different behaviour for tracking and variation 133 // bucketing. 134 RolloutKindExperiment RolloutKind = "experiment" 135 ) 136 137 // VariationOrRollout desscribes either a fixed variation or a percentage rollout. 138 // 139 // There is a VariationOrRollout for every FlagRule, and also one in FeatureFlag.Fallthrough which is 140 // used if no rules match. 141 // 142 // Invariant: one of the variation or rollout must be non-nil. 143 type VariationOrRollout struct { 144 // Variation specifies the index of the variation to return. It is undefined (ldvalue.OptionalInt{}) 145 // if no specific variation is defined. 146 Variation ldvalue.OptionalInt 147 // Rollout specifies a percentage rollout to be used instead of a specific variation. A rollout is 148 // only defined if it has a non-empty Variations list. 149 Rollout Rollout 150 } 151 152 // Rollout describes how users will be bucketed into variations during a percentage rollout. 153 type Rollout struct { 154 // Kind specifies whether this rollout is a simple percentage rollout or represents an experiment. Experiments have 155 // different behaviour for tracking and variation bucketing. 156 Kind RolloutKind 157 // ContextKind is the context kind that this rollout will use to get any necessary context attributes. 158 // 159 // LaunchDarkly will normally always set this property, but if it is empty/omitted, it should be 160 // treated as ldcontext.DefaultKind. An empty string value here represents the property being unset 161 // (so it will be omitted in serialization). 162 ContextKind ldcontext.Kind 163 // Variations is a list of the variations in the percentage rollout and what percentage of users 164 // to include in each. 165 // 166 // The Weight values of all elements in this list should add up to 100000 (100%). If they do not, 167 // the last element in the list will behave as if it includes any leftover percentage (that is, if 168 // the weights are [1000, 1000, 1000] they will be treated as if they were [1000, 1000, 98000]). 169 Variations []WeightedVariation 170 // BucketBy specifies which user attribute should be used to distinguish between users in a rollout. 171 // This only works for simple rollouts; it is ignored for experiments. 172 // 173 // The default (when BucketBy is empty) is ldattr.KeyAttr, the user's primary key. If you wish to 174 // treat users with different keys as the same for rollout purposes as long as they have the same 175 // "country" attribute, you would set this to "country". 176 // 177 // Simple rollouts always take the user's "secondary key" attribute into account as well if the user 178 // has one. Experiments ignore the secondary key. 179 BucketBy ldattr.Ref 180 // Seed, if present, specifies the seed for the hashing algorithm this rollout will use to bucket users, so that 181 // rollouts with the same Seed will assign the same users to the same buckets. 182 // If unspecified, the seed will default to a combination of the flag key and flag-level Salt. 183 Seed ldvalue.OptionalInt 184 } 185 186 // IsExperiment returns whether this rollout represents an experiment. 187 func (r Rollout) IsExperiment() bool { 188 return r.Kind == RolloutKindExperiment 189 } 190 191 // Clause describes an individual clause within a FlagRule or SegmentRule. 192 type Clause struct { 193 // ContextKind is the context kind that this clause applies to. 194 // 195 // LaunchDarkly will normally always set this property, but if it is empty/omitted, it should be 196 // treated as ldcontext.DefaultKind. An empty string value here represents the property being unset (so 197 // it will be omitted in serialization). 198 // 199 // If the value of Attribute is "kind", then ContextKind is ignored because the nature of the context kind 200 // test is described in a richer way by Operator and Values. 201 ContextKind ldcontext.Kind 202 // Attribute specifies the context attribute that is being tested. 203 // 204 // This is required for all Operator types except SegmentMatch. If Op is SegmentMatch then Attribute 205 // is ignored (and will normally be an empty ldattr.Ref{}). 206 // 207 // If the context's value for this attribute is a JSON array, then the test specified in the Clause is 208 // repeated for each value in the array until a match is found or there are no more values. 209 Attribute ldattr.Ref 210 // Op specifies the type of test to perform. 211 Op Operator 212 // Values is a list of values to be compared to the user attribute. 213 // 214 // This is interpreted as an OR: if the user attribute matches any of these values with the specified 215 // operator, the Clause matches the user. 216 // 217 // In the special case where Op is OperatorSegmentMtach, there should only be a single Value, which 218 // must be a string: the key of the user segment. 219 // 220 // If the user does not have a value for the specified attribute, the Values are ignored and the 221 // Clause is always treated as a non-match. 222 Values []ldvalue.Value 223 // Negate is true if the specified Operator should be inverted. 224 // 225 // For instance, this would cause OperatorIn to mean "not equal" rather than "equal". Note that if no 226 // tests are performed for this Clause because the user does not have a value for the specified 227 // attribute, then Negate will not come into effect (the Clause will just be treated as a non-match). 228 Negate bool 229 // preprocessed is created by PreprocessFlag() to speed up clause evaluation in scenarios like 230 // regex matching. 231 preprocessed clausePreprocessedData 232 } 233 234 // WeightedVariation describes a fraction of users who will receive a specific variation. 235 type WeightedVariation struct { 236 // Variation is the index of the variation to be returned if the user is in this bucket. This is 237 // always a real variation index; it cannot be undefined. 238 Variation int 239 // Weight is the proportion of users who should go into this bucket, as an integer from 0 to 100000. 240 Weight int 241 // Untracked means that users allocated to this variation should not have tracking events sent. 242 Untracked bool 243 } 244 245 // Target describes a set of users who will receive a specific variation. 246 type Target struct { 247 // ContextKind is the context kind that this target list applies to. 248 // 249 // LaunchDarkly will normally always set this property, but if it is empty/omitted, it should be 250 // treated as ldcontext.DefaultKind. An empty string value here represents the property being unset (so 251 // it will be omitted in serialization). 252 ContextKind ldcontext.Kind 253 // Values is the set of user keys included in this Target. 254 Values []string 255 // Variation is the index of the variation to be returned if the user matches one of these keys. This 256 // is always a real variation index; it cannot be undefined. 257 Variation int 258 // preprocessed is created by PreprocessFlag() to speed up target matching. 259 preprocessed targetPreprocessedData 260 } 261 262 // Prerequisite describes a requirement that another feature flag return a specific variation. 263 // 264 // A prerequisite condition is met if the specified prerequisite flag has targeting turned on and 265 // returns the specified variation. 266 type Prerequisite struct { 267 // Key is the unique key of the feature flag to be evaluated as a prerequisite. 268 Key string 269 // Variation is the index of the variation that the prerequisite flag must return in order for 270 // the prerequisite condition to be met. If the prerequisite flag has targeting turned on, then 271 // the condition is not met even if the flag's OffVariation matches this value. This is always a 272 // real variation index; it cannot be undefined. 273 Variation int 274 } 275 276 // ClientSideAvailability describes whether a flag is available to client-side SDKs. 277 // 278 // This field can be used by a server-side client to determine whether to include an individual flag in 279 // bootstrapped set of flag data (see https://docs.launchdarkly.com/sdk/client-side/javascript#bootstrapping). 280 type ClientSideAvailability struct { 281 // UsingMobileKey indicates that this flag is available to clients using the mobile key for authorization 282 // (includes most desktop and mobile clients). 283 UsingMobileKey bool 284 // UsingEnvironmentID indicates that this flag is available to clients using the environment id to identify an 285 // environment (includes client-side javascript clients). 286 UsingEnvironmentID bool 287 // Explicit is true if, when serializing this flag, all of the ClientSideAvailability properties should 288 // be included. If it is false, then an older schema is used in which this object is entirely omitted, 289 // UsingEnvironmentID is stored in a deprecated property, and UsingMobileKey is assumed to be true. 290 // 291 // This field exists to ensure that flag representations remain consistent when sent and received 292 // even though the clientSideAvailability property may not be present in the JSON data. It is false 293 // if the flag was deserialized from an older JSON schema that did not include that property. 294 // 295 // Similarly, when deserializing a flag, if it used the older schema then Explicit will be false and 296 // UsingMobileKey will be true. 297 Explicit bool 298 } 299