public void DebugModeExpiresBasedOnServerTimeIfServerTimeIsLaterThanClientTime()
        {
            // Pick a server time that is somewhat ahead of the client time
            var serverTime = DateTime.Now.Add(TimeSpan.FromSeconds(20));

            var mockSender = MakeMockSender();
            var captured   = EventCapture.From(mockSender,
                                               new EventSenderResult(DeliveryStatus.Succeeded, serverTime));

            using (var ep = MakeProcessor(_config, mockSender))
            {
                // Send and flush an event we don't care about, just to set the last server time
                RecordIdentify(ep, _fixedTimestamp, User.WithKey("otherUser"));
                FlushAndWait(ep);
                captured.Events.Clear();

                // Now send an event with debug mode on, with a "debug until" time that is further in
                // the future than the client time, but in the past compared to the server.
                var flag = BasicFlag;
                flag.DebugEventsUntilDate = UnixMillisecondTime.FromDateTime(serverTime).PlusMillis(-1000);
                RecordEval(ep, flag, BasicEval);
                FlushAndWait(ep);

                // Should get a summary event only, not a full feature event
                Assert.Collection(captured.Events,
                                  item => CheckIndexEvent(item, BasicEval.Timestamp, _userJson),
                                  item => CheckSummaryEvent(item));
            }
        }
Exemplo n.º 2
0
        public void VariationDetailSendsFeatureEventWithReasonForValidFlag()
        {
            var flag = new FeatureFlagBuilder().Value(LdValue.Of("a")).Variation(1).Version(1000)
                       .TrackEvents(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(2000))
                       .Reason(EvaluationReason.OffReason).Build();

            _testData.Update(_testData.Flag("flag").PreconfiguredFlag(flag));
            using (LdClient client = MakeClient(user))
            {
                EvaluationDetail <string> result = client.StringVariationDetail("flag", "b");
                Assert.Equal("a", result.Value);
                Assert.Equal(EvaluationReason.OffReason, result.Reason);
                Assert.Collection(eventProcessor.Events,
                                  e => CheckIdentifyEvent(e, user),
                                  e => {
                    EvaluationEvent fe = Assert.IsType <EvaluationEvent>(e);
                    Assert.Equal("flag", fe.FlagKey);
                    Assert.Equal("a", fe.Value.AsString);
                    Assert.Equal(1, fe.Variation);
                    Assert.Equal(1000, fe.FlagVersion);
                    Assert.Equal("b", fe.Default.AsString);
                    Assert.True(fe.TrackEvents);
                    Assert.Equal(UnixMillisecondTime.OfMillis(2000), fe.DebugEventsUntilDate);
                    Assert.Equal(EvaluationReason.OffReason, fe.Reason);
                    Assert.NotEqual(0, fe.Timestamp.Value);
                });
            }
        }
Exemplo n.º 3
0
        public void SerializeFlagWithAllProperties()
        {
            var flag1 = new FeatureFlagBuilder()
                        .Version(1)
                        .Value(LdValue.Of(false))
                        .Variation(2)
                        .FlagVersion(3)
                        .Reason(EvaluationReason.OffReason)
                        .TrackEvents(true)
                        .DebugEventsUntilDate(UnixMillisecondTime.OfMillis(1234))
                        .Build();

            AssertJsonEqual(@"{""version"":1,""value"":false,""variation"":2,""flagVersion"":3," +
                            @"""reason"":{""kind"":""OFF""},""trackEvents"":true,""debugEventsUntilDate"":1234}",
                            DataModelSerialization.SerializeFlag(flag1));

            // make sure we're treating trackReason separately from trackEvents
            var flag2 = new FeatureFlagBuilder()
                        .Version(1)
                        .Value(LdValue.Of(false))
                        .Reason(EvaluationReason.OffReason)
                        .Variation(2)
                        .FlagVersion(3)
                        .TrackReason(true)
                        .Build();

            AssertJsonEqual(@"{""version"":1,""value"":false,""variation"":2,""flagVersion"":3," +
                            @"""reason"":{""kind"":""OFF""},""trackReason"":true}",
                            DataModelSerialization.SerializeFlag(flag2));
        }
        public void AllFlagsStateReturnsStateWithReasons()
        {
            var flag1 = new FeatureFlagBuilder("key1").Version(100)
                        .OffVariation(0).Variations(LdValue.Of("value1"))
                        .Build();
            var flag2 = new FeatureFlagBuilder("key2").Version(200)
                        .OffVariation(1).Variations(LdValue.Of("x"), LdValue.Of("value2"))
                        .TrackEvents(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(1000))
                        .Build();

            testData.UsePreconfiguredFlag(flag1);
            testData.UsePreconfiguredFlag(flag2);

            var state = client.AllFlagsState(user, FlagsStateOption.WithReasons);

            Assert.True(state.Valid);

            var expectedString = @"{""key1"":""value1"",""key2"":""value2"",
                ""$flagsState"":{
                  ""key1"":{
                    ""variation"":0,""version"":100,""reason"":{""kind"":""OFF""}
                  },""key2"":{
                    ""variation"":1,""version"":200,""reason"":{""kind"":""OFF""},""trackEvents"":true,""debugEventsUntilDate"":1000
                  }
                },
                ""$valid"":true
            }";
            var actualString   = LdJsonSerialization.SerializeObject(state);

            AssertHelpers.JsonEqual(expectedString, actualString);
        }
Exemplo n.º 5
0
        private async Task FlushEventsAsync(FlushPayload payload)
        {
            EventOutputFormatter formatter = new EventOutputFormatter(_config);
            string jsonEvents;
            int    eventCount;

            try
            {
                jsonEvents = formatter.SerializeOutputEvents(payload.Events, payload.Summary, out eventCount);
            }
            catch (Exception e)
            {
                LogHelpers.LogException(_logger, "Error preparing events, will not send", e);
                return;
            }

            var result = await _eventSender.SendEventDataAsync(EventDataKind.AnalyticsEvents,
                                                               jsonEvents, eventCount);

            if (result.Status == DeliveryStatus.FailedAndMustShutDown)
            {
                _disabled = true;
            }
            if (result.TimeFromServer.HasValue)
            {
                Interlocked.Exchange(ref _lastKnownPastTime,
                                     UnixMillisecondTime.FromDateTime(result.TimeFromServer.Value).Value);
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Parses the user index from a JSON representation. If the JSON string is null or
        /// empty, it returns an empty user index.
        /// </summary>
        /// <param name="json">the JSON representation</param>
        /// <returns>the parsed data</returns>
        /// <exception cref="FormatException">if the JSON is malformed</exception>
        public static UserIndex Deserialize(string json)
        {
            if (string.IsNullOrEmpty(json))
            {
                return(new UserIndex());
            }
            var builder = ImmutableList.CreateBuilder <IndexEntry>();

            try
            {
                var r = JReader.FromString(json);
                for (var ar0 = r.Array(); ar0.Next(ref r);)
                {
                    var ar1 = r.Array();
                    if (ar1.Next(ref r))
                    {
                        var userId = r.String();
                        if (ar1.Next(ref r))
                        {
                            var timeMillis = r.Long();
                            builder.Add(new IndexEntry {
                                UserId = userId, Timestamp = UnixMillisecondTime.OfMillis(timeMillis)
                            });
                            ar1.Next(ref r);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                throw new FormatException("invalid stored user index", e);
            }
            return(new UserIndex(builder.ToImmutable()));
        }
Exemplo n.º 7
0
        public void SummarizeEventIncrementsCounters()
        {
            var     time = UnixMillisecondTime.OfMillis(1000);
            string  flag1Key = "flag1", flag2Key = "flag2", unknownFlagKey = "badkey";
            int     flag1Version = 100, flag2Version = 200;
            int     variation1 = 1, variation2 = 2;
            LdValue value1 = LdValue.Of("value1"), value2 = LdValue.Of("value2"),
                    value99 = LdValue.Of("value99"),
                    default1 = LdValue.Of("default1"), default2 = LdValue.Of("default2"),
                    default3   = LdValue.Of("default3");
            EventSummarizer es = new EventSummarizer();

            es.SummarizeEvent(time, flag1Key, flag1Version, variation1, value1, default1);
            es.SummarizeEvent(time, flag1Key, flag1Version, variation2, value2, default1);
            es.SummarizeEvent(time, flag2Key, flag2Version, variation1, value99, default2);
            es.SummarizeEvent(time, flag1Key, flag1Version, variation1, value1, default1);
            es.SummarizeEvent(time, unknownFlagKey, null, null, default3, default3);
            EventSummary data = es.Snapshot();

            Dictionary <EventsCounterKey, EventsCounterValue> expected = new Dictionary <EventsCounterKey, EventsCounterValue>();

            Assert.Equal(new EventsCounterValue(2, value1, default1),
                         data.Counters[new EventsCounterKey(flag1Key, flag1Version, variation1)]);
            Assert.Equal(new EventsCounterValue(1, value2, default1),
                         data.Counters[new EventsCounterKey(flag1Key, flag1Version, variation2)]);
            Assert.Equal(new EventsCounterValue(1, value99, default2),
                         data.Counters[new EventsCounterKey(flag2Key, flag2Version, variation1)]);
            Assert.Equal(new EventsCounterValue(1, default3, default3),
                         data.Counters[new EventsCounterKey(unknownFlagKey, null, null)]);
        }
        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));
        }
Exemplo n.º 9
0
        public void DataSinceFromLastDiagnostic()
        {
            IDiagnosticStore _serverDiagnosticStore = CreateDiagnosticStore(null);
            DiagnosticEvent  periodicEvent          = _serverDiagnosticStore.CreateEventAndReset();

            Assert.Equal(periodicEvent.JsonValue.Get("creationDate").AsLong,
                         UnixMillisecondTime.FromDateTime(_serverDiagnosticStore.DataSince).Value);
        }
        public void DataSinceFromLastDiagnostic()
        {
            var             store         = new DiagnosticStoreImpl();
            DiagnosticEvent periodicEvent = store.CreateEventAndReset();

            Assert.Equal(periodicEvent.JsonValue.Get("creationDate").AsLong,
                         UnixMillisecondTime.FromDateTime(store.DataSince).Value);
        }
        public void SetIndex()
        {
            var index = new UserIndex().UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000));

            _wrapper.SetIndex(index);

            var serializedData = _persistentStore.GetValue(ExpectedEnvironmentNamespace, ExpectedIndexKey);

            AssertJsonEqual(index.Serialize(), serializedData);
        }
Exemplo n.º 12
0
        public UserIndex UpdateTimestamp(string userId, UnixMillisecondTime timestamp)
        {
            var builder = ImmutableList.CreateBuilder <IndexEntry>();

            builder.AddRange(Data.Where(e => e.UserId != userId));
            builder.Add(new IndexEntry {
                UserId = userId, Timestamp = timestamp
            });
            return(new UserIndex(builder.ToImmutable()));
        }
 public void NoteTimestamp(UnixMillisecondTime timestamp)
 {
     if (StartDate.Value == 0 || timestamp.Value < StartDate.Value)
     {
         StartDate = timestamp;
     }
     if (timestamp.Value > EndDate.Value)
     {
         EndDate = timestamp;
     }
 }
        public void Serialize()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            var json     = ui.Serialize();
            var expected = @"[[""user1"",1000],[""user2"",2000]]";

            AssertJsonEqual(expected, json);
        }
        public void PruneWhenLimitIsNotExceeded()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            Assert.Same(ui, ui.Prune(3, out var removed1));
            Assert.Empty(removed1);

            Assert.Same(ui, ui.Prune(2, out var removed2));
            Assert.Empty(removed2);
        }
        public void UpdateTimestampForExistingUser()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000));

            ui = ui.UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(2001));

            Assert.Collection(ui.Data,
                              AssertEntry("user2", 2000),
                              AssertEntry("user1", 2001));
        }
 // Adds this event to our counters, if it is a type of event we need to count.
 public void SummarizeEvent(
     UnixMillisecondTime timestamp,
     string flagKey,
     int?flagVersion,
     int?variation,
     LdValue value,
     LdValue defaultValue
     )
 {
     _eventsState.IncrementCounter(flagKey, variation, flagVersion, value, defaultValue);
     _eventsState.NoteTimestamp(timestamp);
 }
        public void AddStreamInit(DateTime timestamp, TimeSpan duration, bool failed)
        {
            var streamInitObject = LdValue.BuildObject();

            streamInitObject.Add("timestamp", UnixMillisecondTime.FromDateTime(timestamp).Value);
            streamInitObject.Add("durationMillis", duration.TotalMilliseconds);
            streamInitObject.Add("failed", failed);
            lock (StreamInitsLock)
            {
                StreamInits.Add(streamInitObject.Build());
            }
        }
        private void CheckSummaryEventDetails(LdValue o, UnixMillisecondTime startDate, UnixMillisecondTime endDate, params Action <LdValue>[] flagChecks)
        {
            CheckSummaryEvent(o);
            Assert.Equal(LdValue.Of(startDate.Value), o.Get("startDate"));
            Assert.Equal(LdValue.Of(endDate.Value), o.Get("endDate"));
            var features = o.Get("features");

            Assert.Equal(flagChecks.Length, features.Count);
            foreach (var flagCheck in flagChecks)
            {
                flagCheck(features);
            }
        }
        public void SummaryEventIsSerialized()
        {
            var summary = new EventSummary();
            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1001));

            summary.IncrementCounter("first", 1, 11, LdValue.Of("value1a"), LdValue.Of("default1"));

            summary.IncrementCounter("second", 1, 21, LdValue.Of("value2a"), LdValue.Of("default2"));

            summary.IncrementCounter("first", 1, 11, LdValue.Of("value1a"), LdValue.Of("default1"));
            summary.IncrementCounter("first", 1, 12, LdValue.Of("value1a"), LdValue.Of("default1"));

            summary.IncrementCounter("second", 2, 21, LdValue.Of("value2b"), LdValue.Of("default2"));
            summary.IncrementCounter("second", null, 21, LdValue.Of("default2"), LdValue.Of("default2")); // flag exists (has version), but eval failed (no variation)

            summary.IncrementCounter("third", null, null, LdValue.Of("default3"), LdValue.Of("default3")); // flag doesn't exist (no version)

            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1000));
            summary.NoteTimestamp(UnixMillisecondTime.OfMillis(1002));

            var f = new EventOutputFormatter(new EventsConfiguration());
            var outputEvent = LdValue.Parse(f.SerializeOutputEvents(new object[0], summary, out var count)).Get(0);
            Assert.Equal(1, count);

            Assert.Equal("summary", outputEvent.Get("kind").AsString);
            Assert.Equal(1000, outputEvent.Get("startDate").AsInt);
            Assert.Equal(1002, outputEvent.Get("endDate").AsInt);

            var featuresJson = outputEvent.Get("features");
            Assert.Equal(3, featuresJson.Count);

            var firstJson = featuresJson.Get("first");
            Assert.Equal("default1", firstJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(firstJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""value"":""value1a"",""variation"":1,""version"":11,""count"":2}"),
                LdValue.Parse(@"{""value"":""value1a"",""variation"":1,""version"":12,""count"":1}"));

            var secondJson = featuresJson.Get("second");
            Assert.Equal("default2", secondJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(secondJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""value"":""value2a"",""variation"":1,""version"":21,""count"":1}"),
                LdValue.Parse(@"{""value"":""value2b"",""variation"":2,""version"":21,""count"":1}"),
                LdValue.Parse(@"{""value"":""default2"",""version"":21,""count"":1}"));

            var thirdJson = featuresJson.Get("third");
            Assert.Equal("default3", thirdJson.Get("default").AsString);
            TestUtil.AssertContainsInAnyOrder(thirdJson.Get("counters").AsList(LdValue.Convert.Json),
                LdValue.Parse(@"{""unknown"":true,""value"":""default3"",""count"":1}"));
        }
Exemplo n.º 21
0
        public void SummarizeEventSetsStartAndEndDates()
        {
            var             time1 = UnixMillisecondTime.OfMillis(1000);
            var             time2 = UnixMillisecondTime.OfMillis(2000);
            var             time3 = UnixMillisecondTime.OfMillis(3000);
            EventSummarizer es    = new EventSummarizer();

            es.SummarizeEvent(time2, "flag", null, null, LdValue.Null, LdValue.Null);
            es.SummarizeEvent(time1, "flag", null, null, LdValue.Null, LdValue.Null);
            es.SummarizeEvent(time3, "flag", null, null, LdValue.Null, LdValue.Null);
            EventSummary data = es.Snapshot();

            Assert.Equal(time1, data.StartDate);
            Assert.Equal(time3, data.EndDate);
        }
Exemplo n.º 22
0
        public void PeriodicEventDefaultValuesAreCorrect()
        {
            IDiagnosticStore _serverDiagnosticStore = CreateDiagnosticStore(null);
            DateTime         dataSince     = _serverDiagnosticStore.DataSince;
            LdValue          periodicEvent = _serverDiagnosticStore.CreateEventAndReset().JsonValue;

            Assert.Equal("diagnostic", periodicEvent.Get("kind").AsString);
            Assert.Equal(UnixMillisecondTime.FromDateTime(dataSince).Value, periodicEvent.Get("dataSinceDate").AsLong);
            Assert.Equal(0, periodicEvent.Get("eventsInLastBatch").AsInt);
            Assert.Equal(0, periodicEvent.Get("droppedEvents").AsInt);
            Assert.Equal(0, periodicEvent.Get("deduplicatedUsers").AsInt);

            LdValue streamInits = periodicEvent.Get("streamInits");

            Assert.Equal(0, streamInits.Count);
        }
        public void PruneRemovesLeastRecentUsers()
        {
            var ui = new UserIndex()
                     .UpdateTimestamp("user1", UnixMillisecondTime.OfMillis(1000))
                     .UpdateTimestamp("user2", UnixMillisecondTime.OfMillis(2000))
                     .UpdateTimestamp("user3", UnixMillisecondTime.OfMillis(1111)) // deliberately out of order
                     .UpdateTimestamp("user4", UnixMillisecondTime.OfMillis(3000))
                     .UpdateTimestamp("user5", UnixMillisecondTime.OfMillis(4000));

            var ui1 = ui.Prune(3, out var removed);

            Assert.Equal(ImmutableList.Create("user1", "user3"), removed);
            Assert.Collection(ui1.Data,
                              AssertEntry("user2", 2000),
                              AssertEntry("user4", 3000),
                              AssertEntry("user5", 4000));
        }
Exemplo n.º 24
0
        public void CanAddStreamInit()
        {
            IDiagnosticStore _serverDiagnosticStore = CreateDiagnosticStore(null);
            DateTime         timestamp = DateTime.Now;

            _serverDiagnosticStore.AddStreamInit(timestamp, TimeSpan.FromMilliseconds(200.0), true);
            DiagnosticEvent periodicEvent = _serverDiagnosticStore.CreateEventAndReset();

            LdValue streamInits = periodicEvent.JsonValue.Get("streamInits");

            Assert.Equal(1, streamInits.Count);

            LdValue streamInit = streamInits.Get(0);

            Assert.Equal(UnixMillisecondTime.FromDateTime(timestamp).Value, streamInit.Get("timestamp").AsLong);
            Assert.Equal(200, streamInit.Get("durationMillis").AsInt);
            Assert.True(streamInit.Get("failed").AsBool);
        }
Exemplo n.º 25
0
 internal static DateTime?ValueToDate(LdValue value)
 {
     if (value.IsString)
     {
         try
         {
             return(DateTime.Parse(value.AsString).ToUniversalTime());
         }
         catch (FormatException)
         {
             return(null);
         }
     }
     if (value.IsNumber)
     {
         return(UnixMillisecondTime.OfMillis(value.AsLong).AsDateTime);
     }
     return(null);
 }
Exemplo n.º 26
0
        public void UsePreconfiguredFlag()
        {
            CreateAndStart();
            _updates.ExpectInit(_initialUser);

            var flag = new FeatureFlagBuilder().Version(1).Value(true).Variation(0).Reason(EvaluationReason.OffReason)
                       .TrackEvents(true).TrackReason(true).DebugEventsUntilDate(UnixMillisecondTime.OfMillis(123)).Build();

            _td.Update(_td.Flag("flag1").PreconfiguredFlag(flag));

            var item1 = _updates.ExpectUpsert(_initialUser, "flag1");

            Assert.Equal(flag, item1.Item);

            _td.Update(_td.Flag("flag1").PreconfiguredFlag(flag));

            var item2       = _updates.ExpectUpsert(_initialUser, "flag1");
            var updatedFlag = new FeatureFlagBuilder(flag).Version(2).Build();

            Assert.Equal(updatedFlag, item2.Item);
        }
Exemplo n.º 27
0
        public async Task <StoreMetadata?> GetMetadataAsync()
        {
            var db = _redis.GetDatabase();

            var value = await db.StringGetAsync(_syncTimeKey);

            if (value.IsNull)
            {
                return(null);
            }
            if (value == "")
            {
                return(new StoreMetadata {
                    LastUpToDate = null
                });
            }
            var millis = long.Parse(value);

            return(new StoreMetadata {
                LastUpToDate = UnixMillisecondTime.OfMillis(millis)
            });
        }
        public DiagnosticEvent CreateEventAndReset()
        {
            DateTime currentTime       = DateTime.Now;
            long     droppedEvents     = Interlocked.Exchange(ref DroppedEvents, 0);
            long     deduplicatedUsers = Interlocked.Exchange(ref DeduplicatedUsers, 0);
            long     eventsInLastBatch = Interlocked.Exchange(ref EventsInLastBatch, 0);
            long     dataSince         = Interlocked.Exchange(ref DataSince, currentTime.ToBinary());

            var statEvent = LdValue.BuildObject();

            AddDiagnosticCommonFields(statEvent, "diagnostic", currentTime);
            statEvent.Add("eventsInLastBatch", eventsInLastBatch);
            statEvent.Add("dataSinceDate", UnixMillisecondTime.FromDateTime(DateTime.FromBinary(dataSince)).Value);
            statEvent.Add("droppedEvents", droppedEvents);
            statEvent.Add("deduplicatedUsers", deduplicatedUsers);
            lock (StreamInitsLock) {
                statEvent.Add("streamInits", StreamInits.Build());
                StreamInits = LdValue.BuildArray();
            }

            return(new DiagnosticEvent(statEvent.Build()));
        }
        public async Task <StoreMetadata?> GetMetadataAsync()
        {
            var key     = PrefixedNamespace(MetadataKey);
            var request = new GetItemRequest(_tableName, MakeKeysMap(key, key), true);
            var result  = await _client.GetItemAsync(request);

            if (result.Item is null || result.Item.Count == 0)
            {
                return(null);
            }
            if (!result.Item.TryGetValue(SyncTimeAttr, out var syncTimeValue) || string.IsNullOrEmpty(syncTimeValue.N))
            {
                return(new StoreMetadata {
                    LastUpToDate = null
                });
            }
            if (!long.TryParse(syncTimeValue.N, out var milliseconds))
            {
                throw new InvalidOperationException("Invalid data in DynamoDB: non-numeric timestamp");
            }
            return(new StoreMetadata {
                LastUpToDate = UnixMillisecondTime.OfMillis(milliseconds)
            });
        }
Exemplo n.º 30
0
        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));
        }