static UpdateInfoFileContent ReadUpdateInfoFile(string fileName) { var retVal = new UpdateInfoFileContent(); if (File.Exists(fileName)) { try { var updateInfoDoc = XDocument.Load(fileName); XAttribute attr; if ((attr = updateInfoDoc.Root.Attribute("binaries-etag")) != null) { retVal.BinariesETag = attr.Value; } DateTime lastChecked; if ((attr = updateInfoDoc.Root.Attribute("last-check-timestamp")) != null) { if (DateTime.TryParseExact(attr.Value, "o", null, System.Globalization.DateTimeStyles.AssumeUniversal | System.Globalization.DateTimeStyles.AdjustToUniversal, out lastChecked)) { retVal.LastCheckTimestamp = lastChecked; } } if ((attr = updateInfoDoc.Root.Attribute("last-check-error")) != null) { retVal.LastCheckError = attr.Value; } } catch { } } return(retVal); }
void SetLastUpdateCheckInfo(UpdateInfoFileContent updateInfoFileContent) { LastUpdateCheckInfo info = null; if (updateInfoFileContent.LastCheckTimestamp.HasValue) { info = new LastUpdateCheckInfo() { When = updateInfoFileContent.LastCheckTimestamp.Value, ErrorMessage = updateInfoFileContent.LastCheckError } } ; lock (sync) { lastUpdateResult = info; } FireChangedEvent(); } void SetState(AutoUpdateState state) { lock (sync) { if (this.state == state) { return; } this.state = state; } trace.Info("autoupdater state -> {0}", state); FireChangedEvent(); }
void SetLastUpdateCheckInfo(UpdateInfoFileContent updateInfoFileContent) { LastUpdateCheckInfo info = null; if (updateInfoFileContent.LastCheckTimestamp.HasValue) { info = new LastUpdateCheckInfo(updateInfoFileContent.LastCheckTimestamp.Value, updateInfoFileContent.LastCheckError); } lock (sync) { lastUpdateResult = info; } FireChangedEvent(); }
static void WriteUpdateInfoFile(string fileName, UpdateInfoFileContent updateInfoFileContent) { var doc = new XDocument(new XElement("root")); if (updateInfoFileContent.BinariesETag != null) { doc.Root.Add(new XAttribute("binaries-etag", updateInfoFileContent.BinariesETag)); } if (updateInfoFileContent.LastCheckTimestamp.HasValue) { doc.Root.Add(new XAttribute("last-check-timestamp", updateInfoFileContent.LastCheckTimestamp.Value.ToString("o"))); } if (updateInfoFileContent.LastCheckError != null) { doc.Root.Add(new XAttribute("last-check-error", updateInfoFileContent.LastCheckError)); } doc.Save(fileName); }
async Task Worker() { try { await Task.Delay(Constants.initialWorkerDelay, workerCancellationToken); HandlePastUpdates(workerCancellationToken); SetState(AutoUpdateState.Idle); for (;;) { var appUpdateInfoFileContent = UpdateInfoFileContent.Read(updateInfoFilePath); var installationUpdateKey = factory.CreateUpdateKey( appUpdateInfoFileContent.BinariesETag, pluginsManager.InstalledPlugins.ToDictionary( p => p.Id, p => UpdateInfoFileContent.Read(Path.Combine(p.PluginDirectory, Constants.updateInfoFileName)).BinariesETag ) ); SetLastUpdateCheckInfo(appUpdateInfoFileContent); await IdleUntilItsTimeToCheckForUpdate(appUpdateInfoFileContent.LastCheckTimestamp); SetState(AutoUpdateState.Checking); var appCheckResult = await CheckForUpdate(appUpdateInfoFileContent.BinariesETag); if (appCheckResult.Status == DownloadUpdateResult.StatusCode.Failure) { continue; } var requiredPlugins = await GetRequiredPlugins(pluginsManager, workerCancellationToken); var requiredUpdateKey = factory.CreateUpdateKey( appCheckResult.ETag, requiredPlugins.ToDictionary(p => p.Id, p => p.IndexItem.ETag) ); var nullUpdateKey = factory.CreateNullUpdateKey(); bool requiredUpdateIsSameAsAlreadyInstalled = requiredUpdateKey.Equals(installationUpdateKey); trace.Info("Comparing required update key '{0}' with already installed '{1}': {2}", requiredUpdateKey, installationUpdateKey, requiredUpdateIsSameAsAlreadyInstalled); if (requiredUpdateIsSameAsAlreadyInstalled) { requiredUpdateKey = nullUpdateKey; } if (!requiredUpdateKey.Equals(currentPendingUpdate?.Key ?? nullUpdateKey)) { if (currentPendingUpdate != null) { await currentPendingUpdate.Dispose(); currentPendingUpdate = null; } if (!requiredUpdateKey.Equals(nullUpdateKey)) { currentPendingUpdate = await factory.CreatePendingUpdate( requiredPlugins, managedAssembliesPath, ComposeUpdateLogFileName(), workerCancellationToken ); trace.Info("Created new pending update with key '{0}'", currentPendingUpdate.Key); } } if (currentPendingUpdate != null) { SetState(AutoUpdateState.WaitingRestart); } else { SetState(AutoUpdateState.Idle); } } } catch (TaskCanceledException) { trace.Info("autoupdater worker cancelled"); } catch (OperationCanceledException) { trace.Info("autoupdater worker cancelled"); } catch (BadInstallationDirException e) { trace.Error(e, "bad installation directory detected"); SetState(AutoUpdateState.FailedDueToBadInstallationDirectory); throw; } catch (Exception e) { trace.Error(e, "autoupdater worker failed"); SetState(AutoUpdateState.Failed); telemetry.ReportException(e, "autoupdater worker"); throw; } }