public UnlaunchFeature Evaluate(FeatureFlag flag, UnlaunchUser user) { var evaluationReasonRef = new AtomicReference <string>(string.Empty); var variation = EvaluateInternal(flag, user, evaluationReasonRef); return(new UnlaunchFeature(flag.Key, variation.Key, variation.Properties, evaluationReasonRef.Get())); }
private static Variation GetVariationIfUserInAllowList(FeatureFlag flag, UnlaunchUser user) { foreach (var variation in flag.Variations) { if (variation.AllowList != null) { var allowList = new HashSet <string>(variation.AllowList.Split(',')); if (allowList.Contains(user.GetId())) { return(variation); } } } return(null); }
private bool CheckDependencies(FeatureFlag featureFlag, UnlaunchUser user) { var prerequisiteFlags = featureFlag.PrerequisiteFlags; if (prerequisiteFlags == null || !prerequisiteFlags.Any()) { return(true); } foreach (var flag in prerequisiteFlags.Keys) { var variation = EvaluateInternal(flag, user, null); if (variation.Key != prerequisiteFlags[flag].Key) { Logger.Info($"PREREQUISITE_FAILED,{flag.Key},{user.GetId()}"); return(false); } } return(true); }
private Variation EvaluateInternal(FeatureFlag flag, UnlaunchUser user, AtomicReference <string> evaluationReasonRef) { if (flag == null) { throw new ArgumentException("unlaunchFlag must not be null"); } if (user == null) { throw new ArgumentException("user must not be null"); } Variation variationToServe; var evaluationReason = string.Empty; if (!flag.Enabled) { Logger.Debug($"FLAG_DISABLED, {flag.Key}, OFF_VARIATION is served to user {user.GetId()}"); variationToServe = flag.OffVariation; evaluationReason = "Default Variation served. Because the flag is disabled."; } else if (!CheckDependencies(flag, user)) { Logger.Info($"PREREQUISITE_FAILED for flag {flag.Key}, OFF_VARIATION is served to user {user.GetId()}"); variationToServe = flag.OffVariation; evaluationReason = "Default Variation served. Because Pre-requisite failed."; } else if ((variationToServe = GetVariationIfUserInAllowList(flag, user)) != null) { Logger.Info($"USER_IN_TARGET_USER for flag {flag.Key}, VARIATION {variationToServe} is served to user {user.GetId()}"); evaluationReason = $"Target User rules matched for userId: {user.GetId()}"; } else { var bucketNumber = GetBucket(user.GetId(), flag.Key); foreach (var rule in flag.Rules) { if (!rule.IsDefault() && rule.Matches(user)) { variationToServe = GetVariationToServeByRule(rule, bucketNumber); Logger.Debug($"RULE_MATCHED for flag {flag.Key}, {variationToServe.Key} Target Rule is served to user {user.GetId()}"); evaluationReason = $"Targeting Rule (priority #{rule.GetPriority()}) matched."; break; } } // No variation matched by rule. Use the default rule. if (variationToServe == null) { var defaultRule = flag.DefaultRule; variationToServe = GetVariationToServeByRule(defaultRule, bucketNumber); Logger.Debug($"RULE_NOT_MATCHED for flag {flag.Key}, {variationToServe.Key} Default Rule is served to user {user.GetId()}"); evaluationReason = "Default Rule served. This is because the flag is Enabled and Target User and Targeting Rules didn't match."; } } evaluationReasonRef?.Set(evaluationReason); return(variationToServe); }
public bool Matches(UnlaunchUser user) { return(_conditions.All(condition => condition.Match(user))); }
public bool Match(UnlaunchUser user) { return(user.GetAttributes().ContainsKey(_attribute) && _operator.Apply(_value, user.GetAttributes()[_attribute], _type)); }