/// <inheritdoc /> public void Init(ProfilerThread Thread) { if (this.currentState == StorageState.NotInitialized) { this.currentState = StorageState.Initializing; this.initializeTask = InitializeAsync(Thread); } }
private async Task Subtask(ProfilerThread Thread) { await Task.Delay(rnd.Next(10, 1000)); Thread.Start(); Thread.NewState("A"); await Task.Delay(rnd.Next(10, 1000)); Thread.NewState("B"); await Task.Delay(rnd.Next(10, 1000)); Thread.NewState("C"); await Task.Delay(rnd.Next(10, 1000)); Thread.NewState("D"); await Task.Delay(rnd.Next(10, 1000)); Thread.Stop(); }
/// <inheritdoc /> public async Task TryRepairDatabase(ProfilerThread Thread) { if (await this.uiDispatcher.DisplayAlert(AppResources.DatabaseIssue, AppResources.DatabaseCorruptInfoText, AppResources.RepairAndContinue, AppResources.ContinueAnyway)) { string method = "Delete database file(s) and create new empty database"; try { Thread?.NewState("Delete"); // 3. Delete and create a new empty database Directory.Delete(dataFolder, true); Thread?.NewState("Recreate"); this.databaseProvider = await CreateDatabaseFile(); Thread?.NewState("Repair3"); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); // If we had to repair, we must register the provider 'again', as one hasn't been provided yet. if (!Database.HasProvider) { method = $"{nameof(Database)}.{nameof(Database.Register)}"; Database.Register(databaseProvider, false); } // All is good. this.SetState(StorageState.Ready); } catch (Exception e3) { e3 = Log.UnnestException(e3); Thread?.Exception(e3); // Delete and create new failed. We're out of options. this.logService.LogException(e3, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); Thread?.NewState("DisplayAlert2"); await this.uiDispatcher.DisplayAlert(AppResources.DatabaseIssue, AppResources.DatabaseRepairFailedInfoText, AppResources.Ok); } } }
/// <summary> /// Thread goes idle. /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="Thread">Profiler thread generating the event.</param> public Idle(long Ticks, ProfilerThread Thread) : base(Ticks, Thread) { }
/// <summary> /// Abstract base class for profiler events. /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="Thread">Profiler thread generating the event.</param> public ProfilerEvent(long Ticks, ProfilerThread Thread) { this.ticks = Ticks; this.thread = Thread; }
/// <summary> /// Event occurred /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="Name">Name of event.</param> /// <param name="Thread">Profiler thread generating the event.</param> public Event(long Ticks, string Name, ProfilerThread Thread) : base(Ticks, Thread) { this.name = Name; }
/// <summary> /// Thread changes state. /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="State">String representation of the new state.</param> /// <param name="Thread">Profiler thread generating the event.</param> public NewState(long Ticks, string State, ProfilerThread Thread) : base(Ticks, Thread) { this.state = State; }
/// <summary> /// Processing stops. /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="Thread">Profiler thread generating the event.</param> public Stop(long Ticks, ProfilerThread Thread) : base(Ticks, Thread) { }
private async Task CreateXmppClient(bool CanCreateKeys) { this.xmppThread = this.startupProfiler?.CreateThread("XMPP", ProfilerThreadType.StateMachine); this.xmppThread?.Start(); this.xmppThread?.Idle(); if (isCreatingClient) { return; } try { isCreatingClient = true; if (!(this.xmppClient is null)) { DestroyXmppClient(); } if (this.xmppClient is null || this.domainName != this.tagProfile.Domain || this.accountName != this.tagProfile.Account || this.passwordHash != this.tagProfile.PasswordHash || this.passwordHashMethod != this.tagProfile.PasswordHashMethod) { this.domainName = this.tagProfile.Domain; this.accountName = this.tagProfile.Account; this.passwordHash = this.tagProfile.PasswordHash; this.passwordHashMethod = this.tagProfile.PasswordHashMethod; (string hostName, int portNumber, bool isIpAddress) = await this.networkService.LookupXmppHostnameAndPort(domainName); this.xmppClient = new XmppClient(hostName, portNumber, accountName, passwordHash, passwordHashMethod, Constants.LanguageCodes.Default, appAssembly, this.sniffer) { TrustServer = !isIpAddress, AllowCramMD5 = false, AllowDigestMD5 = false, AllowPlain = false, AllowEncryption = true, AllowScramSHA1 = true, AllowScramSHA256 = true }; this.xmppClient.RequestRosterOnStartup = false; this.xmppClient.OnStateChanged += XmppClient_StateChanged; this.xmppClient.OnConnectionError += XmppClient_ConnectionError; this.xmppClient.OnError += XmppClient_Error; this.xmppEventSink = new XmppEventSink("XMPP Event Sink", this.xmppClient, this.tagProfile.LogJid, false); if (!string.IsNullOrWhiteSpace(this.tagProfile.LegalJid)) { await this.contracts.CreateClients(CanCreateKeys); } this.IsLoggedOut = false; this.xmppClient.Connect(isIpAddress ? string.Empty : domainName); bool connectSucceeded = false; // Await connected state during registration or user initiated log in, but not otherwise. if (!this.tagProfile.IsCompleteOrWaitingForValidation() || this.userInitiatedLogInOrOut) { connectSucceeded = await this.WaitForConnectedState(Constants.Timeouts.XmppConnect); } // This saves startup time for registered users with a complete profile if (this.tagProfile.IsComplete()) { connectSucceeded = true; } if (!connectSucceeded) { this.logService.LogWarning("Connect to XMPP server '{0}' failed for account '{1}' with the specified timeout of {2} ms", this.domainName, this.accountName, (int)Constants.Timeouts.XmppConnect.TotalMilliseconds); } this.RecreateReconnectTimer(); } } finally { isCreatingClient = false; } }
private async Task XmppClient_StateChanged(object sender, XmppState newState) { this.xmppThread?.NewState(newState.ToString()); switch (newState) { case XmppState.Connected: this.LatestError = string.Empty; this.LatestConnectionError = string.Empty; this.xmppSettingsOk = true; this.RecreateReconnectTimer(); string legalJidBefore = this.tagProfile.LegalJid; if (this.tagProfile.NeedsUpdating()) { await this.DiscoverServices(); } string legalJidAfter = this.tagProfile.LegalJid; bool legalJidWasCleared = !string.IsNullOrWhiteSpace(legalJidBefore) && string.IsNullOrWhiteSpace(legalJidAfter); bool legalJidIsValid = !string.IsNullOrWhiteSpace(legalJidAfter); bool legalJidHasChangedAndIsValid = legalJidIsValid && !string.Equals(legalJidBefore, legalJidAfter); // If LegalJid was cleared, or is different if (legalJidWasCleared || legalJidHasChangedAndIsValid) { this.contracts.DestroyClients(); } // If we have a valid Jid, and contracts isn't created yet. if (legalJidHasChangedAndIsValid || (legalJidIsValid && !this.contracts.IsOnline)) { try { await this.contracts.CreateClients(false); } catch (Exception e) { this.logService.LogException(e); } } this.logService.AddListener(this.xmppEventSink); this.xmppThread?.Stop(); this.xmppThread = null; this.startupProfiler = null; break; case XmppState.Error: if (this.xmppSettingsOk) { this.xmppSettingsOk = false; this.xmppClient?.Reconnect(); } this.xmppThread?.Stop(); this.xmppThread = null; this.startupProfiler = null; break; } this.OnConnectionStateChanged(new ConnectionStateChangedEventArgs(newState, this.userInitiatedLogInOrOut)); }
private async Task PerformStartup(bool isResuming) { ProfilerThread thread = this.startupProfiler?.MainThread.CreateSubThread("AppStartup", ProfilerThreadType.Sequential); thread?.Start(); try { thread?.NewState("Report"); await this.SendErrorReportFromPreviousRun(); thread?.NewState("Startup"); ProfilerThread sdkStartupThread = this.startupProfiler?.CreateThread("SdkStartup", ProfilerThreadType.Sequential); sdkStartupThread?.Start(); sdkStartupThread?.NewState("DB"); this.sdk.UiDispatcher.IsRunningInTheBackground = false; // Start the db. // This is for soft restarts. // If this is a cold start, this call is made already in the App ctor, and this is then a no-op. this.sdk.StorageService.Init(sdkStartupThread); StorageState dbState = await this.sdk.StorageService.WaitForReadyState(); if (dbState == StorageState.NeedsRepair) { await this.sdk.StorageService.TryRepairDatabase(sdkStartupThread); } if (!isResuming) { await this.CreateOrRestoreConfiguration(); } sdkStartupThread?.NewState("Network"); await this.sdk.NetworkService.Load(isResuming); sdkStartupThread?.NewState("Load"); await this.sdk.NeuronService.Load(isResuming); sdkStartupThread?.NewState("Timer"); TimeSpan initialAutoSaveDelay = Constants.Intervals.AutoSave.Multiply(4); this.autoSaveTimer = new Timer(async _ => await AutoSave(), null, initialAutoSaveDelay, Constants.Intervals.AutoSave); sdkStartupThread?.Stop(); thread?.NewState("Navigation"); await this.sdk.NavigationService.Load(isResuming); thread?.NewState("Cache"); await this.imageCacheService.Load(isResuming); thread?.NewState("Orchestrators"); await this.contractOrchestratorService.Load(isResuming); await this.thingRegistryOrchestratorService.Load(isResuming); } catch (Exception e) { e = Waher.Events.Log.UnnestException(e); thread?.Exception(e); this.DisplayBootstrapErrorPage(e.Message, e.StackTrace); } thread?.Stop(); this.StartupCompleted("StartupProfile.uml", false); }
private async Task InitializeAsync(ProfilerThread Thread) { string createDbMethod = $"{nameof(FilesProvider)}.{nameof(FilesProvider.CreateAsync)}()"; string method = null; Thread?.Start(); try { Thread?.NewState("Provider"); // 1. Try create database method = createDbMethod; this.databaseProvider = await CreateDatabaseFile(); Thread?.NewState("Repair"); method = nameof(FilesProvider.RepairIfInproperShutdown); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); } catch (Exception e1) { e1 = Log.UnnestException(e1); Thread?.Exception(e1); // Create failed. this.logService.LogException(e1, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); try { Thread?.NewState("Repair2"); // 2. Try repair database if (this.databaseProvider is null && Database.HasProvider) { // This is an attempt that _can_ work. // During a soft restart, there _may_ be a provider registered already. If so, grab it. this.databaseProvider = Database.Provider as FilesProvider; } if (this.databaseProvider is null) { // Reasoning: If we can't create a provider, and the database doesn't have one assigned either, we're in serious trouble. // Throw an exception, which is caught below, to try and perform a recovery. const string message = "Database does not have a provider, and one cannot be created because the Database file(s) are locked. Catch 22."; method = createDbMethod; throw new InvalidOperationException(message); } method = nameof(FilesProvider.RepairIfInproperShutdown); await this.databaseProvider.RepairIfInproperShutdown(string.Empty); } catch (Exception e2) { e2 = Log.UnnestException(e2); Thread?.Exception(e2); // Repair failed this.logService.LogException(e2, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); } } try { Thread?.NewState("Register"); if (databaseProvider != null) { method = $"{nameof(Database)}.{nameof(Database.Register)}"; Database.Register(databaseProvider, false); // All is good. this.SetState(StorageState.Ready); } else { this.SetState(StorageState.NeedsRepair); } } catch (Exception e) { e = Log.UnnestException(e); Thread?.Exception(e); this.logService.LogException(e, this.GetClassAndMethod(MethodBase.GetCurrentMethod(), method)); this.SetState(StorageState.NeedsRepair); } finally { Thread?.Stop(); } }
/// <summary> /// Exception occurred /// </summary> /// <param name="Ticks">Elapsed ticks.</param> /// <param name="Exception">Exception object.</param> /// <param name="Thread">Profiler thread generating the event.</param> public Exception(long Ticks, System.Exception Exception, ProfilerThread Thread) : base(Ticks, Thread) { this.exception = Exception; }