private static IEnumerable <bool?> QueuedBubblesIterator(string serviceName, bool hourLimitation = false, bool removeCurrentlySendingBubbles = false) { lock (_dbLock) { var currentTime = Time.GetNowUnixTimestamp(); const int SecondsInHour = 3600; using (var db = new SqlDatabase <Entry>(Location)) { foreach (var possibleBubble in db.Store.Where(x => serviceName == x.ServiceName)) { if (hourLimitation && possibleBubble.Time <= currentTime - SecondsInHour) { continue; } foreach (var bubbleGroup in BubbleGroupManager.BubbleGroupsNonUnified) { if (bubbleGroup.PartiallyLoaded) { continue; } foreach (var bubble in bubbleGroup) { if (bubble.Status != Bubble.BubbleStatus.Waiting) { continue; } if (removeCurrentlySendingBubbles && InsertBubble.IsSending(bubble.ID)) { continue; } if (possibleBubble.Guid == bubble.ID) { yield return(true); } } } } } } }
public static Task <List <Receipt> > Send(string[] serviceNames, bool scheduled = false) { return(Task <List <Receipt> > .Factory.StartNew(() => { //PROCESS: 1) find all bubbles under serviceNames in db // 2) relate db entries to bubbles loaded into memory by Disa // 3) parallel send bubbles based respective to service // 4) delete all successful bubbles out of db lock (_sendLock) { var possibleBubblesFromDatabase = new List <Entry>(); lock (_dbLock) { using (var db = new SqlDatabase <Entry>(Location)) { foreach (var possibleBubble in db.Store.Where(x => serviceNames.Contains(x.ServiceName)).Reverse()) { if (!InsertBubble.IsSending(possibleBubble.Guid)) { possibleBubblesFromDatabase.Add(possibleBubble); } } } } var possibleBubblesInDisa = new List <Tuple <Entry, VisualBubble> >(); foreach (var bubbleGroup in BubbleGroupManager.BubbleGroupsNonUnified) { if (bubbleGroup.PartiallyLoaded) { continue; } foreach (var bubble in bubbleGroup) { if (bubble.Status != Bubble.BubbleStatus.Waiting) { continue; } var possibleBubbleFromDatabase = possibleBubblesFromDatabase.FirstOrDefault(x => x.Guid == bubble.ID); if (possibleBubbleFromDatabase != null) { possibleBubblesInDisa.Add(new Tuple <Entry, VisualBubble>(possibleBubbleFromDatabase, bubble)); } } } var sent = new List <Tuple <Entry, bool> >(); var possibleBubblesInDisaByService = possibleBubblesInDisa.GroupBy(x => x.Item1.ServiceName); Parallel.ForEach(possibleBubblesInDisaByService, possibleBubblesInService => { var failed = false; foreach (var possibleBubble in possibleBubblesInService) { if (failed) { sent.Add(new Tuple <Entry, bool>(possibleBubble.Item1, false)); continue; } Utils.DebugPrint(">>>>>>>>>>> Sending queued bubble on " + possibleBubble.Item2.Service.Information.ServiceName + "!"); var sendBubbleTask = BubbleManager.Send(possibleBubble.Item2, true); sendBubbleTask.Wait(); if (sendBubbleTask.Result) { Utils.DebugPrint(">>>>>>>>> Successfully sent queued bubble on " + possibleBubble.Item2.Service.Information.ServiceName + "!"); sent.Add(new Tuple <Entry, bool>(possibleBubble.Item1, true)); lock (_dbLock) { using (var db = new SqlDatabase <Entry>(Location)) { db.Remove(possibleBubble.Item1); } } Utils.Delay(100).Wait(); } else { Utils.DebugPrint(">>>>>>>>> Failed to send queued bubble on " + possibleBubble.Item2.Service.Information.ServiceName + "!"); sent.Add(new Tuple <Entry, bool>(possibleBubble.Item1, false)); failed = true; // fail the entire chain for this service from here on out so messages aren't sent out of order } } }); SanityCheckup(); var receipts = sent.Select(x => new Receipt(x.Item1.Guid, x.Item2)).ToList(); if (!scheduled) { if (receipts.FirstOrDefault(x => !x.Success) != null) { ScheduleReSend(serviceNames); } else { var needToSendAgain = serviceNames.Where(x => BubbleQueueManager.HasQueuedBubbles(x, true, true)).ToArray(); if (needToSendAgain.Any()) { Send(needToSendAgain); } } } return receipts; } })); }