public async Task EventHistory_FlushHistory() { SDKData.Instance.ApiKey = "540aa95ccf215718295c2c563a2090676994f09927f09a6e09a67c83be10b00c"; var beacon = new Beacon(); beacon.Id1 = "7367672374000000ffff0000ffff0007"; beacon.Id2 = 8008; beacon.Id3 = 5; beacon.Timestamp = DateTimeOffset.Now; var args = new BeaconEventArgs(); args.Beacon = beacon; args.EventType = BeaconEventType.Exit; var resolvedActionEventArgs = new ResolvedActionsEventArgs() { BeaconPid = beacon.Pid, BeaconEventType = BeaconEventType.Enter }; BeaconAction beaconaction1 = new BeaconAction() { Body = "body", Url = "http://www.com", Uuid = "1223" }; BeaconAction beaconaction2 = new BeaconAction() { Body = "body", Url = "http://www.com", Uuid = "5678" }; BeaconAction beaconaction3 = new BeaconAction() { Body = "body", Url = "http://www.com", Uuid = "9678" }; ResolvedAction res1 = new ResolvedAction() { SupressionTime = 100, SendOnlyOnce = true, BeaconAction = beaconaction1 }; ResolvedAction res2 = new ResolvedAction() { SupressionTime = 100, SendOnlyOnce = true, BeaconAction = beaconaction2 }; ResolvedAction res3 = new ResolvedAction() { SupressionTime = 1, SendOnlyOnce = true, BeaconAction = beaconaction3 }; EventHistory eventHistory = new EventHistory(); await eventHistory.SaveBeaconEventAsync(args); await eventHistory.SaveExecutedResolvedActionAsync(resolvedActionEventArgs, beaconaction1); await eventHistory.SaveExecutedResolvedActionAsync(resolvedActionEventArgs, beaconaction3); await eventHistory.FlushHistoryAsync(); }
/// <summary> /// If supressionTime is set for the action, fuction will check from the history if the /// action is already presented during the supression time. /// </summary> /// <param name="resolvedAction"></param> /// <returns>True only if action should be supressed.</returns> public async Task<bool> ShouldSupressAsync(ResolvedAction resolvedAction) { bool suppress = false; if (resolvedAction.SupressionTime > 0) { try { _asyncWaiter.WaitOne(); IList<DBHistoryAction> dbHistoryActions = await _storage.GetActionsAsync(resolvedAction.BeaconAction.Uuid); if (dbHistoryActions != null) { foreach (var dbHistoryAction in dbHistoryActions) { var action_timestamp = dbHistoryAction.dt.AddSeconds(resolvedAction.SupressionTime); if (action_timestamp > DateTimeOffset.Now) { suppress = true; break; } } } } finally { _asyncWaiter.Set(); } } return suppress; }
/// <summary> /// If sendOnlyOnce is true for resolved action, fuction will check from the history if the /// action is already presented for the user. /// </summary> /// <param name="resolvedAction"></param> /// <returns>True ,if action type is SendOnlyOnce, and it has been shown already. Otherwise false.</returns> public async Task<bool> CheckSendOnlyOnceAsync(ResolvedAction resolvedAction) { bool sendonlyOnce = false; if (resolvedAction.SendOnlyOnce) { try { _asyncWaiter.WaitOne(); DBHistoryAction dbHistoryAction = await _storage.GetActionAsync(resolvedAction.BeaconAction.Uuid); if (dbHistoryAction != null) { sendonlyOnce = true; } } finally { _asyncWaiter.Set(); } } return sendonlyOnce; }
/// <summary> /// /// </summary> /// <param name="resolvedAction"></param> /// <param name="dueTime"></param> /// <param name="beaconPid"></param> /// <param name="eventTypeDetectedByDevice"></param> /// <returns></returns> public async Task SaveDelayedActionAsync( ResolvedAction resolvedAction, DateTimeOffset dueTime, string beaconPid, BeaconEventType eventTypeDetectedByDevice) { string actionAsString = ResolvedAction.Serialize(resolvedAction); DBDelayedAction delayedAction = new DBDelayedAction() { ResolvedAction = actionAsString, DueTime = dueTime, BeaconPid = beaconPid, EventTypeDetectedByDevice = (int)eventTypeDetectedByDevice, Executed = false }; await _db.InsertAsync(delayedAction); }
/// <summary> /// Executes the given action, stores the event in event history and notifies the listeners. /// </summary> /// <param name="resolvedAction"></param> /// <param name="beaconPid"></param> /// <param name="beaconEventType"></param> private async Task ExecuteActionAsync(ResolvedAction resolvedAction, string beaconPid, BeaconEventType beaconEventType) { bool checkOnlyOnce = await _eventHistory.CheckSendOnlyOnceAsync(resolvedAction); bool shouldSupress = await _eventHistory.ShouldSupressAsync(resolvedAction); if (!shouldSupress && !checkOnlyOnce && resolvedAction.IsInsideTimeframes(DateTimeOffset.Now)) { await _eventHistory.SaveExecutedResolvedActionAsync(resolvedAction.BeaconAction, beaconPid, beaconEventType); if (resolvedAction.ReportImmediately) { await _eventHistory.FlushHistoryAsync(); } if (BeaconActionResolved != null) { BeaconActionResolved(this, resolvedAction.BeaconAction); } } }
/// <summary> /// Serializes the given ResolvedAction instance. /// </summary> /// <param name="resolvedAction">The instance to serialize.</param> /// <returns>The serialized instance as string.</returns> public static string Serialize(ResolvedAction resolvedAction) { MemoryStream stream = new MemoryStream(); DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(ResolvedAction)); serializer.WriteObject(stream, resolvedAction); stream.Position = 0; StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); }
/// <summary> /// Parses and constructs a ResolvedAction instance from the given JSON data. /// </summary> /// <param name="contentJson"></param> /// <returns>A newly created ResolvedAction instance.</returns> public static ResolvedAction ResolvedActionFromJsonObject(JsonObject contentJson) { var resolvedAction = new ResolvedAction(); var obj = contentJson.GetObject(); var type = (int)obj.GetNamedValue(KeyType).GetNumber(); var actionUUID = obj.GetNamedString(KeyActionUuid); var trigger = (int)obj.GetNamedNumber(KeyTrigger); var delaySeconds = JsonHelper.Optional(obj, KeyDelayTime, 0); var jsonContent = obj.GetNamedObject(KeyContent); var sendOnlyOnce = JsonHelper.OptionalBoolean(obj, KeySendOnlyOnce, false); var beacons = contentJson.GetNamedArray(KeyBeacons); var supressionTime = JsonHelper.Optional(obj, KeysupressionTime, -1); var reportImmediately = JsonHelper.OptionalBoolean(obj, KeyReportImmediately, false); // TimeFrames if (obj.ContainsKey(KeyTimeframes)) { if (obj.GetNamedValue(KeyTimeframes).ValueType == JsonValueType.Array) { var keyframes = obj.GetNamedArray(KeyTimeframes); foreach (var frame in keyframes) { if (frame.ValueType == JsonValueType.Object) { string start = JsonHelper.OptionalString(frame.GetObject(), KeyStart); string end = JsonHelper.OptionalString(frame.GetObject(), KeyEnd); DateTimeOffset? startOffset = null; DateTimeOffset? endOffset = null; var newFrame = new Timeframe(); if (start.Length > 5) { startOffset = DateTimeOffset.Parse(start); } if (end.Length > 5) { endOffset = DateTimeOffset.Parse(end); } resolvedAction.Timeframes.Add(new Timeframe() { Start = startOffset, End = endOffset }); } } } } foreach (JsonValue resp in beacons) { if (resp.ValueType == JsonValueType.String) { resolvedAction.BeaconPids.Add(resp.GetString(), 1); } } BeaconAction action = ActionFactory.CreateBeaconAction(type, jsonContent, actionUUID); resolvedAction.BeaconAction = action; resolvedAction.EventTypeDetectedByDevice = (BeaconEventType)trigger; resolvedAction.Delay = delaySeconds; resolvedAction.SendOnlyOnce = sendOnlyOnce; resolvedAction.SupressionTime = supressionTime; resolvedAction.ReportImmediately = reportImmediately; return resolvedAction; }