internal static async void UpdateGroupLegibleID(BubbleGroup bubbleGroup, Action finished = null) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return; } try { await service.GetBubbleGroupLegibleId(bubbleGroup, legibleID => { bubbleGroup.LegibleId = legibleID; if (finished == null) { BubbleGroupEvents.RaiseRefreshed(bubbleGroup); } else { finished(); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group legible ID: " + service.Information.ServiceName + " - " + bubbleGroup.Address + ": " + ex); if (finished != null) { finished(); } } }
public static bool UpdatePhoto(BubbleGroup bubbleGroup, Action <DisaThumbnail> finished) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return(false); } if (bubbleGroup.Service.Information.UsesInternet && !Platform.HasInternetConnection()) { return(false); } try { service.GetBubbleGroupPhoto(bubbleGroup, photo => { if (photo != null && photo.Failed) { if (finished != null) { finished(bubbleGroup.Photo); } return; } Action <DisaThumbnail> callbackFinished = thePhoto => { bubbleGroup.Photo = thePhoto; bubbleGroup.IsPhotoSetFromService = true; if (finished != null) { finished(bubbleGroup.Photo); } }; if (photo == null && bubbleGroup.IsParty) { BubbleGroupUtils.StitchPartyPhoto(bubbleGroup, callbackFinished); } else { callbackFinished(photo); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group photo: " + service.Information.ServiceName + ": " + ex.Message); if (finished != null) { finished(null); } } return(true); }
public static void SendPresence(Service service, bool available, bool justAddIfNoLastPresence = false) { if (!service.Information.DoesSupport(typeof(PresenceBubble))) { return; } var presenceBubble = new PresenceBubble(Time.GetNowUnixTimestamp(), Bubble.BubbleDirection.Outgoing, null, false, service, available); Utils.DebugPrint("Sending " + (presenceBubble.Available ? "available" : "unavailble") + " to " + presenceBubble.Service.Information.ServiceName); lock (LastPresenceBubbles) { Action a = () => { LastPresenceBubbles.RemoveAll(pb => pb.Service == presenceBubble.Service); LastPresenceBubbles.Add(presenceBubble); }; if (!justAddIfNoLastPresence) { a(); } else { var hasPresence = LastPresenceBubbles.Any(x => x.Service == presenceBubble.Service); if (hasPresence) { // do-nothing } else { a(); } } } if (!justAddIfNoLastPresence && ServiceManager.IsRunning(service)) { Send(presenceBubble); } if (justAddIfNoLastPresence) { return; } if (available) { return; } foreach (var group in BubbleGroupManager.FindAll(service)) { @group.PresenceType = PresenceBubble.PresenceType.Unavailable; } }
public static bool LoadFullyIfNeeded(BubbleGroup group, bool sync = false) { if (@group == null) { return(false); } var loadedSomething = false; lock (BubbleGroupDatabase.OperationLock) { var unifiedGroup = @group as UnifiedBubbleGroup; var associatedGroups = unifiedGroup != null ? unifiedGroup.Groups.ToList() : new[] { @group }.ToList(); var associatedPartiallyLoadedGroups = associatedGroups.Where(x => x.PartiallyLoaded).ToList(); foreach (var partiallyLoadedGroup in associatedPartiallyLoadedGroups) { loadedSomething = true; var partiallyLoadedBubblesToRemove = partiallyLoadedGroup.Bubbles.ToList(); foreach (var bubble in BubbleGroupDatabase.FetchBubbles(partiallyLoadedGroup).Reverse()) { partiallyLoadedGroup.Bubbles.Add(bubble); } foreach (var partiallyLoadedBubbleToRemove in partiallyLoadedBubblesToRemove) { partiallyLoadedGroup.Bubbles.Remove(partiallyLoadedBubbleToRemove); } partiallyLoadedGroup.PartiallyLoaded = false; } if (unifiedGroup != null && !unifiedGroup.UnifiedGroupLoaded) { Populate(unifiedGroup); } } if (!sync && loadedSomething) { Task.Factory.StartNew(() => { var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup != null) { BubbleQueueManager.Send(unifiedGroup.Groups.Where(x => ServiceManager.IsRunning(x.Service)) .Select(x => x.Service.Information.ServiceName).ToArray()); } else if (ServiceManager.IsRunning(@group.Service)) { BubbleQueueManager.Send(new[] { @group.Service.Information.ServiceName }); } BubbleManager.SetNotQueuedToFailures(@group); }); } return(loadedSomething); }
internal static void UpdateLastOnline(BubbleGroup bubbleGroup, bool updateUi = true, bool fromProcessUpdateLastOnlineQueue = false) { var service = bubbleGroup.Service; if (!fromProcessUpdateLastOnlineQueue) { if (!ServiceManager.IsRunning(service) && !bubbleGroup.IsParty) { lock (UpdateLastOnlineQueue) UpdateLastOnlineQueue.Add(new Tuple <BubbleGroup, bool>(bubbleGroup, updateUi)); return; } } if (!ServiceManager.IsRunning(service) || bubbleGroup.IsParty) { return; } // reject the last online update if the Presence is currently available if (bubbleGroup.Presence) { return; } try { service.GetBubbleGroupLastOnline(bubbleGroup, time => { // reject the last online update if the Presence is currently available if (bubbleGroup.Presence) { return; } bubbleGroup.PresenceType = PresenceBubble.PresenceType.Unavailable; bubbleGroup.LastSeen = time; if (updateUi) { BubbleGroupEvents.RaiseInformationUpdated(bubbleGroup); } //we constantly need to subscribe to a bubble group. doing it //in last online method is the most effective. BubbleManager.SendSubscribe(bubbleGroup, true); //Presence(service, true); }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group last online: " + service.Information.ServiceName + ": " + ex.Message); } }
public static bool UpdateUnknownPartyParticipant(BubbleGroup bubbleGroup, string participantAddress, Action onAdded = null) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return(false); } if (string.IsNullOrWhiteSpace(participantAddress)) { return(false); } if (bubbleGroup.FailedUnknownParticipants.FirstOrDefault(x => bubbleGroup.Service.BubbleGroupComparer(x, participantAddress)) != null) { return(false); } try { service.GetBubbleGroupUnknownPartyParticipant(bubbleGroup, participantAddress, participant => { if (participant != null) { var contains = bubbleGroup.Participants.FirstOrDefault(x => bubbleGroup.Service.BubbleGroupComparer(x.Address, participantAddress)) != null; if (!contains) { participant.Unknown = true; bubbleGroup.Participants.Add(participant); } } else { bubbleGroup.FailedUnknownParticipants.Add(participantAddress); } if (onAdded != null) { onAdded(); } BubbleGroupEvents.RaiseRefreshed(bubbleGroup); BubbleGroupEvents.RaiseBubblesUpdated(bubbleGroup); }); } catch (Exception ex) { Utils.DebugPrint("Error getting unknown bubble group participant: " + service.Information.ServiceName + ": " + ex.Message); return(false); } return(true); }
internal static void UpdateLastOnline(BubbleGroup bubbleGroup, bool updateUi = true, bool fromProcessUpdateLastOnlineQueue = false) { var service = bubbleGroup.Service; if (!fromProcessUpdateLastOnlineQueue) { if (!ServiceManager.IsRunning(service) && !bubbleGroup.IsParty) { Utils.DebugPrint(">>>>>>>>>>>>>> Stashing UpdateLastOnline for later."); lock (UpdateLastOnlineQueue) UpdateLastOnlineQueue.Add(new Tuple <BubbleGroup, bool>(bubbleGroup, updateUi)); return; } } if (!ServiceManager.IsRunning(service) || bubbleGroup.IsParty) { return; } // reject the last online update if the Presence is currently available if (bubbleGroup.Presence) { return; } try { Utils.DebugPrint(">>>>>>>>>>>>>> Calling GetBubbleGroupLastOnline."); service.GetBubbleGroupLastOnline(bubbleGroup, time => { // reject the last online update if the Presence is currently available if (bubbleGroup.Presence) { return; } bubbleGroup.PresenceType = PresenceBubble.PresenceType.Unavailable; bubbleGroup.LastSeen = time; if (updateUi) { BubbleGroupEvents.RaiseInformationUpdated(bubbleGroup); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group last online: " + service.Information.ServiceName + ": " + ex.Message); } }
private static bool SupportsSyncAndIsRunning(Service service) { if (!ServiceManager.IsRunning(service)) { return(false); } if (!SupportsSync(service)) { return(false); } return(true); }
internal static void SyncService(Service service) { if (ServiceManager.IsRunning(service)) { Utils.DebugPrint("Refreshing service contacts..."); service.RefreshPhoneBookContacts(); } else { Utils.DebugPrint("Force refreshing service " + service.Information.ServiceName + " isn't possible. Why? It isn't running!"); } Utils.DebugPrint("Finished refreshing service contacts. Calling contacts update and bubble group update."); BubbleGroupUpdater.Update(service); }
public static bool UpdateQuotedMessageTitle(VisualBubble bubble, Action <string> onTitleUpdated) { var service = bubble.Service; if (!ServiceManager.IsRunning(service)) { return(false); } if (string.IsNullOrWhiteSpace(bubble.QuotedAddress)) { return(false); } try { service.GetQuotedMessageTitle(bubble, result => { var bubbleGroup = BubbleGroupManager.FindWithAddress(bubble.Service, bubble.Address); if (bubbleGroup != null) { var quotedTitles = bubbleGroup.QuotedTitles == null ? new List <DisaQuotedTitle>() : bubbleGroup.QuotedTitles.ToList(); var quotedTitle = quotedTitles.FirstOrDefault(x => bubbleGroup.Service.BubbleGroupComparer(x.Address, bubble.QuotedAddress)); if (quotedTitle == null) { quotedTitles.Add(new DisaQuotedTitle { Address = bubble.QuotedAddress, Title = result, }); } else { quotedTitle.Title = result; } bubbleGroup.QuotedTitles = quotedTitles.ToArray(); } onTitleUpdated(result); }); return(true); } catch (Exception e) { Utils.DebugPrint("Error getting quoted message title " + e); return(false); } }
public static async void UpdatePhoto(BubbleGroup bubbleGroup, Action <DisaThumbnail> finished) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return; } if (bubbleGroup.Service.Information.UsesInternet && !Platform.HasInternetConnection()) { return; } try { await service.GetBubbleGroupPhoto(bubbleGroup, photo => { if (photo != null && photo.Failed) { if (finished != null) { finished(bubbleGroup.Photo); } return; } bubbleGroup.Photo = photo; bubbleGroup.IsPhotoSetFromService = true; if (finished != null) { finished(bubbleGroup.Photo); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group photo: " + service.Information.ServiceName + " - " + bubbleGroup.Address + ": " + ex); if (finished != null) { finished(null); } } }
public static async void UpdateParticipantPhoto(Service service, DisaParticipant participant, Action <DisaThumbnail> finished) { if (!ServiceManager.IsRunning(service)) { return; } if (service.Information.UsesInternet && !Platform.HasInternetConnection()) { return; } var participantClosure = participant; try { await service.GetBubbleGroupPartyParticipantPhoto(participant, result => { if (result != null && result.Failed) { if (finished != null) { finished(participantClosure.Photo); } return; } participantClosure.IsPhotoSetFromService = true; participantClosure.Photo = result; finished(result); }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group participant photo: " + service.Information.ServiceName + " - " + participant.Address + ": " + ex); if (finished != null) { finished(null); } } return; }
internal static async void UpdateName(BubbleGroup bubbleGroup, Action finished = null) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return; } try { await service.GetBubbleGroupName(bubbleGroup, title => { bubbleGroup.IsTitleSetFromService = true; if (string.IsNullOrWhiteSpace(title)) { Utils.DebugPrint("Update name title is null (rejecting): " + service.Information.ServiceName + " - " + bubbleGroup.Address); } else { bubbleGroup.Title = title; } if (finished == null) { BubbleGroupEvents.RaiseRefreshed(bubbleGroup); BubbleGroupEvents.RaiseInformationUpdated(bubbleGroup); } else { finished(); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group name: " + service.Information.ServiceName + " - " + bubbleGroup.Address + ": " + ex); if (finished != null) { finished(); } } }
private static void SetUnread(BubbleGroup group, bool unread, bool updateUi = true, bool skipSendReadBubble = false, bool onlySetIfServiceRunning = true) { var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup != null) { foreach (var innerGroup in unifiedGroup.Groups) { SetUnread(innerGroup, false, skipSendReadBubble); } } Action @do = () => { var updatedSomething = BubbleGroupSettingsManager.GetUnread(@group); BubbleGroupSettingsManager.SetUnread(@group, unread); if (unifiedGroup == null) { if (!skipSendReadBubble) { if (@group.Service.Information.DoesSupport(typeof(ReadBubble)) && ServiceManager.IsRunning(@group.Service)) { BubbleManager.Send(new ReadBubble(Time.GetNowUnixTimestamp(), Bubble.BubbleDirection.Outgoing, @group.Service, @group.Address, null, Time.GetNowUnixTimestamp(), @group.IsParty, updatedSomething)); } } } if (updateUi) { BubbleGroupEvents.RaiseRefreshed(@group); } }; if (onlySetIfServiceRunning && ServiceManager.IsRunning(@group.Service)) { @do(); } else if (!onlySetIfServiceRunning) { @do(); } }
private static void SetUnread(BubbleGroup group, bool unread, bool updateUi = true, bool skipSendReadBubble = false, bool onlySetIfServiceRunning = true) { var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup != null) { foreach (var innerGroup in unifiedGroup.Groups) { SetUnread(innerGroup, unread, false, skipSendReadBubble, onlySetIfServiceRunning); } } var currentlyUnread = BubbleGroupSettingsManager.GetUnread(@group); if ((onlySetIfServiceRunning && ServiceManager.IsRunning(@group.Service)) || !onlySetIfServiceRunning) { BubbleGroupSettingsManager.SetUnread(@group, unread); if (unifiedGroup == null) { if (!skipSendReadBubble) { if (@group.Service.Information.DoesSupport(typeof(ReadBubble)) && ServiceManager.IsRunning(@group.Service)) { var readBubble = new ReadBubble(Time.GetNowUnixTimestamp(), Bubble.BubbleDirection.Outgoing, @group.Service, @group.Address, null, Time.GetNowUnixTimestamp(), @group.IsParty, currentlyUnread); if (@group.IsExtendedParty) { readBubble.ExtendedParty = true; } BubbleManager.Send(readBubble); } } } if (updateUi) { BubbleGroupEvents.RaiseRefreshed(@group); } } else { BubbleGroupSettingsManager.SetUnreadOffline(@group, unread); } }
private static BubbleGroup AddNewInternal(VisualBubble newBubble, bool raiseBubbleInserted) { var group = new BubbleGroup(newBubble, null, false); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(group, group.LastBubbleSafe().ID, true); if (ServiceManager.IsRunning(@group.Service)) { newBubble.Service.NewBubbleGroupCreated(@group).ContinueWith(x => { // force the UI to refetch the photo @group.IsPhotoSetFromService = false; BubbleManager.SendSubscribe(@group, true); BubbleGroupUpdater.Update(@group); }); } BubbleGroupManager.BubbleGroupsAdd(@group); BubbleGroupDatabase.AddBubble(@group, newBubble); if (raiseBubbleInserted) { try { BubbleGroupEvents.RaiseBubbleInserted(newBubble, @group); } catch (Exception ex) { Utils.DebugPrint( "Error in notifying the interface that the bubble group has been updated (" + newBubble.Service.Information.ServiceName + "): " + ex.Message); } } BubbleGroupUpdater.Update(@group); return(@group); }
public static Task ForceUpdate(Service service) { return(Task.Factory.StartNew(() => { Utils.DebugPrint("Querying phone contacts..."); _phoneBookContacts = Platform.GetPhoneBookContacts(); if (service != null) { if (ServiceManager.IsRunning(service)) { Utils.DebugPrint("Refreshing service contacts..."); service.RefreshPhoneBookContacts(); } else { Utils.DebugPrint("Force refreshing service " + service.Information.ServiceName + " isn't possible. Why? It isn't running!"); } Utils.DebugPrint("Finished refreshing service contacts. Calling contacts update and bubble group update."); BubbleGroupUpdater.Update(service); } })); }
public static void GetMentions(BubbleGroup group, Action <List <Mention> > result) { if (ServiceManager.IsRunning(group.Service)) { // Pull latest mention values Task.Factory.StartNew(() => { var uiMentions = group.Service as IMentions; if (uiMentions != null) { uiMentions.GetMentions(group, (mentions) => { // No RemoveAll for ThreadSafeList var itemsToRemove = group.Mentions.ToList(); foreach (var itemToRemove in itemsToRemove) { group.Mentions.Remove(itemToRemove); } group.Mentions.AddRange(mentions); result(mentions); }); } else { result(new List <Mention>()); } }); } else { // TODO: For hashtags we pull across all groups. var mentions = group.Mentions.Where(m => m.BubbleGroupId == group.ID).ToList(); result(mentions); } }
internal static void UpdateName(BubbleGroup bubbleGroup, Action finished = null) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return; } try { service.GetBubbleGroupName(bubbleGroup, title => { bubbleGroup.IsTitleSetFromService = true; bubbleGroup.Title = title; if (finished == null) { BubbleGroupEvents.RaiseRefreshed(bubbleGroup); BubbleGroupEvents.RaiseInformationUpdated(bubbleGroup); } else { finished(); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group name: " + service.Information.ServiceName + ": " + ex.Message); if (finished != null) { finished(); } } }
public static bool LoadFullyIfNeeded(BubbleGroup group, bool sync = false) { if (@group == null) { return(false); } var loadedSomething = false; lock (BubbleGroupDatabase.OperationLock) { var unifiedGroup = @group as UnifiedBubbleGroup; var adjustUnifiedGroupUnreadIndicatorIfExists = false; var associatedGroups = unifiedGroup != null ? unifiedGroup.Groups.ToList() : new[] { @group }.ToList(); var associatedPartiallyLoadedGroups = associatedGroups.Where(x => x.PartiallyLoaded).ToList(); foreach (var partiallyLoadedGroup in associatedPartiallyLoadedGroups) { var partiallyLoadedBubblesToRemove = partiallyLoadedGroup.Bubbles.ToList(); var rollingBack = false; TryAgain: try { loadedSomething = true; partiallyLoadedGroup.PartiallyLoaded = false; foreach (var bubble in BubbleGroupDatabase.FetchBubbles(partiallyLoadedGroup).Reverse()) { partiallyLoadedGroup.Bubbles.Add(bubble); } foreach (var partiallyLoadedBubbleToRemove in partiallyLoadedBubblesToRemove) { partiallyLoadedGroup.Bubbles.Remove(partiallyLoadedBubbleToRemove); } if (partiallyLoadedGroup.Bubbles.Count < 1) { foreach (var partiallyLoadedBubbleToRemove in partiallyLoadedBubblesToRemove) { partiallyLoadedGroup.Bubbles.Add(partiallyLoadedBubbleToRemove); } } } catch (Exception ex) { Utils.DebugPrint("Failed to fully load partially loaded group " + partiallyLoadedGroup.ID + ": " + ex); if (!rollingBack) { Utils.DebugPrint("Attempting to roll back the last transaction...."); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(partiallyLoadedGroup, null, false); adjustUnifiedGroupUnreadIndicatorIfExists = true; rollingBack = true; var lastModifiedIndex = BubbleGroupIndex.GetLastModifiedIndex(partiallyLoadedGroup.ID); if (lastModifiedIndex.HasValue) { try { BubbleGroupDatabase.RollBackTo(partiallyLoadedGroup, lastModifiedIndex.Value); goto TryAgain; } catch (Exception ex2) { Utils.DebugPrint("Failed to rollback: " + ex2); // fall-through. It's unrecoverable! } } else { // fall-through. It's unrecoverable! } } Utils.DebugPrint("Partially loaded group is dead. Killing and restarting (lost data occurred)."); BubbleGroupDatabase.Kill(partiallyLoadedGroup); BubbleGroupSync.RemoveFromSync(partiallyLoadedGroup); BubbleGroupDatabase.AddBubbles(partiallyLoadedGroup, partiallyLoadedBubblesToRemove.ToArray()); } } if (unifiedGroup != null && !unifiedGroup.UnifiedGroupLoaded) { Populate(unifiedGroup); } if (unifiedGroup != null && adjustUnifiedGroupUnreadIndicatorIfExists) { BubbleGroupSettingsManager.SetUnreadIndicatorGuid(unifiedGroup, null, false); } } if (!sync && loadedSomething) { Task.Factory.StartNew(() => { var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup != null) { BubbleQueueManager.Send(unifiedGroup.Groups.Where(x => ServiceManager.IsRunning(x.Service)) .Select(x => x.Service.Information.ServiceName).ToArray()); } else if (ServiceManager.IsRunning(@group.Service)) { BubbleQueueManager.Send(new[] { @group.Service.Information.ServiceName }); } BubbleQueueManager.SetNotQueuedToFailures(@group); }); } return(loadedSomething); }
public static Task Sync(BubbleGroup group, bool force = false) { return(Task.Factory.StartNew(() => { Utils.DebugPrint("Syncing convo " + group.ID); lock (SyncLock) { Utils.DebugPrint("Syncing convo " + group.ID + " (after lock)"); var somethingSynced = true; var groupsToSync = new List <BubbleGroup>(); var unifiedGroup = group as UnifiedBubbleGroup; if (unifiedGroup != null) { groupsToSync.AddRange(unifiedGroup.Groups); } else { groupsToSync.Add(group); } foreach (var groupToSync in groupsToSync) { if (!groupToSync.NeedsSync && !force) { continue; } var groupToSyncAgent = groupToSync.Service as Agent; if (groupToSyncAgent == null) { continue; } if (!ServiceManager.IsRunning(groupToSync.Service)) { continue; } try { var syncTask = groupToSyncAgent.Sync(groupToSync, Database.GetActionId(groupToSync)); syncTask.Wait(); var syncResult = syncTask.Result; if (!syncResult.EmptyResult && !syncResult.NullActionId && !syncResult.JustRefresh) { lock (BubbleGroupDatabase.OperationLock) { if (syncResult.ResultType == Result.Type.Purge) { Utils.DebugPrint("Sync is purging the database for bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); BubbleGroupDatabase.Kill(groupToSync); } if (!syncResult.EmptyInserts) { Utils.DebugPrint("Sync is inserting " + syncResult.Inserts.Length + " bubbles into " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); if (syncResult.ResultType == Result.Type.Purge) { syncResult.Inserts.TimSort((x, y) => x.Time.CompareTo(y.Time)); BubbleGroupDatabase.AddBubbles(groupToSync, syncResult.Inserts); } else { BubbleGroupDatabase.InsertBubblesByTime(groupToSync, syncResult.Inserts, SearchDepth); } } if (!syncResult.EmptyUpdates) { Utils.DebugPrint("Sync is updating " + syncResult.Updates.Length + " bubbles into " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); BubbleManager.Update(groupToSync, syncResult.Updates, SearchDepth); } Database.SetActionId(groupToSync, syncResult.NewActionId); } } else { Utils.DebugPrint("Sync for bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName + " returned an empty result (" + syncResult.ResultType.ToString() + ")."); somethingSynced = syncResult.JustRefresh; } groupToSync.NeedsSync = false; } catch (Exception ex) { Utils.DebugPrint("Failed to sync bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName + ": " + ex); somethingSynced = false; } } if (somethingSynced) { lock (BubbleGroupDatabase.OperationLock) { var sendingBubbles = BubbleManager.FetchAllSendingAndDownloading(group).ToList(); BubbleGroupFactory.UnloadFullLoad(group); BubbleGroupFactory.LoadFullyIfNeeded(group, true); if (sendingBubbles.Any()) { BubbleManager.Replace(group, sendingBubbles); } group.RaiseBubblesSynced(); } } } })); }
public static Task Sync(BubbleGroup group, bool force = false) { return(Task.Factory.StartNew(() => { Utils.DebugPrint("Syncing convo " + group.ID); lock (SyncLock) { Utils.DebugPrint("Syncing convo " + group.ID + " (after lock)"); var somethingSynced = false; var groupsToSync = new List <BubbleGroup>(); var unifiedGroup = group as UnifiedBubbleGroup; if (unifiedGroup != null) { groupsToSync.AddRange(unifiedGroup.Groups); } else { groupsToSync.Add(group); } foreach (var groupToSync in groupsToSync) { if (!groupToSync.NeedsSync && !force) { continue; } var groupToSyncAgent = groupToSync.Service as Agent; if (groupToSyncAgent == null) { continue; } if (!ServiceManager.IsRunning(groupToSync.Service)) { continue; } somethingSynced = true; try { ReSync: var syncTime = Time.GetNowUnixTimestamp(); var syncTask = groupToSyncAgent.Sync(groupToSync, Database.GetActionId(groupToSync)); syncTask.Wait(); var syncResult = syncTask.Result; if (!syncResult.EmptyResult && !syncResult.NullActionId && !syncResult.JustRefresh) { lock (BubbleGroupDatabase.OperationLock) { if (syncResult.ResultType == Result.Type.Purge) { if (BubbleGroupManager.LastBubbleSentTimestamps.ContainsKey(groupToSync.ID)) { lock (BubbleGroupManager.LastBubbleSentTimestamps) { var lastBubbleSentTime = BubbleGroupManager.LastBubbleSentTimestamps[groupToSync.ID]; if (lastBubbleSentTime >= syncTime) { Utils.DebugPrint("Sync has detected that a bubble was sent during the time the sync was fetched. Redoing sync..."); goto ReSync; } } } Utils.DebugPrint("Sync is purging the database for bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); BubbleGroupDatabase.Kill(groupToSync); } if (!syncResult.EmptyInserts) { Utils.DebugPrint("Sync is inserting " + syncResult.Inserts.Length + " bubbles into " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); if (syncResult.ResultType == Result.Type.Purge) { syncResult.Inserts.TimSort((x, y) => x.Time.CompareTo(y.Time)); BubbleGroupDatabase.AddBubbles(groupToSync, syncResult.Inserts); // If a purge is issued, then we need to carry over all sending bubbles to the new BubbleGroup being created. // Additionally, we need to remove any sending bubbles that are already on the insert list to avoid duplicates. var sendingBubbles = BubbleManager.FetchAllSending(groupToSync).ToList(); var sendingBubblesFiltered = new List <VisualBubble>(); foreach (var sendingBubble in sendingBubbles) { var hasInsertBubble = syncResult.Inserts.FirstOrDefault(x => x.ID == sendingBubble.ID) != null; if (!hasInsertBubble) { sendingBubblesFiltered.Add(sendingBubble); } } if (sendingBubblesFiltered.Any()) { BubbleGroupDatabase.InsertBubblesByTime(groupToSync, sendingBubblesFiltered.ToArray(), SearchDepth); } } else { BubbleGroupDatabase.InsertBubblesByTime(groupToSync, syncResult.Inserts, SearchDepth); } } if (!syncResult.EmptyUpdates) { Utils.DebugPrint("Sync is updating " + syncResult.Updates.Length + " bubbles into " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName); BubbleManager.Update(groupToSync, syncResult.Updates, SearchDepth); } } } else { Utils.DebugPrint("Sync for bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName + " returned an empty result (" + syncResult.ResultType.ToString() + ")."); } if (!syncResult.NullActionId) { Database.SetActionId(groupToSync, syncResult.NewActionId); } groupToSync.NeedsSync = false; } catch (Exception ex) { Utils.DebugPrint("Failed to sync bubble group " + groupToSync.ID + " on service " + groupToSync.Service.Information.ServiceName + ": " + ex); } } if (somethingSynced) { lock (BubbleGroupDatabase.OperationLock) { // Here we need to replace all the sending or downloading bubbles with the 'real' ones. // If this is never done, then on the UI, a 'sending' will never be set to 'sent', and any download // progress will never be updated. Why? Different memory objects. var sendingBubbles = BubbleManager.FetchAllSendingAndDownloading(group).ToList(); BubbleGroupFactory.UnloadFullLoad(group); BubbleGroupFactory.LoadFullyIfNeeded(group, true); if (sendingBubbles.Any()) { BubbleManager.Replace(group, sendingBubbles); } group.RaiseBubblesSynced(); } } } })); }
internal static async void UpdatePartyParticipants(BubbleGroup bubbleGroup, Action finished = null) { var service = bubbleGroup.Service; if (!ServiceManager.IsRunning(service)) { return; } if (!bubbleGroup.IsParty) { if (finished != null) { finished(); } return; } try { await service.GetBubbleGroupPartyParticipants(bubbleGroup, participants => { // we need to propogate the old participant photos to the new participant list var newParticipants = participants == null ? new List <DisaParticipant>() : participants.ToList(); foreach (var oldParticipant in bubbleGroup.Participants) { var newParticipant = newParticipants.FirstOrDefault(x => service.BubbleGroupComparer(x.Address, oldParticipant.Address)); if (newParticipant != null) { newParticipant.Photo = oldParticipant.Photo; newParticipant.IsPhotoSetFromService = oldParticipant.IsPhotoSetFromService; } } // move all unknown participants over foreach (var unknownParticipant in bubbleGroup.Participants.Where(x => x.Unknown)) { if (newParticipants.FirstOrDefault(x => service.BubbleGroupComparer(x.Address, unknownParticipant.Address)) == null) { newParticipants.Add(unknownParticipant); } } bubbleGroup.Participants = new ThreadSafeList <DisaParticipant>(newParticipants); bubbleGroup.IsParticipantsSetFromService = true; if (finished == null) { BubbleGroupEvents.RaiseBubblesUpdated(bubbleGroup); } else { finished(); } }); } catch (Exception ex) { Utils.DebugPrint("Error updating bubble group participants: " + service.Information.ServiceName + " - " + bubbleGroup.Address + ": " + ex); if (finished != null) { finished(); } } }
private static Task <bool> Send(Bubble b, BubbleGroup group, bool resend) { return(Task <bool> .Factory.StartNew(() => { var vb = b as VisualBubble; if (vb != null) { if (vb.Status == Bubble.BubbleStatus.Sent) { Utils.DebugPrint("Trying to send a bubble that is already sent! On " + vb.Service.Information.ServiceName); return true; } Func <bool> restartServiceIfNeeded = () => { if (!ServiceManager.IsRegistered(b.Service) || ServiceManager.IsRunning(b.Service) || ServiceManager.IsAborted(b.Service)) { return false; } Utils.DebugPrint( "For f***s sakes. The scheduler isn't doing it's job properly, or " + "you're sending a message to it at a weird time. Starting it up bra (" + b.Service.Information.ServiceName + ")."); ServiceManager.AbortAndRestart(b.Service); return true; }; var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId; if (vb.IdService == null && vb.IdService2 == null && visualBubbleServiceId != null) { visualBubbleServiceId.AddVisualBubbleIdServices(vb); } try { @group = Group(vb, resend, true); } catch (Exception ex) { Utils.DebugPrint("Problem in Send:GroupBubble from service " + vb.Service.Information.ServiceName + ": " + ex.Message); return false; } if (@group == null) { Utils.DebugPrint("Could not find a suitable group for bubble " + vb.ID + " on " + vb.Service.Information.ServiceName); return false; } var shouldQueue = vb.Service.QueuedBubblesParameters == null || !vb.Service.QueuedBubblesParameters.BubblesNotToQueue.Contains(vb.GetType()); try { if (shouldQueue && !resend && BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName, true, false)) { BubbleQueueManager.JustQueue(group, vb); restartServiceIfNeeded(); return false; } if (shouldQueue) { Monitor.Enter(vb.Service.SendBubbleLock); } using (var queued = new BubbleQueueManager.InsertBubble(group, vb, shouldQueue)) { Action checkForQueued = () => { if (!resend && BubbleQueueManager.HasQueuedBubbles(vb.Service.Information.ServiceName, true, true)) { BubbleQueueManager.Send(new [] { vb.Service.Information.ServiceName }); } }; try { FailBubbleIfPathDoesntExist(vb); SendBubbleInternal(b); } catch (ServiceQueueBubbleException ex) { Utils.DebugPrint("Queuing visual bubble on service " + vb.Service.Information.ServiceName + ": " + ex.Message); UpdateStatus(vb, Bubble.BubbleStatus.Waiting, @group); if (!restartServiceIfNeeded()) { checkForQueued(); } return false; } catch (Exception ex) { queued.CancelQueue(); Utils.DebugPrint("Visual bubble on " + vb.Service.Information.ServiceName + " failed to be sent: " + ex); UpdateStatus(vb, Bubble.BubbleStatus.Failed, @group); BubbleGroupEvents.RaiseBubbleFailed(vb, @group); if (!restartServiceIfNeeded()) { checkForQueued(); } //FIXME: if the bubble fails to send, allow the queue manager to continue. if (resend) { return true; } return false; } queued.CancelQueue(); lock (BubbleGroupManager.LastBubbleSentTimestamps) { BubbleGroupManager.LastBubbleSentTimestamps[group.ID] = Time.GetNowUnixTimestamp(); } if (vb.Status == Bubble.BubbleStatus.Delivered) { Utils.DebugPrint( "************ Race condition. The server set the status to delivered/read before we could send it to sent. :')"); checkForQueued(); return true; } UpdateStatus(vb, Bubble.BubbleStatus.Sent, @group); checkForQueued(); return true; } } finally { if (shouldQueue) { Monitor.Exit(vb.Service.SendBubbleLock); } } } else { var composeBubble = b as ComposeBubble; if (composeBubble != null) { var bubbleToSend = composeBubble.BubbleToSend; var visualBubbleServiceId = bubbleToSend.Service as IVisualBubbleServiceId; if (bubbleToSend.IdService == null && bubbleToSend.IdService2 == null && visualBubbleServiceId != null) { visualBubbleServiceId.AddVisualBubbleIdServices(bubbleToSend); } @group.InsertByTime(bubbleToSend); try { BubbleGroupEvents.RaiseBubbleInserted(bubbleToSend, @group); } catch { // do nothing } } try { SendBubbleInternal(b); } catch (ServiceBubbleGroupAddressException ex) { if (!String.IsNullOrWhiteSpace(ex.Address)) { if (composeBubble != null) { composeBubble.BubbleToSend.Address = ex.Address; composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Sent; var actualGroup = Group(composeBubble.BubbleToSend, resend, true); ServiceEvents.RaiseComposeFinished( @group as ComposeBubbleGroup, actualGroup); return true; } } composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed; return false; } catch (Exception ex) { Utils.DebugPrint("Failed to send bubble on service " + b.Service.Information.ServiceName); if (composeBubble != null) { composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed; } return false; } if (composeBubble != null) { composeBubble.BubbleToSend.Status = Bubble.BubbleStatus.Failed; return false; } return true; } })); }