internal static async Task <Version> Update(bool updateOverride = false) { if (!SharedInfo.BuildInfo.CanUpdate || (GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { return(null); } await UpdateSemaphore.WaitAsync().ConfigureAwait(false); try { ArchiLogger.LogGenericInfo(Strings.UpdateCheckingNewVersion); // If backup directory from previous update exists, it's a good idea to purge it now string backupDirectory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.UpdateDirectory); if (Directory.Exists(backupDirectory)) { // It's entirely possible that old process is still running, wait a short moment for eventual cleanup await Task.Delay(5000).ConfigureAwait(false); try { Directory.Delete(backupDirectory, true); } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } } GitHub.ReleaseResponse releaseResponse = await GitHub.GetLatestRelease(GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable).ConfigureAwait(false); if (releaseResponse == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } if (string.IsNullOrEmpty(releaseResponse.Tag)) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } Version newVersion = new Version(releaseResponse.Tag); ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); if (SharedInfo.Version >= newVersion) { if (SharedInfo.Version > newVersion) { ArchiLogger.LogGenericWarning(Strings.WarningPreReleaseVersion); await Task.Delay(15 * 1000).ConfigureAwait(false); } return(newVersion); } if (!updateOverride && (GlobalConfig.UpdatePeriod == 0)) { ArchiLogger.LogGenericInfo(Strings.UpdateNewVersionAvailable); await Task.Delay(5000).ConfigureAwait(false); return(null); } // Auto update logic starts here if (releaseResponse.Assets == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssets); return(null); } string targetFile = SharedInfo.ASF + "-" + SharedInfo.BuildInfo.Variant + ".zip"; GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => asset.Name.Equals(targetFile, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssetForThisVersion); return(null); } if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) { ArchiLogger.LogNullError(nameof(binaryAsset.DownloadURL)); return(null); } if (!string.IsNullOrEmpty(releaseResponse.ChangelogPlainText)) { ArchiLogger.LogGenericInfo(releaseResponse.ChangelogPlainText); } ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024)); WebBrowser.BinaryResponse response = await WebBrowser.UrlGetToBinaryWithProgress(binaryAsset.DownloadURL).ConfigureAwait(false); if (response?.Content == null) { return(null); } try { using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(response.Content))) { if (!UpdateFromArchive(zipArchive, SharedInfo.HomeDirectory)) { ArchiLogger.LogGenericError(Strings.WarningFailed); } } } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } if (OS.IsUnix) { string executable = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName); if (File.Exists(executable)) { OS.UnixSetFileAccessExecutable(executable); } } ArchiLogger.LogGenericInfo(Strings.UpdateFinished); return(newVersion); } finally { UpdateSemaphore.Release(); } }
internal static async Task <Version> CheckAndUpdateProgram(bool updateOverride = false) { if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None) { return(null); } string assemblyFile = Assembly.GetEntryAssembly().Location; if (string.IsNullOrEmpty(assemblyFile)) { ArchiLogger.LogNullError(nameof(assemblyFile)); return(null); } if (!File.Exists(SharedInfo.VersionFile)) { ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsEmpty, SharedInfo.VersionFile)); return(null); } string version; try { version = await File.ReadAllTextAsync(SharedInfo.VersionFile).ConfigureAwait(false); } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } if (string.IsNullOrEmpty(version)) { ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, SharedInfo.VersionFile)); return(null); } version = version.TrimEnd(); if (string.IsNullOrEmpty(version) || !IsValidVersion(version)) { ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsInvalid, SharedInfo.VersionFile)); return(null); } if (version.Equals(DefaultVersion)) { return(null); } if ((AutoUpdatesTimer == null) && Program.GlobalConfig.AutoUpdates) { TimeSpan autoUpdatePeriod = TimeSpan.FromHours(AutoUpdatePeriodInHours); AutoUpdatesTimer = new Timer( async e => await CheckAndUpdateProgram().ConfigureAwait(false), null, autoUpdatePeriod, // Delay autoUpdatePeriod // Period ); ArchiLogger.LogGenericInfo(string.Format(Strings.AutoUpdateCheckInfo, autoUpdatePeriod.ToHumanReadable())); } ArchiLogger.LogGenericInfo(Strings.UpdateCheckingNewVersion); string targetDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); // Cleanup from previous update - update directory for old in-use runtime files string backupDirectory = Path.Combine(targetDirectory, SharedInfo.UpdateDirectory); if (Directory.Exists(backupDirectory)) { // It's entirely possible that old process is still running, wait a short moment for eventual cleanup await Task.Delay(5000).ConfigureAwait(false); try { Directory.Delete(backupDirectory, true); } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } } // Cleanup from previous update - old non-runtime in-use files foreach (string file in Directory.EnumerateFiles(targetDirectory, "*.old", SearchOption.AllDirectories)) { try { File.Delete(file); } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } } string releaseURL = SharedInfo.GithubReleaseURL + (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable ? "/latest" : "?per_page=1"); GitHub.ReleaseResponse releaseResponse; if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) { releaseResponse = await Program.WebBrowser.UrlGetToJsonResultRetry <GitHub.ReleaseResponse>(releaseURL).ConfigureAwait(false); if (releaseResponse == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } } else { List <GitHub.ReleaseResponse> releases = await Program.WebBrowser.UrlGetToJsonResultRetry <List <GitHub.ReleaseResponse> >(releaseURL).ConfigureAwait(false); if ((releases == null) || (releases.Count == 0)) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } releaseResponse = releases[0]; } if (string.IsNullOrEmpty(releaseResponse.Tag)) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } Version newVersion = new Version(releaseResponse.Tag); ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); if (SharedInfo.Version == newVersion) { return(SharedInfo.Version); } if (SharedInfo.Version > newVersion) { ArchiLogger.LogGenericWarning(Strings.WarningPreReleaseVersion); await Task.Delay(15 * 1000).ConfigureAwait(false); return(SharedInfo.Version); } if (!updateOverride && !Program.GlobalConfig.AutoUpdates) { ArchiLogger.LogGenericInfo(Strings.UpdateNewVersionAvailable); await Task.Delay(5000).ConfigureAwait(false); return(null); } // Auto update logic starts here if (releaseResponse.Assets == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssets); return(null); } string targetFile = SharedInfo.ASF + "-" + version + ".zip"; GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => asset.Name.Equals(targetFile, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssetForThisVersion); return(null); } if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) { ArchiLogger.LogNullError(nameof(binaryAsset.DownloadURL)); return(null); } ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024)); byte[] result = await Program.WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false); if (result == null) { return(null); } try { using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(result))) { UpdateFromArchive(zipArchive, targetDirectory); } } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } if (IsUnixVersion(version)) { string executable = Path.Combine(targetDirectory, SharedInfo.AssemblyName); if (File.Exists(executable)) { OS.UnixSetFileAccessExecutable(executable); } } ArchiLogger.LogGenericInfo(Strings.UpdateFinished); await RestartOrExit().ConfigureAwait(false); return(newVersion); }
internal static GlobalConfig Load(string filePath) { if (string.IsNullOrEmpty(filePath)) { ASF.ArchiLogger.LogNullError(nameof(filePath)); return(null); } if (!File.Exists(filePath)) { return(null); } GlobalConfig globalConfig; try { globalConfig = JsonConvert.DeserializeObject <GlobalConfig>(File.ReadAllText(filePath)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); return(null); } if (globalConfig == null) { ASF.ArchiLogger.LogNullError(nameof(globalConfig)); return(null); } // User might not know what he's doing // Ensure that he can't screw core ASF variables if (globalConfig.MaxFarmingTime == 0) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorConfigPropertyInvalid, nameof(globalConfig.MaxFarmingTime), globalConfig.MaxFarmingTime)); return(null); } if (globalConfig.FarmingDelay == 0) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorConfigPropertyInvalid, nameof(globalConfig.FarmingDelay), globalConfig.FarmingDelay)); return(null); } if (globalConfig.ConnectionTimeout == 0) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorConfigPropertyInvalid, nameof(globalConfig.ConnectionTimeout), globalConfig.ConnectionTimeout)); return(null); } if (globalConfig.IPCPort == 0) { ASF.ArchiLogger.LogGenericError(string.Format(Strings.ErrorConfigPropertyInvalid, nameof(globalConfig.IPCPort), globalConfig.IPCPort)); return(null); } if (globalConfig.SteamProtocols.HasFlag(ProtocolTypes.WebSocket) && !OS.SupportsWebSockets()) { globalConfig.SteamProtocols &= ~ProtocolTypes.WebSocket; if (globalConfig.SteamProtocols == 0) { globalConfig.SteamProtocols = ProtocolTypes.Tcp; } } GlobalConfig result = globalConfig; return(result); }
internal static async Task <Version> CheckAndUpdateProgram(bool updateOverride = false) { if (!SharedInfo.BuildInfo.CanUpdate || (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None)) { return(null); } if ((AutoUpdatesTimer == null) && (Program.GlobalConfig.UpdatePeriod > 0)) { TimeSpan autoUpdatePeriod = TimeSpan.FromHours(Program.GlobalConfig.UpdatePeriod); AutoUpdatesTimer = new Timer( async e => await CheckAndUpdateProgram().ConfigureAwait(false), null, autoUpdatePeriod, // Delay autoUpdatePeriod // Period ); ArchiLogger.LogGenericInfo(string.Format(Strings.AutoUpdateCheckInfo, autoUpdatePeriod.ToHumanReadable())); } ArchiLogger.LogGenericInfo(Strings.UpdateCheckingNewVersion); // Cleanup from previous update - update directory for old in-use runtime files string backupDirectory = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.UpdateDirectory); if (Directory.Exists(backupDirectory)) { // It's entirely possible that old process is still running, wait a short moment for eventual cleanup await Task.Delay(5000).ConfigureAwait(false); try { Directory.Delete(backupDirectory, true); } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } } // Cleanup from previous update - old non-runtime in-use files try { foreach (string file in Directory.EnumerateFiles(SharedInfo.HomeDirectory, "*.old", SearchOption.AllDirectories)) { File.Delete(file); } } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } string releaseURL = SharedInfo.GithubReleaseURL + (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable ? "/latest" : "?per_page=1"); GitHub.ReleaseResponse releaseResponse; if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) { WebBrowser.ObjectResponse <GitHub.ReleaseResponse> objectResponse = await Program.WebBrowser.UrlGetToJsonObject <GitHub.ReleaseResponse>(releaseURL).ConfigureAwait(false); if (objectResponse?.Content == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } releaseResponse = objectResponse.Content; } else { WebBrowser.ObjectResponse <List <GitHub.ReleaseResponse> > objectResponse = await Program.WebBrowser.UrlGetToJsonObject <List <GitHub.ReleaseResponse> >(releaseURL).ConfigureAwait(false); if ((objectResponse?.Content == null) || (objectResponse.Content.Count == 0)) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } releaseResponse = objectResponse.Content[0]; } if (string.IsNullOrEmpty(releaseResponse.Tag)) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } Version newVersion = new Version(releaseResponse.Tag); ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateVersionInfo, SharedInfo.Version, newVersion)); if (SharedInfo.Version == newVersion) { return(SharedInfo.Version); } if (SharedInfo.Version > newVersion) { ArchiLogger.LogGenericWarning(Strings.WarningPreReleaseVersion); await Task.Delay(15 * 1000).ConfigureAwait(false); return(SharedInfo.Version); } if (!updateOverride && (Program.GlobalConfig.UpdatePeriod == 0)) { ArchiLogger.LogGenericInfo(Strings.UpdateNewVersionAvailable); await Task.Delay(5000).ConfigureAwait(false); return(null); } // Auto update logic starts here if (releaseResponse.Assets == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssets); return(null); } string targetFile = SharedInfo.ASF + "-" + SharedInfo.BuildInfo.Variant + ".zip"; GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => asset.Name.Equals(targetFile, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssetForThisVersion); return(null); } if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) { ArchiLogger.LogNullError(nameof(binaryAsset.DownloadURL)); return(null); } ArchiLogger.LogGenericInfo(string.Format(Strings.UpdateDownloadingNewVersion, newVersion, binaryAsset.Size / 1024 / 1024)); WebBrowser.BinaryResponse response = await Program.WebBrowser.UrlGetToBinaryWithProgress(binaryAsset.DownloadURL).ConfigureAwait(false); if (response?.Content == null) { return(null); } try { using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(response.Content))) { if (!UpdateFromArchive(zipArchive, SharedInfo.HomeDirectory)) { ArchiLogger.LogGenericError(Strings.WarningFailed); } } } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } if (OS.IsUnix) { string executable = Path.Combine(SharedInfo.HomeDirectory, SharedInfo.AssemblyName); if (File.Exists(executable)) { OS.UnixSetFileAccessExecutable(executable); } } ArchiLogger.LogGenericInfo(Strings.UpdateFinished); await RestartOrExit().ConfigureAwait(false); return(newVersion); }