public static UnifiedBubbleGroup CreateUnified(List <BubbleGroup> groups, BubbleGroup primaryGroup) { lock (BubbleGroupDatabase.OperationLock) { var unifiedGroupsToKill = new HashSet <UnifiedBubbleGroup>(); foreach (var group in groups) { if (group.IsUnified) { unifiedGroupsToKill.Add(group.Unified); @group.DeregisterUnified(); } } foreach (var unifiedGroup in unifiedGroupsToKill) { BubbleGroupManager.BubbleGroupsRemove(unifiedGroup); } UnifiedBubbleGroupsDatabase.Remove(unifiedGroupsToKill); var unified = CreateUnifiedInternal(groups, primaryGroup); UnifiedBubbleGroupsDatabase.Add(unified, new DisaUnifiedBubbleGroupEntry(unified.ID, unified.Groups.Select(innerGroup => innerGroup.ID) .ToArray(), primaryGroup.ID, primaryGroup.ID)); BubbleGroupManager.BubbleGroupsAdd(unified); return(unified); } }
public static UnifiedBubbleGroup CreateUnified(List <BubbleGroup> groups, BubbleGroup primaryGroup) { lock (BubbleGroupDatabase.OperationLock) { var unifiedGroupsToKill = new HashSet <UnifiedBubbleGroup>(); foreach (var group in groups) { if (group.IsUnified) { unifiedGroupsToKill.Add(group.Unified); @group.DeregisterUnified(); } } foreach (var unifiedGroup in unifiedGroupsToKill) { BubbleGroupManager.BubbleGroupsRemove(unifiedGroup); } BubbleGroupIndex.RemoveUnified(unifiedGroupsToKill.Select(x => x.ID).ToArray()); var unified = CreateUnifiedInternal(groups, primaryGroup); BubbleGroupIndex.AddUnified(unified); BubbleGroupManager.BubbleGroupsAdd(unified); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(unified, unified.LastBubbleSafe().ID, false); return(unified); } }
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); }
internal static BubbleGroup Group(VisualBubble vb, bool resend = false, bool insertAtBottom = false) { lock (BubbleGroupDatabase.OperationLock) { Utils.DebugPrint("Grouping an " + vb.Direction + " bubble on service " + vb.Service.Information.ServiceName); var theGroup = BubbleGroupManager.FindWithAddress(vb.Service, vb.Address); BubbleGroupFactory.LoadFullyIfNeeded(theGroup); var duplicate = false; var newGroup = false; if (theGroup == null) { Utils.DebugPrint(vb.Service.Information.ServiceName + " unable to find suitable group. Creating a new one."); theGroup = new BubbleGroup(vb, null, false); newGroup = true; Utils.DebugPrint("GUID of new group: " + theGroup.ID); vb.Service.NewBubbleGroupCreated(theGroup).ContinueWith(x => { // force the UI to refetch the photo theGroup.IsPhotoSetFromService = false; SendSubscribe(theGroup, true); BubbleGroupUpdater.Update(theGroup); }); BubbleGroupManager.BubbleGroupsAdd(theGroup); } else { if (resend) { if (vb.Status == Bubble.BubbleStatus.Failed) { UpdateStatus(vb, Bubble.BubbleStatus.Waiting, theGroup); } return(theGroup); } var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId; if (visualBubbleServiceId != null && visualBubbleServiceId.DisctinctIncomingVisualBubbleIdServices()) { if (vb.IdService != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService == vb.IdService) != null; } if (!duplicate && vb.IdService2 != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService2 == vb.IdService2) != null; } } if (!duplicate) { Utils.DebugPrint(vb.Service.Information.ServiceName + " found a group. Adding."); if (insertAtBottom) { var lastBubble = theGroup.LastBubbleSafe(); if (lastBubble.Time > vb.Time) { vb.Time = lastBubble.Time; } } theGroup.InsertByTime(vb); } else { Utils.DebugPrint("Yuck. It's a duplicate bubble. No need to readd: " + vb.IdService + ", " + vb.IdService2); } } if (!duplicate) { Utils.DebugPrint("Inserting bubble into database group!"); try { if (newGroup) { BubbleGroupDatabase.AddBubble(theGroup, vb); } else { BubbleGroupDatabase.InsertBubbleByTime(theGroup, vb); } } catch (Exception ex) { Utils.DebugPrint("Bubble failed to be inserting/added into the group " + theGroup.ID + ": " + ex); } try { BubbleGroupEvents.RaiseBubbleInserted(vb, theGroup); } catch (Exception ex) { Utils.DebugPrint( "Error in notifying the interface that the bubble group has been updated (" + vb.Service.Information.ServiceName + "): " + ex.Message); } } return(theGroup); } }
internal static BubbleGroup Group(VisualBubble vb, bool resend = false, bool insertAtBottom = false) { lock (BubbleGroupDatabase.OperationLock) { Utils.DebugPrint("Grouping an " + vb.Direction + " bubble on service " + vb.Service.Information.ServiceName); var theGroup = BubbleGroupManager.FindWithAddress(vb.Service, vb.Address); BubbleGroupFactory.LoadFullyIfNeeded(theGroup); var duplicate = false; var newGroup = false; if (theGroup == null) { Utils.DebugPrint(vb.Service.Information.ServiceName + " unable to find suitable group. Creating a new one."); theGroup = new BubbleGroup(vb, null, false); newGroup = true; Utils.DebugPrint("GUID of new group: " + theGroup.ID); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(theGroup, theGroup.LastBubbleSafe().ID, true); vb.Service.NewBubbleGroupCreated(theGroup).ContinueWith(x => { // force the UI to refetch the photo theGroup.IsPhotoSetFromService = false; SendSubscribe(theGroup, true); BubbleGroupUpdater.Update(theGroup); }); BubbleGroupManager.BubbleGroupsAdd(theGroup); } else { if (resend) { if (vb.Status == Bubble.BubbleStatus.Failed) { UpdateStatus(vb, Bubble.BubbleStatus.Waiting, theGroup); } return(theGroup); } var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId; if (visualBubbleServiceId != null && visualBubbleServiceId.DisctinctIncomingVisualBubbleIdServices()) { if (vb.IdService != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService == vb.IdService) != null; } if (!duplicate && vb.IdService2 != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => x.GetType() == vb.GetType() && x.IdService2 == vb.IdService2) != null; } } if (!duplicate) { Utils.DebugPrint(vb.Service.Information.ServiceName + " found a group. Adding."); if (insertAtBottom) { var lastBubble = theGroup.LastBubbleSafe(); if (lastBubble.Time > vb.Time) { vb.Time = lastBubble.Time; } } theGroup.InsertByTime(vb); } else { Utils.DebugPrint("Yuck. It's a duplicate bubble. No need to readd: " + vb.IdService + ", " + vb.IdService2); } } try { if (theGroup.IsParty && !string.IsNullOrWhiteSpace(vb.ParticipantAddressNickname)) { var participantAddressNicknamesArray = theGroup.ParticipantNicknames; if (participantAddressNicknamesArray == null) { participantAddressNicknamesArray = new DisaParticipantNickname[0]; } var participantAddressNicknames = participantAddressNicknamesArray.ToList(); var changed = false; var adding = true; foreach (var participantAddressNickname in participantAddressNicknames) { if (theGroup.Service.BubbleGroupComparer(participantAddressNickname.Address, vb.ParticipantAddress)) { if (participantAddressNickname.Nickname != vb.ParticipantAddressNickname) { participantAddressNickname.Nickname = vb.ParticipantAddressNickname; changed = true; } adding = false; break; } } if (adding) { participantAddressNicknames.Add(new DisaParticipantNickname { Address = vb.ParticipantAddress, Nickname = vb.ParticipantAddressNickname, }); } if (changed || adding) { theGroup.ParticipantNicknames = participantAddressNicknames.ToArray(); } } } catch (Exception ex) { Utils.DebugPrint("Failed to insert/update participant nickname into cache: " + ex); } if (!duplicate) { Utils.DebugPrint("Inserting bubble into database group!"); try { if (newGroup) { BubbleGroupDatabase.AddBubble(theGroup, vb); } else { BubbleGroupDatabase.InsertBubbleByTime(theGroup, vb); } } catch (Exception ex) { Utils.DebugPrint("Bubble failed to be inserting/added into the group " + theGroup.ID + ": " + ex); } try { BubbleGroupEvents.RaiseBubbleInserted(vb, theGroup); } catch (Exception ex) { Utils.DebugPrint( "Error in notifying the interface that the bubble group has been updated (" + vb.Service.Information.ServiceName + "): " + ex.Message); } } return(theGroup); } }
private static bool LoadInternal(SqlDatabase <Entry> db) { var entries = GetAllEntries(db); if (entries == null) { return(false); } var bubbleGroupsActualCount = Directory.GetFiles(BubbleGroupDatabase.GetBaseLocation(), "*.*", SearchOption.AllDirectories).Length; var entriesCount = entries.Count(x => !x.Unified); if (!(bubbleGroupsActualCount > entriesCount - 5 && bubbleGroupsActualCount < entriesCount + 5)) { Utils.DebugPrint("Actual count does not match index count (+-5 tolerance). We'll have to re-generate index."); return(false); } foreach (var entry in entries) { if (entry.Unified) { continue; } var service = ServiceManager.GetByName(entry.Service); if (service != null) { var mostRecentVisualBubble = DeserializeBubble(entry.LastBubble); mostRecentVisualBubble.Service = service; mostRecentVisualBubble.ID = entry.LastBubbleGuid; var bubbleGroup = new BubbleGroup(mostRecentVisualBubble, entry.Guid, true); BubbleGroupManager.BubbleGroupsAdd(bubbleGroup, true); } else { Utils.DebugPrint("Could not obtain a valid service object from " + entry.Id + " (" + entry.Service + ")"); } } foreach (var entry in entries) { if (!entry.Unified) { continue; } var innerGroups = new List <BubbleGroup>(); var innerGroupsIds = entry.UnifiedBubbleGroupsGuids.Split(','); if (innerGroupsIds != null) { foreach (var innerGroupId in innerGroupsIds) { var innerGroup = BubbleGroupManager.Find(innerGroupId); if (innerGroup == null) { Utils.DebugPrint("Unified group, inner group " + innerGroupId + " could not be related."); } else { innerGroups.Add(innerGroup); } } } if (!innerGroups.Any()) { Utils.DebugPrint("This unified group has no inner groups. Skipping this unified group."); continue; } var primaryGroup = innerGroups.FirstOrDefault(x => x.ID == entry.UnifiedPrimaryBubbleGroupGuid); if (primaryGroup == null) { Utils.DebugPrint("Unified group, primary group " + entry.UnifiedPrimaryBubbleGroupGuid + " could not be related. Skipping this unified group."); continue; } var id = entry.Guid; var unifiedGroup = BubbleGroupFactory.CreateUnifiedInternal(innerGroups, primaryGroup, id); var sendingGroup = innerGroups.FirstOrDefault(x => x.ID == entry.UnifiedSendingBubbleGroupGuid); if (sendingGroup != null) { unifiedGroup._sendingGroup = sendingGroup; } BubbleGroupManager.BubbleGroupsAdd(unifiedGroup, true); } return(true); }
internal static void LoadAllPartiallyIfPossible(int bubblesPerGroup = 100) { var corruptedGroups = new List <string>(); var bubbleGroupsLocations = Directory.GetFiles(BubbleGroupDatabase.GetBaseLocation(), "*.*", SearchOption.AllDirectories); var bubbleGroupsLocationsSorted = bubbleGroupsLocations.OrderByDescending(x => Time.GetUnixTimestamp(File.GetLastWriteTime(x))).ToList(); foreach (var bubbleGroupLocation in bubbleGroupsLocationsSorted) { String groupId = null; try { var groupHeader = Path.GetFileNameWithoutExtension(bubbleGroupLocation); var groupDelimeter = groupHeader.IndexOf("^", StringComparison.Ordinal); var serviceName = groupHeader.Substring(0, groupDelimeter); groupId = groupHeader.Substring(groupDelimeter + 1); var service = ServiceManager.GetByName(serviceName); if (service == null) { Utils.DebugPrint("Service " + serviceName + " not found in AllServices!"); continue; } var deserializedBubbleGroup = LoadPartiallyIfPossible(bubbleGroupLocation, service, groupId, bubblesPerGroup); if (deserializedBubbleGroup == null) { throw new Exception("DeserializedBubbleGroup is nothing."); } BubbleGroupManager.BubbleGroupsAdd(deserializedBubbleGroup); } catch (Exception ex) { Utils.DebugPrint("Group " + bubbleGroupLocation + " is corrupt. Deleting. " + ex); File.Delete(bubbleGroupLocation); if (groupId != null) { corruptedGroups.Add(groupId); } } } var migrationResaveNeeded = false; var corruptedUnifiedGroups = new List <SimpleDatabase <UnifiedBubbleGroup, DisaUnifiedBubbleGroupEntry> .Container>(); var removeFromRuntime = new List <SimpleDatabase <UnifiedBubbleGroup, DisaUnifiedBubbleGroupEntry> .Container>(); foreach (var group in UnifiedBubbleGroupsDatabase) { var innerGroupCorrupt = false; var innerGroups = new List <BubbleGroup>(); foreach (var innerGroupId in @group.Serializable.GroupIds) { var innerGroup = BubbleGroupManager.Find(innerGroupId); if (innerGroup == null) { Utils.DebugPrint("Unified group, inner group " + innerGroupId + " could not be related."); if (corruptedGroups.Contains(innerGroupId)) { Utils.DebugPrint( "It was detected that this inner group was corrupted and deleted. Will delete unified group."); innerGroupCorrupt = true; corruptedUnifiedGroups.Add(@group); } } else { innerGroups.Add(innerGroup); } } if (!innerGroups.Any()) { Utils.DebugPrint("Yuck. This unified group has no inner groups. Removing from runtime."); removeFromRuntime.Add(@group); continue; } if (innerGroupCorrupt) { continue; } var primaryGroup = innerGroups.FirstOrDefault(x => x.ID == @group.Serializable.PrimaryGroupId); if (primaryGroup == null) { Utils.DebugPrint("Unified group, primary group " + @group.Serializable.PrimaryGroupId + " could not be related. Removing from runtime."); removeFromRuntime.Add(@group); continue; } var id = @group.Serializable.Id; var unifiedGroup = CreateUnifiedInternal(innerGroups, primaryGroup, id); if (id == null) { migrationResaveNeeded = true; @group.Serializable.Id = unifiedGroup.ID; } var sendingGroup = innerGroups.FirstOrDefault(x => x.ID == @group.Serializable.SendingGroupId); if (sendingGroup != null) { unifiedGroup.SendingGroup = sendingGroup; } @group.Object = unifiedGroup; BubbleGroupManager.BubbleGroupsAdd(unifiedGroup); } if (removeFromRuntime.Any()) { foreach (var group in removeFromRuntime) { UnifiedBubbleGroupsDatabase.Remove(@group); } } if (corruptedUnifiedGroups.Any()) { foreach (var group in corruptedUnifiedGroups) { UnifiedBubbleGroupsDatabase.Remove(@group); } } if (migrationResaveNeeded) { Utils.DebugPrint("It was detected that we need to save migration changes for UnifiedBubbleGroups."); UnifiedBubbleGroupsDatabase.SaveChanges(); } try { foreach (var groupCache in BubbleGroupCacheManager.Load()) { var associatedGroup = BubbleGroupManager.Find(groupCache.Guid); if (associatedGroup == null) { continue; } var unifiedGroup = associatedGroup as UnifiedBubbleGroup; if (unifiedGroup != null) { associatedGroup = unifiedGroup.PrimaryGroup; } associatedGroup.Title = groupCache.Name; associatedGroup.Photo = groupCache.Photo; associatedGroup.IsPhotoSetInitiallyFromCache = true; if (groupCache.Participants != null) { associatedGroup.Participants = groupCache.Participants.ToSynchronizedCollection(); foreach (var participant in associatedGroup.Participants) { participant.IsPhotoSetInitiallyFromCache = true; } } } } catch (Exception ex) { Utils.DebugPrint("Failed to load bubble groups!: " + ex); } BubbleGroupSettingsManager.Load(); }
internal static BubbleGroup Group(VisualBubble vb, bool resend = false, bool insertAtBottom = false) { lock (BubbleGroupDatabase.OperationLock) { Utils.DebugPrint("Grouping an " + vb.Direction + " bubble on service " + vb.Service.Information.ServiceName); AddUrlMarkupIfNeeded(vb); var theGroup = BubbleGroupManager.FindWithAddress(vb.Service, vb.Address); BubbleGroupFactory.LoadFullyIfNeeded(theGroup); var duplicate = false; var newGroup = false; if (theGroup == null) { Utils.DebugPrint(vb.Service.Information.ServiceName + " unable to find suitable group. Creating a new one."); theGroup = new BubbleGroup(vb, null, false); newGroup = true; Utils.DebugPrint("GUID of new group: " + theGroup.ID); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(theGroup, theGroup.LastBubbleSafe().ID, true); vb.Service.NewBubbleGroupCreated(theGroup).ContinueWith(x => { // force the UI to refetch the photo theGroup.IsPhotoSetFromService = false; SendSubscribe(theGroup, true); BubbleGroupUpdater.Update(theGroup); }); BubbleGroupManager.BubbleGroupsAdd(theGroup); } else { if (resend) { if (vb.Status == Bubble.BubbleStatus.Failed) { UpdateStatus(vb, Bubble.BubbleStatus.Waiting, theGroup); } return(theGroup); } // Does the Service for this VisualBubble require that the VisualBubble's IdService and IdService2 // be distinct? var visualBubbleServiceId = vb.Service as IVisualBubbleServiceId; if (visualBubbleServiceId != null && visualBubbleServiceId.DisctinctIncomingVisualBubbleIdServices()) { // Ok, we need to be distinct, BUT do the VisualBubble Type's have to be distinct as well? var checkType = true; if (!DisaFrameworkMethods.Missing(vb.Service, DisaFrameworkMethods.IVisualBubbleServiceIdCheckType)) { checkType = visualBubbleServiceId.CheckType(); } // Ok, now does the Service have special additional logic it wants to use for the distinction comparison? // Example: For Telegram, we allow an ImageBubble immediately followed by a TextBubble to have the // same VisualBubble.IdService - as this represents an image with a caption in Telegram. if (DisaFrameworkMethods.Missing(vb.Service, DisaFrameworkMethods.IVisualBubbleServiceIdVisualBubbleIdComparer)) { // Normal distinction checks if (vb.IdService != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => (!checkType || x.GetType() == vb.GetType()) && x.IdService == vb.IdService) != null; } if (!duplicate && vb.IdService2 != null) { duplicate = theGroup.Bubbles.FirstOrDefault(x => (!checkType || x.GetType() == vb.GetType()) && x.IdService2 == vb.IdService2) != null; } } else { // Special additional Service defined distinction checks if (vb.IdService != null) { var duplicateBubble = theGroup.Bubbles.FirstOrDefault(x => (!checkType || x.GetType() == vb.GetType()) && x.IdService == vb.IdService); duplicate = duplicateBubble == null ? false : visualBubbleServiceId.VisualBubbleIdComparer(left: duplicateBubble, right: vb); } if (!duplicate && vb.IdService2 != null) { var duplicateBubble = theGroup.Bubbles.FirstOrDefault(x => (!checkType || x.GetType() == vb.GetType()) && x.IdService2 == vb.IdService2); duplicate = duplicateBubble == null ? false : visualBubbleServiceId.VisualBubbleIdComparer(duplicateBubble, vb); } } } if (!duplicate) { Utils.DebugPrint(vb.Service.Information.ServiceName + " found a group. Adding."); if (insertAtBottom) { var lastBubble = theGroup.LastBubbleSafe(); if (lastBubble.Time > vb.Time) { vb.Time = lastBubble.Time; } } theGroup.InsertByTime(vb); } else { Utils.DebugPrint("Yuck. It's a duplicate bubble. No need to readd: " + vb.IdService + ", " + vb.IdService2); } } try { if (theGroup.IsParty && !string.IsNullOrWhiteSpace(vb.ParticipantAddressNickname)) { var participantAddressNicknamesArray = theGroup.ParticipantNicknames; if (participantAddressNicknamesArray == null) { participantAddressNicknamesArray = new DisaParticipantNickname[0]; } var participantAddressNicknames = participantAddressNicknamesArray.ToList(); var changed = false; var adding = true; foreach (var participantAddressNickname in participantAddressNicknames) { if (theGroup.Service.BubbleGroupComparer(participantAddressNickname.Address, vb.ParticipantAddress)) { if (participantAddressNickname.Nickname != vb.ParticipantAddressNickname) { participantAddressNickname.Nickname = vb.ParticipantAddressNickname; changed = true; } adding = false; break; } } if (adding) { participantAddressNicknames.Add(new DisaParticipantNickname { Address = vb.ParticipantAddress, Nickname = vb.ParticipantAddressNickname, }); } if (changed || adding) { theGroup.ParticipantNicknames = participantAddressNicknames.ToArray(); } } } catch (Exception ex) { Utils.DebugPrint("Failed to insert/update participant nickname into cache: " + ex); } if (!duplicate) { Utils.DebugPrint("Inserting bubble into database group!"); try { if (newGroup) { BubbleGroupDatabase.AddBubble(theGroup, vb); } else { BubbleGroupDatabase.InsertBubbleByTime(theGroup, vb); } } catch (Exception ex) { Utils.DebugPrint("Bubble failed to be inserting/added into the group " + theGroup.ID + ": " + ex); } try { BubbleGroupEvents.RaiseBubbleInserted(vb, theGroup); } catch (Exception ex) { Utils.DebugPrint( "Error in notifying the interface that the bubble group has been updated (" + vb.Service.Information.ServiceName + "): " + ex.Message); } } return(theGroup); } }