internal static FullDataSet <ItemDescriptor> ParseFullDataset(ref JReader r) { try { var dataBuilder = ImmutableList.CreateBuilder <KeyValuePair <DataKind, KeyedItems <ItemDescriptor> > >(); for (var topLevelObj = r.Object(); topLevelObj.Next(ref r);) { var name = topLevelObj.Name.ToString(); var kind = DataModel.AllDataKinds.FirstOrDefault(k => name == PathNameForKind(k)); if (kind == null) { continue; } var itemsBuilder = ImmutableList.CreateBuilder <KeyValuePair <string, ItemDescriptor> >(); for (var itemsObj = r.Object(); itemsObj.Next(ref r);) { var key = itemsObj.Name.ToString(); var item = kind.DeserializeFromJReader(ref r); itemsBuilder.Add(new KeyValuePair <string, ItemDescriptor>(key, item)); } dataBuilder.Add(new KeyValuePair <DataKind, KeyedItems <ItemDescriptor> >(kind, new KeyedItems <ItemDescriptor>(itemsBuilder.ToImmutable()))); } return(new FullDataSet <ItemDescriptor>(dataBuilder.ToImmutable())); } catch (Exception e) { throw r.TranslateException(e); } }
public object ReadJson(ref JReader reader) { var valid = true; var flags = new Dictionary <string, FlagState>(); for (var topLevelObj = reader.Object(); topLevelObj.Next(ref reader);) { var key = topLevelObj.Name.ToString(); switch (key) { case "$valid": valid = reader.Bool(); break; case "$flagsState": for (var flagsObj = reader.Object(); flagsObj.Next(ref reader);) { var subKey = flagsObj.Name.ToString(); var flag = flags.ContainsKey(subKey) ? flags[subKey] : new FlagState(); for (var metaObj = reader.Object(); metaObj.Next(ref reader);) { switch (metaObj.Name.ToString()) { case "variation": flag.Variation = reader.IntOrNull(); break; case "version": flag.Version = reader.IntOrNull(); break; case "trackEvents": flag.TrackEvents = reader.Bool(); break; case "debugEventsUntilDate": var n = reader.LongOrNull(); flag.DebugEventsUntilDate = n.HasValue ? UnixMillisecondTime.OfMillis(n.Value) : (UnixMillisecondTime?)null; break; case "reason": flag.Reason = EvaluationReasonConverter.ReadJsonNullableValue(ref reader); break; } } flags[subKey] = flag; } break; default: var flagForValue = flags.ContainsKey(key) ? flags[key] : new FlagState(); flagForValue.Value = LdValueConverter.ReadJsonValue(ref reader); flags[key] = flagForValue; break; } } return(new FeatureFlagsState(valid, flags)); }
internal static SegmentRule ReadSegmentRule(ref JReader reader) { ImmutableList <Clause> clauses = null; int? weight = null; UserAttribute?bucketBy = null; for (var obj = reader.Object(); obj.Next(ref reader);) { switch (obj.Name) { case var n when n == "clauses": clauses = SerializationHelpers.ReadClauses(ref reader); break; case var n when n == "weight": weight = reader.IntOrNull(); break; case var n when n == "bucketBy": var s = reader.StringOrNull(); bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s); break; } } return(new SegmentRule(clauses, weight, bucketBy)); }
internal static FlagRule ReadFlagRule(ref JReader r) { string id = null; int? variation = null; Rollout?rollout = null; ImmutableList <Clause> clauses = null; bool trackEvents = false; for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name) { case var n when n == "id": id = r.StringOrNull(); break; case var n when n == "variation": variation = r.IntOrNull(); break; case var n when n == "rollout": rollout = ReadRollout(ref r); break; case var n when n == "clauses": clauses = SerializationHelpers.ReadClauses(ref r); break; case var n when n == "trackEvents": trackEvents = r.Bool(); break; } } return(new FlagRule(variation, rollout, id, clauses, trackEvents)); }
public object ReadJson(ref JReader reader) { string key = null; int version = 0; bool deleted = false; ImmutableList <string> included = null, excluded = null; ImmutableList <SegmentRule> rules = null; string salt = null; for (var obj = reader.Object().WithRequiredProperties(_requiredProperties); obj.Next(ref reader);) { switch (obj.Name) { case var n when n == "key": key = reader.String(); break; case var n when n == "version": version = reader.Int(); break; case var n when n == "deleted": deleted = reader.Bool(); break; case var n when n == "included": included = SerializationHelpers.ReadStrings(ref reader); break; case var n when n == "excluded": excluded = SerializationHelpers.ReadStrings(ref reader); break; case var n when n == "rules": var rulesBuilder = ImmutableList.CreateBuilder <SegmentRule>(); for (var rulesArr = reader.Array(); rulesArr.Next(ref reader);) { rulesBuilder.Add(ReadSegmentRule(ref reader)); } rules = rulesBuilder.ToImmutable(); break; case var n when n == "salt": salt = reader.StringOrNull(); break; } } if (key is null && !deleted) { throw new RequiredPropertyException("key", 0); } return(new Segment(key, version, deleted, included, excluded, rules, salt)); }
private static FullDataSet <ItemDescriptor> ParseJson(ref JReader r, int version) { var flagsBuilder = ImmutableList.CreateBuilder <KeyValuePair <string, ItemDescriptor> >(); var segmentsBuilder = ImmutableList.CreateBuilder <KeyValuePair <string, ItemDescriptor> >(); for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name.ToString()) { case "flags": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { var key = subObj.Name.ToString(); var flag = FeatureFlagSerialization.Instance.ReadJson(ref r) as FeatureFlag; flagsBuilder.Add(new KeyValuePair <string, ItemDescriptor>(key, new ItemDescriptor(version, FlagWithVersion(flag, version)))); } break; case "flagValues": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { var key = subObj.Name.ToString(); var value = LdValueConverter.ReadJsonValue(ref r); var flag = FlagWithValue(key, value, version); flagsBuilder.Add(new KeyValuePair <string, ItemDescriptor>(key, new ItemDescriptor(version, flag))); } break; case "segments": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { var key = subObj.Name.ToString(); var segment = SegmentSerialization.Instance.ReadJson(ref r) as Segment; segmentsBuilder.Add(new KeyValuePair <string, ItemDescriptor>(key, new ItemDescriptor(version, SegmentWithVersion(segment, version)))); } break; } } return(new FullDataSet <ItemDescriptor>(ImmutableList.Create <KeyValuePair <DataKind, KeyedItems <ItemDescriptor> > >( new KeyValuePair <DataKind, KeyedItems <ItemDescriptor> >(DataModel.Features, new KeyedItems <ItemDescriptor>(flagsBuilder.ToImmutable())), new KeyValuePair <DataKind, KeyedItems <ItemDescriptor> >(DataModel.Segments, new KeyedItems <ItemDescriptor>(segmentsBuilder.ToImmutable())) ))); }
internal static Rollout?ReadRollout(ref JReader r) { ImmutableList <WeightedVariation> variations = null; UserAttribute?bucketBy = null; var obj = r.ObjectOrNull(); if (!obj.IsDefined) { return(null); } while (obj.Next(ref r)) { switch (obj.Name) { case var n when n == "variations": var listBuilder = ImmutableList.CreateBuilder <WeightedVariation>(); for (var arr = r.ArrayOrNull(); arr.Next(ref r);) { int variation = 0, weight = 0; for (var wvObj = r.Object(); wvObj.Next(ref r);) { switch (wvObj.Name) { case var nn when nn == "variation": variation = r.Int(); break; case var nn when nn == "weight": weight = r.Int(); break; } } listBuilder.Add(new WeightedVariation(variation, weight)); } variations = listBuilder.ToImmutable(); break; case var n when n == "bucketBy": var s = r.StringOrNull(); bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s); break; } } return(new Rollout(variations, bucketBy)); }
internal static Target ReadTarget(ref JReader r) { ImmutableList <string> values = null; int variation = 0; for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name) { case var n when n == "values": values = SerializationHelpers.ReadStrings(ref r); break; case var n when n == "variation": variation = r.Int(); break; } } return(new Target(values, variation)); }
internal static Prerequisite ReadPrerequisite(ref JReader r) { string key = null; int variation = 0; for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name) { case var n when n == "key": key = r.String(); break; case var n when n == "variation": variation = r.Int(); break; } } return(new Prerequisite(key, variation)); }
private static FlagFileData ParseJson(ref JReader r) { var ret = new FlagFileData { Flags = new Dictionary <string, FeatureFlag>(), FlagValues = new Dictionary <string, LdValue>(), Segments = new Dictionary <string, Segment>() }; for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name.ToString()) { case "flags": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { ret.Flags[subObj.Name.ToString()] = FeatureFlagSerialization.Instance.ReadJson(ref r) as FeatureFlag; } break; case "flagValues": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { ret.FlagValues[subObj.Name.ToString()] = LdValueConverter.ReadJsonValue(ref r); } break; case "segments": for (var subObj = r.ObjectOrNull(); subObj.Next(ref r);) { ret.Segments[subObj.Name.ToString()] = SegmentSerialization.Instance.ReadJson(ref r) as Segment; } break; } } return(ret); }
internal static ImmutableList <Clause> ReadClauses(ref JReader r) { var builder = ImmutableList.CreateBuilder <Clause>(); for (var arr = r.ArrayOrNull(); arr.Next(ref r);) { UserAttribute attribute = new UserAttribute(); Operator op = null; ImmutableList <LdValue> values = null; bool negate = false; for (var obj = r.Object(); obj.Next(ref r);) { switch (obj.Name) { case var n when n == "attribute": attribute = UserAttribute.ForName(r.String()); break; case var n when n == "op": op = Operator.ForName(r.String()); // Operator.ForName never returns null - unrecognized operators return a stub object break; case var n when n == "values": values = ReadValues(ref r); break; case var n when n == "negate": negate = r.Bool(); break; } } builder.Add(new Clause(attribute, op, values, negate)); } return(builder.ToImmutable()); }
internal static Rollout?ReadRollout(ref JReader r) { ImmutableList <WeightedVariation> variations = null; UserAttribute?bucketBy = null; RolloutKind kind = RolloutKind.Rollout; int? seed = null; var obj = r.ObjectOrNull(); if (!obj.IsDefined) { return(null); } while (obj.Next(ref r)) { switch (obj.Name) { case var n when n == "variations": var listBuilder = ImmutableList.CreateBuilder <WeightedVariation>(); for (var arr = r.ArrayOrNull(); arr.Next(ref r);) { int variation = 0, weight = 0; bool untracked = false; for (var wvObj = r.Object(); wvObj.Next(ref r);) { switch (wvObj.Name) { case var nn when nn == "variation": variation = r.Int(); break; case var nn when nn == "weight": weight = r.Int(); break; case var nn when nn == "untracked": untracked = r.Bool(); break; } } listBuilder.Add(new WeightedVariation(variation, weight, untracked)); } variations = listBuilder.ToImmutable(); break; case var n when n == "bucketBy": var s = r.StringOrNull(); bucketBy = s is null ? (UserAttribute?)null : UserAttribute.ForName(s); break; case var n when n == "kind": var kindStr = r.StringOrNull(); kind = "experiment".Equals(kindStr) ? RolloutKind.Experiment : RolloutKind.Rollout; break; case var n when n == "seed": seed = r.IntOrNull(); break; } } return(new Rollout(kind, seed, variations, bucketBy)); }
public object ReadJson(ref JReader reader) { string key = null; int version = 0; bool deleted = false; bool on = false; ImmutableList <Prerequisite> prerequisites = null; ImmutableList <Target> targets = null; ImmutableList <FlagRule> rules = null; string salt = null; VariationOrRollout fallthrough = new VariationOrRollout(); int?offVariation = null; ImmutableList <LdValue> variations = null; bool trackEvents = false, trackEventsFallthrough = false; UnixMillisecondTime?debugEventsUntilDate = null; bool clientSide = false; for (var obj = reader.Object().WithRequiredProperties(_requiredProperties); obj.Next(ref reader);) { switch (obj.Name) { case var n when n == "key": key = reader.String(); break; case var n when n == "version": version = reader.Int(); break; case var n when n == "deleted": deleted = reader.Bool(); break; case var n when n == "on": on = reader.Bool(); break; case var n when n == "prerequisites": var prereqsBuilder = ImmutableList.CreateBuilder <Prerequisite>(); for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);) { prereqsBuilder.Add(ReadPrerequisite(ref reader)); } prerequisites = prereqsBuilder.ToImmutable(); break; case var n when n == "targets": var targetsBuilder = ImmutableList.CreateBuilder <Target>(); for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);) { targetsBuilder.Add(ReadTarget(ref reader)); } targets = targetsBuilder.ToImmutable(); break; case var n when n == "rules": var rulesBuilder = ImmutableList.CreateBuilder <FlagRule>(); for (var arr = reader.ArrayOrNull(); arr.Next(ref reader);) { rulesBuilder.Add(ReadFlagRule(ref reader)); } rules = rulesBuilder.ToImmutable(); break; case var n when n == "fallthrough": fallthrough = ReadVariationOrRollout(ref reader); break; case var n when n == "offVariation": offVariation = reader.IntOrNull(); break; case var n when n == "variations": variations = SerializationHelpers.ReadValues(ref reader); break; case var n when n == "salt": salt = reader.StringOrNull(); break; case var n when n == "trackEvents": trackEvents = reader.Bool(); break; case var n when n == "trackEventsFallthrough": trackEventsFallthrough = reader.Bool(); break; case var n when n == "debugEventsUntilDate": var dt = reader.LongOrNull(); debugEventsUntilDate = dt.HasValue ? UnixMillisecondTime.OfMillis(dt.Value) : (UnixMillisecondTime?)null; break; case var n when n == "clientSide": clientSide = reader.Bool(); break; } } if (key is null && !deleted) { throw new RequiredPropertyException("key", 0); } return(new FeatureFlag(key, version, deleted, on, prerequisites, targets, rules, fallthrough, offVariation, variations, salt, trackEvents, trackEventsFallthrough, debugEventsUntilDate, clientSide)); }
public static FeatureFlag ReadJsonValue(ref JReader reader) { LdValue value = LdValue.Null; int version = 0; int? flagVersion = null; int? variation = null; EvaluationReason? reason = null; bool trackEvents = false; bool trackReason = false; UnixMillisecondTime?debugEventsUntilDate = null; for (var or = reader.Object(); or.Next(ref reader);) { // The use of multiple == tests instead of switch allows for a slight optimization on // some platforms where it wouldn't always need to allocate a string for or.Name. See: // https://github.com/launchdarkly/dotnet-jsonstream/blob/master/src/LaunchDarkly.JsonStream/PropertyNameToken.cs var name = or.Name; if (name == "value") { value = LdJsonConverters.LdValueConverter.ReadJsonValue(ref reader); } else if (name == "version") { version = reader.Int(); } else if (name == "flagVersion") { flagVersion = reader.IntOrNull(); } else if (name == "variation") { variation = reader.IntOrNull(); } else if (name == "reason") { reason = LdJsonConverters.EvaluationReasonConverter.ReadJsonNullableValue(ref reader); } else if (name == "trackEvents") { trackEvents = reader.Bool(); } else if (name == "trackReason") { trackReason = reader.Bool(); } else if (name == "debugEventsUntilDate") { var dt = reader.LongOrNull(); if (dt.HasValue) { debugEventsUntilDate = UnixMillisecondTime.OfMillis(dt.Value); } } } return(new FeatureFlag( value, variation, reason, version, flagVersion, trackEvents, trackReason, debugEventsUntilDate )); }
private static EvaluationReason?ReadJsonInternal(ref JReader reader, bool nullable) { var obj = (nullable ? reader.ObjectOrNull() : reader.Object()) .WithRequiredProperties(_requiredProperties); if (!obj.IsDefined) { return(null); } try { EvaluationReasonKind kind = EvaluationReasonKind.Error; int? ruleIndex = null; string ruleId = null; string prerequisiteKey = null; EvaluationErrorKind?errorKind = null; bool inExperiment = false; BigSegmentsStatus?bigSegmentsStatus = null; while (obj.Next(ref reader)) { var name = obj.Name; if (name == "kind") { try { kind = EvaluationReasonKindConverter.FromIdentifier(reader.String()); } catch (ArgumentException) { throw new SyntaxException("unsupported value for \"kind\"", 0); } } else if (name == "ruleIndex") { ruleIndex = reader.Int(); } else if (name == "ruleId") { ruleId = reader.String(); } else if (name == "prerequisiteKey") { prerequisiteKey = reader.String(); } else if (name == "errorKind") { try { errorKind = EvaluationErrorKindConverter.FromIdentifier(reader.String()); } catch (ArgumentException) { throw new SyntaxException("unsupported value for \"errorKind\"", 0); } } else if (name == "inExperiment") { inExperiment = reader.Bool(); } else if (name == "bigSegmentsStatus") { try { bigSegmentsStatus = BigSegmentsStatusConverter.FromIdentifier(reader.String()); } catch (ArgumentException) { throw new SyntaxException("unsupported value for \"bigSegmentsStatus\"", 0); } } } EvaluationReason reason; switch (kind) // it's guaranteed to have a value, otherwise there'd be a required property error above { case EvaluationReasonKind.Off: reason = EvaluationReason.OffReason; break; case EvaluationReasonKind.Fallthrough: reason = EvaluationReason.FallthroughReason; break; case EvaluationReasonKind.TargetMatch: reason = EvaluationReason.TargetMatchReason; break; case EvaluationReasonKind.RuleMatch: reason = EvaluationReason.RuleMatchReason(ruleIndex ?? 0, ruleId); break; case EvaluationReasonKind.PrerequisiteFailed: reason = EvaluationReason.PrerequisiteFailedReason(prerequisiteKey); break; case EvaluationReasonKind.Error: reason = EvaluationReason.ErrorReason(errorKind ?? EvaluationErrorKind.Exception); break; default: return(null); } if (inExperiment) { reason = reason.WithInExperiment(true); } if (bigSegmentsStatus.HasValue) { reason = reason.WithBigSegmentsStatus(bigSegmentsStatus); } return(reason); } catch (Exception e) { throw reader.TranslateException(e); } }