Пример #1
0
        public static void Delete(BubbleGroup group)
        {
            lock (BubbleGroupDatabase.OperationLock)
            {
                var unifiedGroup = @group as UnifiedBubbleGroup;
                if (unifiedGroup != null)
                {
                    DeleteUnified(unifiedGroup);
                    return;
                }

                var file = BubbleGroupDatabase.GetLocation(@group);

                if (File.Exists(file))
                {
                    File.Delete(file);
                }

                BubbleGroupSync.RemoveFromSync(@group);

                BubbleGroupSync.DeleteBubbleGroupIfHasAgent(@group);

                BubbleGroupManager.BubbleGroupsRemove(@group);
            }
        }
Пример #2
0
        public void InsertByTime(VisualBubble b)
        {
            if (Bubbles.Count > BubblesCapSize)
            {
                Bubbles.RemoveAt(0);
            }

            for (int i = Bubbles.Count - 1; i >= 0; i--)
            {
                var nBubble = Bubbles[i];
                if (nBubble.Time <= b.Time)
                {
                    // adding it to the end, we can do a simple contract
                    if (i == Bubbles.Count - 1)
                    {
                        Bubbles.Add(b);
                        if (b.Direction == Bubble.BubbleDirection.Incoming)
                        {
                            BubbleGroupSettingsManager.SetUnread(this, true);
                        }
                    }
                    // inserting, do a full contract
                    else
                    {
                        Bubbles.Insert(i + 1, b);
                    }
                    break;
                }

                // could not find a valid place to insert, then skip insertion.
                if (i == 0)
                {
                    return;
                }
            }

            if (Unified == null)
            {
                _bubblesInsertedCount++;
                if (_bubblesInsertedCount % 100 == 0)
                {
                    if (BubbleGroupSync.SupportsSyncAndIsRunning(this))
                    {
                        Action doSync = async() =>
                        {
                            using (Platform.AquireWakeLock("DisaSync"))
                            {
                                await Utils.Delay(1000);

                                await BubbleGroupSync.Sync(this, true);
                            }
                        };
                        doSync();
                    }
                }
            }

            RaiseBubbleInserted(b);
            RaiseUnifiedBubblesUpdatedIfUnified(b);
        }
Пример #3
0
        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);
        }
Пример #4
0
        public static Task Start(Service service, bool smartStart = false, int smartStartSeconds = 10)
        {
            return(Task.Factory.StartNew(() =>
            {
                using (var wakeLock = Platform.AquireWakeLock("DisaStart"))
                {
                    if (IsRunning(service))
                    {
                        Utils.DebugPrint(
                            "The service is already running. Preventing possible deadlock. SmartStart? " +
                            smartStart);
                        return;
                    }

                    if (IsStarting(service))
                    {
                        Utils.DebugPrint(
                            "The service is being started. Preventing possible deadlock. SmartStart? " +
                            smartStart);
                        return;
                    }

                    Action epilogue = () => { GetFlags(service).Starting = false; };

                    lock (service)
                    {
                        GetFlags(service).Aborted = false;
                        GetFlags(service).AbortedSpecial = false;
                        GetFlags(service).Starting = true;
                        GetFlags(service).ManualSettingsNeeded = false;

                        Utils.DebugPrint("Loading settings for service " + service.Information.ServiceName);
                        try
                        {
                            var settings = SettingsManager.Load(service);
                            if (settings == null)
                            {
                                Utils.DebugPrint("Failed to load saved settings for "
                                                 + service.Information.ServiceName +
                                                 ". Will try to initialize with no settings...");
                                if (!service.InitializeDefault())
                                {
                                    Utils.DebugPrint(
                                        "Service doesn't allow initializing without settings. Needs manual input.");
                                    GetFlags(service).ManualSettingsNeeded = true;
                                    ServiceEvents.RaiseServiceManualSettingsNeeded(service);
                                }
                                else
                                {
                                    Utils.DebugPrint("Service initialized under no settings.");
                                }
                            }
                            else
                            {
                                Utils.DebugPrint("Loading saved settings! Initializing...");
                                if (service.Initialize(settings))
                                {
                                    Utils.DebugPrint("Successfully initialized service!");
                                }
                                else
                                {
                                    Utils.DebugPrint("Failed to initialize service. Needs manual input.");
                                    GetFlags(service).ManualSettingsNeeded = true;
                                    ServiceEvents.RaiseServiceManualSettingsNeeded(service);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Utils.DebugPrint("Failed: " + ex);
                            epilogue();
                            return;
                        }

                        Utils.DebugPrint("Starting service " + service.Information.ServiceName);

                        try
                        {
                            if (service.Information.UsesInternet &&
                                !Platform.HasInternetConnection())
                            {
                                throw new Exception("No internet connection. Cannot connect service: "
                                                    + service.Information.ServiceName);
                            }

                            StartInternal(service, wakeLock);
                        }
                        catch (ServiceSchedulerException ex)
                        {
                            Utils.DebugPrint("Problem in scheduler: " + ex.Message);
                            epilogue();
                            return;
                        }
                        catch (ServiceSpecialRestartException)
                        {
                            Utils.DebugPrint("Service " + service.Information.ServiceName +
                                             " is asking to be restarted on connect/authenticate. This should be called sparingly, Disa can easily " +
                                             "break under these circumstances. Restarting...");
                            StopInternal(service);
                            epilogue();
                            Start(service, smartStart, smartStartSeconds);
                            return;
                        }
                        catch (ServiceExpiredException)
                        {
                            Utils.DebugPrint("The service " + service.Information.ServiceName +
                                             " has expired. :(");
                            GetFlags(service).Aborted = true;
                            GetFlags(service).Expired = true;
                            ServiceEvents.RaiseServiceExpired(service);
                            StopInternal(service);
                            epilogue();
                            return;
                        }
                        catch (Exception ex)
                        {
                            if (smartStart)
                            {
                                StopInternal(service, false);

                                if (smartStartSeconds > 600)
                                {
                                    Utils.DebugPrint("Service " + service.Information.ServiceName +
                                                     " needs to wait over 10minutes to be restarted." +
                                                     " Killing SmartStart. The service will not be restarted. Reason: " + ex);
                                    epilogue();
                                    return;
                                }

                                Utils.DebugPrint("Service " + service.Information.ServiceName +
                                                 " failed to be started. SmartStart enabled. "
                                                 + "Service being scheduled to be re-started in T-" +
                                                 smartStartSeconds + " seconds! Reason: " + ex);

                                var hasSmartStart = new object();
                                service.HasSmartStart = hasSmartStart;

                                Platform.ScheduleAction(smartStartSeconds,
                                                        new WakeLockBalancer.ActionObject(() =>
                                {
                                    if (IsAborted(service))
                                    {
                                        Utils.DebugPrint(
                                            "Service " +
                                            service.Information
                                            .ServiceName +
                                            " tried to be started, but it deemed killed.");
                                        return;
                                    }

                                    if (service.HasSmartStart !=
                                        hasSmartStart)
                                    {
                                        Utils.DebugPrint(
                                            "This smart start has been invalidated. There " +
                                            "seems to be another one on the block.");
                                        return;
                                    }

                                    Utils.DebugPrint(
                                        "Smart start is firing the service " +
                                        service.Information
                                        .ServiceName +
                                        " up again!");

                                    StopInternal(service);
                                    Start(service, true, smartStartSeconds * 2);
                                }, WakeLockBalancer.ActionObject.ExecuteType.TaskWithWakeLock));

                                epilogue();
                                return;
                            }

                            Utils.DebugPrint("Failed to start service " + service.Information.ServiceName +
                                             " (No SmartStart) : " + ex);
                            StopInternal(service, false);
                            epilogue();
                            return;
                        }

                        BubbleManager.SendSubscribe(service, true);
                        BubbleManager.SendLastPresence(service);

                        service.ReceivingBubblesThread = new Thread(() =>
                        {
                            try
                            {
                                StartReceiveBubbles(service);
                            }
                            catch (ThreadAbortException)
                            {
                                Utils.DebugPrint(
                                    "Abort thread excepton in receiving bubbles on service (outer thread) " +
                                    service.Information.ServiceName);
                            }
                            catch (Exception ex)
                            {
                                Utils.DebugPrint(">>>>>>>>> " + ex.Message + " " + ex.StackTrace);
                            }
                            Utils.DebugPrint("Receiving bubbles for service " +
                                             service.Information.ServiceName + " has come to an end.");
                        });
                        service.ReceivingBubblesThread.Start();

                        GetFlags(service).Starting = false;

                        BubbleManager.SetNotQueuedToFailures(service);

                        Utils.Delay(1000).ContinueWith(x =>
                        {
                            BubbleGroupSync.ResetSyncsIfHasAgent(service);
                            BubbleGroupUpdater.Update(service);
                            BubbleQueueManager.Send(new[] { service.Information.ServiceName });
                            BubbleGroupManager.ProcessUpdateLastOnlineQueue(service);
                        });
                    }
                }
            }));
        }
Пример #5
0
        public void InsertByTime(VisualBubble b)
        {
            if (Bubbles.Count >= BubblesCapSize)
            {
                Bubbles.RemoveAt(0);
            }

            if (!(this is ComposeBubbleGroup))
            {
                var unreadIndicatorGuid = BubbleGroupSettingsManager.GetUnreadIndicatorGuid(this);
                for (int i = Bubbles.Count - 1; i >= 0; i--)
                {
                    var nBubble = Bubbles[i];

                    var unreadIndicatorIndex = -1;
                    if (unreadIndicatorGuid != null && unreadIndicatorGuid == nBubble.ID)
                    {
                        unreadIndicatorIndex = i;
                    }

                    // IMPORTANT: Our Time field is specified in seconds, however scenarios are appearing
                    //            (e.g., bots) where messages are sent in on the same second but still require
                    //            proper ordering. In this case, Services may set a flag specifying a fallback
                    //            to the ID assigned by the Service (e.g. Telegram).
                    if ((nBubble.Time == b.Time) &&
                        (nBubble.IsServiceIdSequence && b.IsServiceIdSequence))
                    {
                        if (string.Compare(
                                strA: nBubble.IdService,
                                strB: b.IdService,
                                ignoreCase: false,
                                culture: CultureInfo.InvariantCulture) < 0)
                        {
                            //
                            // Incoming bubble must be placed AFTER current bubble we are evaluating
                            //

                            if (i == Bubbles.Count - 1)
                            {
                                Bubbles.Add(b);
                                if (b.Direction == Bubble.BubbleDirection.Incoming)
                                {
                                    BubbleGroupSettingsManager.SetUnread(this, true);
                                }
                            }
                            else
                            {
                                Bubbles.Insert(i + 1, b);
                                if (i >= unreadIndicatorIndex && b.Direction == Bubble.BubbleDirection.Outgoing)
                                {
                                    BubbleGroupSettingsManager.SetUnreadIndicatorGuid(this, b.ID, false);
                                }
                            }
                        }
                        else
                        {
                            //
                            // Incoming bubble must be placed BEFORE current bubble we are evaluating
                            //

                            Bubbles.Insert(i, b);
                            if (i >= unreadIndicatorIndex && b.Direction == Bubble.BubbleDirection.Outgoing)
                            {
                                BubbleGroupSettingsManager.SetUnreadIndicatorGuid(this, b.ID, false);
                            }
                        }
                        break;
                    }
                    // OK, simpler scenario, incoming bubble must be placed AFTER current bubble we are evaluating
                    else if (nBubble.Time <= b.Time)
                    {
                        // adding it to the end, we can do a simple contract
                        if (i == Bubbles.Count - 1)
                        {
                            Bubbles.Add(b);
                            if (b.Direction == Bubble.BubbleDirection.Incoming)
                            {
                                BubbleGroupSettingsManager.SetUnread(this, true);
                            }
                        }
                        // inserting, do a full contract
                        else
                        {
                            Bubbles.Insert(i + 1, b);
                        }
                        if (i >= unreadIndicatorIndex && b.Direction == Bubble.BubbleDirection.Outgoing)
                        {
                            BubbleGroupSettingsManager.SetUnreadIndicatorGuid(this, b.ID, false);
                        }
                        break;
                    }

                    // could not find a valid place to insert, then skip insertion.
                    if (i == 0)
                    {
                        return;
                    }
                }
            }

            if (Unified == null)
            {
                _bubblesInsertedCount++;
                if (_bubblesInsertedCount % 100 == 0)
                {
                    if (BubbleGroupSync.SupportsSyncAndIsRunning(this))
                    {
                        Action doSync = async() =>
                        {
                            using (Platform.AquireWakeLock("DisaSync"))
                            {
                                await Utils.Delay(1000);

                                await BubbleGroupSync.Sync(this, true);
                            }
                        };
                        doSync();
                    }
                }
            }

            RaiseBubbleInserted(b);
            RaiseUnifiedBubblesUpdatedIfUnified(b);
        }