private LogGenericWarning ( string message, [ previousMethodName = null ) : void | ||
message | string | |
previousMethodName | [ | |
return | void |
internal static async Task InitBots() { if (Bot.Bots.Count != 0) { return; } // Before attempting to connect, initialize our configuration await Bot.InitializeSteamConfiguration(Program.GlobalConfig.SteamProtocols, Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false); HashSet <string> botNames; try { botNames = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).ToHashSet(); } catch (Exception e) { ArchiLogger.LogGenericException(e); return; } if (botNames.Count == 0) { ArchiLogger.LogGenericWarning(Strings.ErrorNoBotsDefined); return; } if (botNames.Count > MaximumRecommendedBotsCount) { ArchiLogger.LogGenericWarning(string.Format(Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); await Task.Delay(10000).ConfigureAwait(false); } await Utilities.InParallel(botNames.OrderBy(botName => botName).Select(Bot.RegisterBot)).ConfigureAwait(false); }
internal static async Task InitBots() { if (Bot.Bots.Count != 0) { return; } // Ensure that we ask for a list of servers if we don't have any saved servers available IEnumerable <ServerRecord> servers = await Program.GlobalDatabase.ServerListProvider.FetchServerListAsync().ConfigureAwait(false); if (servers?.Any() != true) { ArchiLogger.LogGenericInfo(string.Format(Strings.Initializing, nameof(SteamDirectory))); SteamConfiguration steamConfiguration = SteamConfiguration.Create(builder => builder.WithProtocolTypes(Program.GlobalConfig.SteamProtocols).WithCellID(Program.GlobalDatabase.CellID).WithServerListProvider(Program.GlobalDatabase.ServerListProvider).WithHttpClientFactory(() => Program.WebBrowser.GenerateDisposableHttpClient())); try { await SteamDirectory.LoadAsync(steamConfiguration).ConfigureAwait(false); ArchiLogger.LogGenericInfo(Strings.Success); } catch { ArchiLogger.LogGenericWarning(Strings.BotSteamDirectoryInitializationFailed); await Task.Delay(5000).ConfigureAwait(false); } } HashSet <string> botNames; try { botNames = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).ToHashSet(); } catch (Exception e) { ArchiLogger.LogGenericException(e); return; } if (botNames.Count == 0) { ArchiLogger.LogGenericWarning(Strings.ErrorNoBotsDefined); return; } if (botNames.Count > MaximumRecommendedBotsCount) { ArchiLogger.LogGenericWarning(string.Format(Strings.WarningExcessiveBotsCount, MaximumRecommendedBotsCount)); await Task.Delay(10000).ConfigureAwait(false); } await Utilities.InParallel(botNames.OrderBy(botName => botName).Select(Bot.RegisterBot)).ConfigureAwait(false); }
internal async Task<bool> UrlHeadRetry(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { ArchiLogger.LogNullError(nameof(request)); return false; } bool result = false; for (byte i = 0; (i < MaxRetries) && !result; i++) { result = await UrlHead(request, referer).ConfigureAwait(false); } if (result) { return true; } ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries"); return false; }
internal async Task <byte[]> UrlGetToBytesWithProgressRetry(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { ArchiLogger.LogNullError(nameof(request)); return(null); } byte[] result = null; for (byte i = 0; (i < MaxTries) && (result == null); i++) { result = await UrlGetToBytesWithProgress(request, referer).ConfigureAwait(false); } if (result != null) { return(result); } ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, MaxTries)); ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request)); return(null); }
internal async Task <byte[]> UrlGetToBytesRetry(string request, string referer = null) { if (string.IsNullOrEmpty(request)) { ArchiLogger.LogNullError(nameof(request)); return(null); } byte[] result = null; for (byte i = 0; (i < MaxRetries) && (result == null); i++) { result = await UrlGetToBytes(request, referer).ConfigureAwait(false); } if (result != null) { return(result); } ArchiLogger.LogGenericWarning("Request failed even after " + MaxRetries + " tries"); return(null); }
internal static async Task InitBots() { if (Bot.Bots.Count != 0) { return; } // Before attempting to connect, initialize our configuration await Bot.InitializeSteamConfiguration(Program.GlobalConfig.SteamProtocols, Program.GlobalDatabase.CellID, Program.GlobalDatabase.ServerListProvider).ConfigureAwait(false); try { IEnumerable <Task> tasks = Directory.EnumerateFiles(SharedInfo.ConfigDirectory, "*" + SharedInfo.ConfigExtension).Select(Path.GetFileNameWithoutExtension).Where(botName => !string.IsNullOrEmpty(botName) && IsValidBotName(botName)).OrderBy(botName => botName).Select(Bot.RegisterBot); switch (Program.GlobalConfig.OptimizationMode) { case GlobalConfig.EOptimizationMode.MinMemoryUsage: foreach (Task task in tasks) { await task.ConfigureAwait(false); } break; default: await Task.WhenAll(tasks).ConfigureAwait(false); break; } } catch (Exception e) { ArchiLogger.LogGenericException(e); return; } if (Bot.Bots.Count == 0) { ArchiLogger.LogGenericWarning(Strings.ErrorNoBotsDefined); } }
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 { // 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)) { ArchiLogger.LogGenericInfo(Strings.UpdateCleanup); // 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); } ArchiLogger.LogGenericInfo(Strings.Done); } ArchiLogger.LogGenericInfo(Strings.UpdateCheckingNewVersion); 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 { #if !NETFRAMEWORK await #endif using MemoryStream memoryStream = new MemoryStream(response.Content); using ZipArchive zipArchive = new ZipArchive(memoryStream); 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 (SharedInfo.IsCustomBuild || (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); 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 try { foreach (string file in Directory.EnumerateFiles(targetDirectory, "*.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.UrlGetToObjectRetry <GitHub.ReleaseResponse>(releaseURL).ConfigureAwait(false); if (objectResponse == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateCheckFailed); return(null); } releaseResponse = objectResponse.Content; } else { WebBrowser.ObjectResponse <List <GitHub.ReleaseResponse> > objectResponse = await Program.WebBrowser.UrlGetToObjectRetry <List <GitHub.ReleaseResponse> >(releaseURL).ConfigureAwait(false); if ((objectResponse == 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); } const string targetFile = SharedInfo.ASF + "-" + SharedInfo.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.UrlGetToBinaryWithProgressRetry(binaryAsset.DownloadURL).ConfigureAwait(false); if (response == null) { return(null); } try { using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(response.Content))) { UpdateFromArchive(zipArchive, targetDirectory); } } catch (Exception e) { ArchiLogger.LogGenericException(e); return(null); } if (IsUnixVariant(SharedInfo.Variant)) { string executable = Path.Combine(targetDirectory, SharedInfo.AssemblyName); if (File.Exists(executable)) { OS.UnixSetFileAccessExecutable(executable); } } ArchiLogger.LogGenericInfo(Strings.UpdateFinished); await RestartOrExit().ConfigureAwait(false); return(newVersion); }
public async Task <ObjectResponse <T> > UrlGetToJsonObject <T>(string request, string referer = null, ERequestOptions requestOptions = ERequestOptions.None, byte maxTries = MaxTries) where T : class { if (string.IsNullOrEmpty(request) || (maxTries == 0)) { ArchiLogger.LogNullError(nameof(request) + " || " + nameof(maxTries)); return(null); } ObjectResponse <T> result = null; for (byte i = 0; i < maxTries; i++) { using StreamResponse response = await UrlGetToStream(request, referer, requestOptions | ERequestOptions.ReturnClientErrors, 1).ConfigureAwait(false); // ReSharper disable once UseNullPropagationWhenPossible - false check if (response == null) { continue; } if (response.StatusCode.IsClientErrorCode()) { if (requestOptions.HasFlag(ERequestOptions.ReturnClientErrors)) { result = new ObjectResponse <T>(response); } break; } if (response.Content == null) { continue; } T obj; try { using StreamReader streamReader = new StreamReader(response.Content); using JsonReader jsonReader = new JsonTextReader(streamReader); JsonSerializer serializer = new JsonSerializer(); obj = serializer.Deserialize <T>(jsonReader); } catch (JsonException e) { ArchiLogger.LogGenericWarningException(e); if (Debugging.IsUserDebugging) { ArchiLogger.LogGenericDebug(string.Format(Strings.Content, response.Content)); } continue; } return(new ObjectResponse <T>(response, obj)); } if (maxTries > 1) { ArchiLogger.LogGenericWarning(string.Format(Strings.ErrorRequestFailedTooManyTimes, maxTries)); ArchiLogger.LogGenericDebug(string.Format(Strings.ErrorFailingRequest, request)); } return(result); }
internal static async Task CheckForUpdate(bool updateOverride = false) { string exeFile = Assembly.GetEntryAssembly().Location; if (string.IsNullOrEmpty(exeFile)) { ArchiLogger.LogNullError(nameof(exeFile)); return; } string oldExeFile = exeFile + ".old"; // We booted successfully so we can now remove old exe file if (File.Exists(oldExeFile)) { // It's entirely possible that old process is still running, allow at least a second before trying to remove the file await Task.Delay(1000).ConfigureAwait(false); try { File.Delete(oldExeFile); } catch (Exception e) { ArchiLogger.LogGenericException(e); ArchiLogger.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!"); } } if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None) { return; } if ((AutoUpdatesTimer == null) && Program.GlobalConfig.AutoUpdates) { AutoUpdatesTimer = new Timer( async e => await CheckForUpdate().ConfigureAwait(false), null, TimeSpan.FromDays(1), // Delay TimeSpan.FromDays(1) // Period ); ArchiLogger.LogGenericInfo("ASF will automatically check for new versions every 24 hours"); } string releaseURL = SharedInfo.GithubReleaseURL; if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) { releaseURL += "/latest"; } ArchiLogger.LogGenericInfo("Checking new version..."); 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("Could not check latest version!"); return; } } else { List <GitHub.ReleaseResponse> releases = await Program.WebBrowser.UrlGetToJsonResultRetry <List <GitHub.ReleaseResponse> >(releaseURL).ConfigureAwait(false); if ((releases == null) || (releases.Count == 0)) { ArchiLogger.LogGenericWarning("Could not check latest version!"); return; } releaseResponse = releases[0]; } if (string.IsNullOrEmpty(releaseResponse.Tag)) { ArchiLogger.LogGenericWarning("Could not check latest version!"); return; } Version newVersion = new Version(releaseResponse.Tag); ArchiLogger.LogGenericInfo("Local version: " + SharedInfo.Version + " | Remote version: " + newVersion); if (SharedInfo.Version.CompareTo(newVersion) >= 0) // If local version is the same or newer than remote version { return; } if (!updateOverride && !Program.GlobalConfig.AutoUpdates) { ArchiLogger.LogGenericInfo("New version is available!"); ArchiLogger.LogGenericInfo("Consider updating yourself!"); await Task.Delay(5000).ConfigureAwait(false); return; } if (File.Exists(oldExeFile)) { ArchiLogger.LogGenericWarning("Refusing to proceed with auto update as old " + oldExeFile + " binary could not be removed, please remove it manually"); return; } // Auto update logic starts here if (releaseResponse.Assets == null) { ArchiLogger.LogGenericWarning("Could not proceed with update because that version doesn't include assets!"); return; } string exeFileName = Path.GetFileName(exeFile); GitHub.ReleaseResponse.Asset binaryAsset = releaseResponse.Assets.FirstOrDefault(asset => !string.IsNullOrEmpty(asset.Name) && asset.Name.Equals(exeFileName, StringComparison.OrdinalIgnoreCase)); if (binaryAsset == null) { ArchiLogger.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!"); return; } if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) { ArchiLogger.LogGenericWarning("Could not proceed with update because download URL is empty!"); return; } ArchiLogger.LogGenericInfo("Downloading new version..."); ArchiLogger.LogGenericInfo("While waiting, consider donating if you appreciate the work being done :)"); byte[] result = await Program.WebBrowser.UrlGetToBytesRetry(binaryAsset.DownloadURL).ConfigureAwait(false); if (result == null) { return; } string newExeFile = exeFile + ".new"; // Firstly we create new exec try { File.WriteAllBytes(newExeFile, result); } catch (Exception e) { ArchiLogger.LogGenericException(e); return; } // Now we move current -> old try { File.Move(exeFile, oldExeFile); } catch (Exception e) { ArchiLogger.LogGenericException(e); try { // Cleanup File.Delete(newExeFile); } catch { // Ignored } return; } // Now we move new -> current try { File.Move(newExeFile, exeFile); } catch (Exception e) { ArchiLogger.LogGenericException(e); try { // Cleanup File.Move(oldExeFile, exeFile); File.Delete(newExeFile); } catch { // Ignored } return; } ArchiLogger.LogGenericInfo("Update process finished!"); if (Program.GlobalConfig.AutoRestart) { ArchiLogger.LogGenericInfo("Restarting..."); await Task.Delay(5000).ConfigureAwait(false); Program.Restart(); } else { ArchiLogger.LogGenericInfo("Exiting..."); await Task.Delay(5000).ConfigureAwait(false); Program.Exit(); } }