public static void Save(Service service, DisaSettings settings) { lock (Lock) { var path = GetPath(service); bool settingsFileExists = File.Exists(path); MemoryStream sw2; using (var sw = new MemoryStream()) { Save(sw, service.Information.Settings, settings); sw2 = sw; } if (sw2 != null) { File.WriteAllBytes(path, sw2.ToArray()); ServiceEvents.RaiseSettingsSaved(service); } if (!settingsFileExists) { Analytics.RaiseServiceEvent( Analytics.EventAction.ServiceSetup, Analytics.EventCategory.Services, service); } } }
public static void Unregister(Service service) { if (!IsRegistered(service)) { throw new ServiceSchedulerException("Service " + service.Information.ServiceName + " is not registered!"); } lock (ServicesBindings) ServicesBindings.Remove(ServicesBindings.FirstOrDefault(s => s.Service == service)); ServiceEvents.RaiseServiceUnRegistered(service); }
public static void Unregister(Service service) { if (!IsRegistered(service)) { throw new ServiceSchedulerException("Service " + service.Information.ServiceName + " is not registered!"); } lock (ServicesBindings) ServicesBindings.Remove(ServicesBindings.FirstOrDefault(s => s.Service == service)); ServiceEvents.RaiseServiceUnRegistered(service); SettingsChangedManager.SetNeedsContactSync(service, true); Analytics.RaiseServiceEvent( Analytics.EventAction.ServiceUnregistered, Analytics.EventCategory.Services, service); }
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); }); } } })); }
private static void StartInternal(Service registeredService, WakeLock wakeLock) { if (IsManualSettingsNeeded(registeredService)) { throw new ServiceSchedulerException("Service " + registeredService.Information.ServiceName + " needs manual input for settings."); } if (!IsRegistered(registeredService)) { throw new ServiceSchedulerException("Could not locate service " + registeredService.Information.ServiceName + ". Are you sure you registered it?"); } if (IsRunning(registeredService)) { throw new ServiceSchedulerException(registeredService.Information.ServiceName + " service is already running."); } ClearFailures(registeredService); ServiceEvents.RaiseServiceSettingsLoaded(registeredService); Action connect = () => { try { registeredService.Connect(wakeLock); } catch (NotImplementedException) { } catch (ServiceSpecialRestartException) { throw; } catch (Exception ex) { GetFlags(registeredService).ConnectionFailed = true; throw new Exception("Service " + registeredService.Information.ServiceName + " flat out failed to connect. Problem: " + ex); } }; Action authenticate = () => { try { var authSuccess = registeredService.Authenticate(wakeLock); if (!authSuccess) { throw new Exception("Failed authentication " + registeredService.Information.ServiceName + "."); } } catch (NotImplementedException) { } catch (ServiceSpecialRestartException) { throw; } catch (ServiceExpiredException) { throw; } catch (Exception ex) { GetFlags(registeredService).AuthenticationFailed = true; throw new Exception("Service " + registeredService.Information.ServiceName + " flat out failed to authenticate. Problem: " + ex); } }; if (registeredService.Information.Procedure == ServiceInfo.ProcedureType.AuthenticateConnect) { authenticate(); connect(); } else if (registeredService.Information.Procedure == ServiceInfo.ProcedureType.ConnectAuthenticate) { connect(); authenticate(); } GetFlags(registeredService).Running = true; ServiceEvents.RaiseServiceStarted(registeredService); }
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; } })); }
public static void OnPhoneContactsUpdated() { Task.Factory.StartNew(() => { if (_isUpdating) { Utils.DebugPrint("Contacts are already updating... Returning..."); return; } Action action = () => { lock (PhoneBookContactsLock) { using (new PhoneContactsUpdatingDisposable()) { if (_phoneBookContacts == null) { Utils.DebugPrint("Phone contacts have not yet been used by the framework/services. Therefore, and update doesn't make sense. Skipping."); return; } Utils.DebugPrint("Phone contacts have been updated! Querying phone contacts..."); var updatedPhoneContacts = Platform.GetPhoneBookContacts(); Utils.DebugPrint("Checking if any numbers/names have been updated..."); var updatedPhoneContactsNumbers = (from phoneBookRelation in updatedPhoneContacts from phoneNumber in phoneBookRelation.PhoneNumbers select phoneNumber.Number).ToList(); var phoneBookContactsNumbers = (from phoneBookRelation in _phoneBookContacts from phoneNumber in phoneBookRelation.PhoneNumbers select phoneNumber.Number).ToList(); var updatedPhoneContactsFullName = (from phoneBookRelation in updatedPhoneContacts select phoneBookRelation.FullName).ToList(); var phoneContactsFullName = (from phoneBookRelation in _phoneBookContacts select phoneBookRelation.FullName).ToList(); var phoneBooksEqual = updatedPhoneContactsNumbers.Intersect(phoneBookContactsNumbers).Count() == updatedPhoneContactsNumbers.Union(phoneBookContactsNumbers).Count() && updatedPhoneContactsFullName.Intersect(phoneContactsFullName).Count() == updatedPhoneContactsFullName.Union(phoneContactsFullName).Count(); if (phoneBooksEqual) { Utils.DebugPrint( "Phone books are equal. No need to update contacts!"); return; } _phoneBookContacts = updatedPhoneContacts; Utils.DebugPrint("Got phone contacts... updating running services..."); var notRunningServices = ServiceManager.AllNoUnified.ToList(); foreach ( var service in ServiceManager.RunningNoUnified) { try { service.RefreshPhoneBookContacts(); BubbleGroupUpdater.Update(service); ServiceEvents.RaiseContactsUpdated(service); notRunningServices.Remove(service); } catch (Exception ex) { Utils.DebugPrint("Service " + service.Information.ServiceName + " failed to refresh it contacts. " + ex.Message); } } if (notRunningServices.Any()) { SettingsChangedManager.SetNeedsContactSync(notRunningServices.ToArray(), true); } SaveCachedPhoneBookContacts(updatedPhoneContacts); } } }; using (Platform.AquireWakeLock("DisaContactsUpdate")) { action(); } }); }