private static async Task OnDeletedConfigFile(string name, string fullPath) { if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(fullPath)) { ArchiLogger.LogNullError(nameof(name) + " || " + nameof(fullPath)); return; } string botName = Path.GetFileNameWithoutExtension(name); if (string.IsNullOrEmpty(botName)) { return; } DateTime lastWriteTime = DateTime.UtcNow; if (LastWriteTimes.TryGetValue(name, out DateTime savedLastWriteTime)) { if (savedLastWriteTime >= lastWriteTime) { return; } } LastWriteTimes[name] = lastWriteTime; // It's entirely possible that some process is still accessing our file, allow at least a second before trying to read it await Task.Delay(1000).ConfigureAwait(false); // It's also possible that we got some other event in the meantime if (LastWriteTimes.TryGetValue(name, out savedLastWriteTime)) { if (lastWriteTime != savedLastWriteTime) { return; } if (LastWriteTimes.TryRemove(name, out savedLastWriteTime)) { if (lastWriteTime != savedLastWriteTime) { return; } } } if (botName.Equals(SharedInfo.ASF)) { if (File.Exists(fullPath)) { return; } // Some editors might decide to delete file and re-create it in order to modify it // If that's the case, we wait for maximum of 5 seconds before shutting down await Task.Delay(5000).ConfigureAwait(false); if (File.Exists(fullPath)) { return; } ArchiLogger.LogGenericError(Strings.ErrorGlobalConfigRemoved); await Program.Exit(1).ConfigureAwait(false); return; } if (!IsValidBotName(botName)) { return; } if (Bot.Bots.TryGetValue(botName, out Bot bot)) { await bot.OnConfigChanged(true).ConfigureAwait(false); } }
internal static async Task CheckForUpdate(bool updateOverride = false) { string exeFile = Assembly.GetEntryAssembly().Location; if (string.IsNullOrEmpty(exeFile)) { Logging.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) { Logging.LogGenericException(e); Logging.LogGenericError("Could not remove old ASF binary, please remove " + oldExeFile + " manually in order for update function to work!"); } } if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Unknown) { 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 ); Logging.LogGenericInfo("ASF will automatically check for new versions every 24 hours"); } string releaseURL = SharedInfo.GithubReleaseURL; if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.Stable) { releaseURL += "/latest"; } Logging.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) { Logging.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)) { Logging.LogGenericWarning("Could not check latest version!"); return; } releaseResponse = releases[0]; } if (string.IsNullOrEmpty(releaseResponse.Tag)) { Logging.LogGenericWarning("Could not check latest version!"); return; } Version newVersion = new Version(releaseResponse.Tag); Logging.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) { Logging.LogGenericInfo("New version is available!"); Logging.LogGenericInfo("Consider updating yourself!"); await Task.Delay(5000).ConfigureAwait(false); return; } if (File.Exists(oldExeFile)) { Logging.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) { Logging.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) { Logging.LogGenericWarning("Could not proceed with update because there is no asset that relates to currently running binary!"); return; } if (string.IsNullOrEmpty(binaryAsset.DownloadURL)) { Logging.LogGenericWarning("Could not proceed with update because download URL is empty!"); return; } Logging.LogGenericInfo("Downloading new version..."); Logging.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) { Logging.LogGenericException(e); return; } // Now we move current -> old try { File.Move(exeFile, oldExeFile); } catch (Exception e) { Logging.LogGenericException(e); try { // Cleanup File.Delete(newExeFile); } catch { // Ignored } return; } // Now we move new -> current try { File.Move(newExeFile, exeFile); } catch (Exception e) { Logging.LogGenericException(e); try { // Cleanup File.Move(oldExeFile, exeFile); File.Delete(newExeFile); } catch { // Ignored } return; } Logging.LogGenericInfo("Update process finished!"); if (Program.GlobalConfig.AutoRestart) { Logging.LogGenericInfo("Restarting..."); await Task.Delay(5000).ConfigureAwait(false); Program.Restart(); } else { Logging.LogGenericInfo("Exiting..."); await Task.Delay(5000).ConfigureAwait(false); Program.Exit(); } }