diff --git a/ArchiSteamFarm/ASF.cs b/ArchiSteamFarm/ASF.cs index cb69a2027..fb8c178d3 100644 --- a/ArchiSteamFarm/ASF.cs +++ b/ArchiSteamFarm/ASF.cs @@ -46,6 +46,32 @@ namespace ArchiSteamFarm { private static FileSystemWatcher FileSystemWatcher; internal static async Task CheckForUpdate(bool updateOverride = false) { + string currentDirectory = Directory.GetCurrentDirectory(); + + // Cleanup from previous update - update directory for old in-use runtime files + string backupDirectory = Path.Combine(currentDirectory, SharedInfo.UpdateDirectory); + if (Directory.Exists(backupDirectory)) { + // It's entirely possible that old process is still running, wait at least a second for eventual cleanup + await Task.Delay(1000).ConfigureAwait(false); + + try { + Directory.Delete(backupDirectory, true); + } catch (Exception e) { + ArchiLogger.LogGenericException(e); + return; + } + } + + // Cleanup from previous update - old non-runtime in-use files + foreach (string file in Directory.GetFiles(currentDirectory, "*.old", SearchOption.AllDirectories)) { + try { + File.Delete(file); + } catch (Exception e) { + ArchiLogger.LogGenericException(e); + return; + } + } + if (Program.GlobalConfig.UpdateChannel == GlobalConfig.EUpdateChannel.None) { return; } @@ -56,21 +82,6 @@ namespace ArchiSteamFarm { return; } - string oldAssemblyFile = assemblyFile + ".old"; - - // We booted successfully so we can now remove old exe file - if (File.Exists(oldAssemblyFile)) { - // 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(oldAssemblyFile); - } catch (Exception e) { - ArchiLogger.LogGenericException(e); - ArchiLogger.LogGenericError(string.Format(Strings.ErrorRemovingOldBinary, oldAssemblyFile)); - } - } - if (!File.Exists(SharedInfo.VersionFile)) { ArchiLogger.LogGenericError(string.Format(Strings.ErrorIsEmpty, SharedInfo.VersionFile)); return; @@ -153,11 +164,6 @@ namespace ArchiSteamFarm { return; } - if (File.Exists(oldAssemblyFile)) { - ArchiLogger.LogGenericError(string.Format(Strings.ErrorRemovingOldBinary, oldAssemblyFile)); - return; - } - // Auto update logic starts here if (releaseResponse.Assets == null) { ArchiLogger.LogGenericWarning(Strings.ErrorUpdateNoAssets); @@ -184,27 +190,12 @@ namespace ArchiSteamFarm { return; } - try { - File.Move(assemblyFile, oldAssemblyFile); - } catch (Exception e) { - ArchiLogger.LogGenericException(e); - return; - } - try { using (ZipArchive zipArchive = new ZipArchive(new MemoryStream(result))) { UpdateFromArchive(zipArchive); } } catch (Exception e) { ArchiLogger.LogGenericException(e); - - try { - // Cleanup - File.Move(oldAssemblyFile, assemblyFile); - } catch { - // Ignored - } - return; } @@ -436,21 +427,44 @@ namespace ArchiSteamFarm { return; } - string targetDirectory = Directory.GetCurrentDirectory(); + string currentDirectory = Directory.GetCurrentDirectory(); + string backupDirectory = Path.Combine(currentDirectory, SharedInfo.UpdateDirectory); - foreach (ZipArchiveEntry file in archive.Entries) { - string completeFileName = Path.Combine(targetDirectory, file.FullName); - string directory = Path.GetDirectoryName(completeFileName); + Directory.CreateDirectory(backupDirectory); + + // Move top-level runtime in-use files to other directory + // We must do it in order to not crash at later stage - all libraries/executables must keep original names + foreach (string file in Directory.GetFiles(currentDirectory)) { + string target = Path.Combine(backupDirectory, Path.GetFileName(file)); + File.Move(file, target); + } + + foreach (ZipArchiveEntry zipFile in archive.Entries) { + string file = Path.Combine(currentDirectory, zipFile.FullName); + string directory = Path.GetDirectoryName(file); if (!Directory.Exists(directory)) { Directory.CreateDirectory(directory); } - if (string.IsNullOrEmpty(file.Name) || file.Name.Equals(SharedInfo.GlobalConfigFileName)) { + if (string.IsNullOrEmpty(zipFile.Name) || zipFile.Name.Equals(SharedInfo.GlobalConfigFileName)) { continue; } - file.ExtractToFile(completeFileName, true); + string backupFile = file + ".old"; + + if (File.Exists(file)) { + // This is non-runtime file to be replaced, probably in use, move it away + File.Move(file, backupFile); + } + + zipFile.ExtractToFile(file); + + try { + File.Delete(backupFile); + } catch { + // Ignored - that file is indeed in use, it will be deleted after restart + } } } diff --git a/ArchiSteamFarm/IPC.cs b/ArchiSteamFarm/IPC.cs index 4e4f93efe..9b6fb1708 100644 --- a/ArchiSteamFarm/IPC.cs +++ b/ArchiSteamFarm/IPC.cs @@ -46,9 +46,6 @@ namespace ArchiSteamFarm { } string url = "http://" + host + ":" + port + "/" + nameof(IPC) + "/"; - - ASF.ArchiLogger.LogGenericInfo(string.Format(Strings.IPCStarting, url)); - HttpListener.Prefixes.Add(url); } @@ -57,6 +54,8 @@ namespace ArchiSteamFarm { return; } + ASF.ArchiLogger.LogGenericInfo(string.Format(Strings.IPCStarting, HttpListener.Prefixes.FirstOrDefault())); + try { HttpListener.Start(); } catch (HttpListenerException e) { diff --git a/ArchiSteamFarm/Program.cs b/ArchiSteamFarm/Program.cs index 6821630ec..726ea59ad 100644 --- a/ArchiSteamFarm/Program.cs +++ b/ArchiSteamFarm/Program.cs @@ -124,8 +124,13 @@ namespace ArchiSteamFarm { return; } + string executable = Process.GetCurrentProcess().MainModule.FileName; + string executableName = Path.GetFileNameWithoutExtension(executable); + + IEnumerable arguments = Environment.GetCommandLineArgs().Skip(executableName.Equals(SharedInfo.AssemblyName) ? 1 : 0); + try { - Process.Start(Assembly.GetEntryAssembly().Location, string.Join(" ", Environment.GetCommandLineArgs().Skip(1))); + Process.Start(executable, string.Join(" ", arguments)); } catch (Exception e) { ASF.ArchiLogger.LogGenericException(e); } diff --git a/ArchiSteamFarm/SharedInfo.cs b/ArchiSteamFarm/SharedInfo.cs index 4113db473..db0ed266a 100644 --- a/ArchiSteamFarm/SharedInfo.cs +++ b/ArchiSteamFarm/SharedInfo.cs @@ -39,6 +39,7 @@ namespace ArchiSteamFarm { internal const string GlobalDatabaseFileName = ASF + ".db"; internal const string LogFile = "log.txt"; internal const string StatisticsServer = "asf.justarchi.net"; + internal const string UpdateDirectory = "_old"; internal const string VersionFile = AssemblyName + ".version"; internal static readonly Version Version = Assembly.GetEntryAssembly().GetName().Version;