mirror of
https://github.com/tribufu/ServerManagers
synced 2026-05-06 15:17:34 +00:00
source code checkin
This commit is contained in:
parent
5f8fb2c825
commit
7e57b72e35
675 changed files with 168433 additions and 0 deletions
293
src/ServerManager.Updater/Program.cs
Normal file
293
src/ServerManager.Updater/Program.cs
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
|
||||
namespace ServerManagerTool.Updater
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private static string[] ApplicationArgs
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private static string DownloadUrl
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
private static string Prefix
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.Title = "Server Manager Updater";
|
||||
|
||||
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
|
||||
|
||||
var updaterArgs = args;
|
||||
ApplicationArgs = null;
|
||||
DownloadUrl = null;
|
||||
Prefix = null;
|
||||
|
||||
try
|
||||
{
|
||||
// check if the updater is already running
|
||||
if (ProcessUtils.IsAlreadyRunning())
|
||||
throw new Exception("The updater is already running.");
|
||||
|
||||
var process = Validate(updaterArgs);
|
||||
CloseApplication(process);
|
||||
process = null;
|
||||
|
||||
Update();
|
||||
RestartApplication();
|
||||
|
||||
Environment.ExitCode = 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
OutputError(ex.Message, ex.StackTrace);
|
||||
Environment.ExitCode = 1;
|
||||
|
||||
OutputMessage("Press any key to continue.");
|
||||
Console.ReadKey(true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void CloseApplication(Process process)
|
||||
{
|
||||
OutputMessage("Closing application...");
|
||||
|
||||
if (process == null || process.HasExited)
|
||||
throw new Exception("The process is not associated with a running application.");
|
||||
|
||||
// send a close to the application
|
||||
process.CloseMainWindow();
|
||||
|
||||
// wait until the application has been closed
|
||||
DateTime start = DateTime.Now;
|
||||
while (!process.HasExited)
|
||||
{
|
||||
if (start.AddMinutes(5) < DateTime.Now)
|
||||
{
|
||||
process.Kill();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!process.HasExited)
|
||||
throw new Exception("The application could not be closed.");
|
||||
}
|
||||
|
||||
private static void OutputError(string error, string stackTrace)
|
||||
{
|
||||
Console.WriteLine($"ERROR: {error}");
|
||||
}
|
||||
|
||||
private static void OutputMessage(string message)
|
||||
{
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
|
||||
private static void RestartApplication()
|
||||
{
|
||||
OutputMessage("Restarting application...");
|
||||
|
||||
var file = ApplicationArgs[0];
|
||||
var arguments = string.Empty;
|
||||
if (ApplicationArgs.Length > 1)
|
||||
{
|
||||
string[] argumentArray = new string[ApplicationArgs.Length - 1];
|
||||
Array.Copy(ApplicationArgs, 1, argumentArray, 0, argumentArray.Length);
|
||||
arguments = String.Join(" ", argumentArray);
|
||||
}
|
||||
|
||||
ProcessStartInfo info = new ProcessStartInfo()
|
||||
{
|
||||
FileName = file.AsQuoted(),
|
||||
Arguments = arguments,
|
||||
UseShellExecute = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
var process = Process.Start(info);
|
||||
if (process == null)
|
||||
throw new Exception("Could not restart application.");
|
||||
}
|
||||
|
||||
private static void Update()
|
||||
{
|
||||
if (ApplicationArgs == null || ApplicationArgs.Length == 0)
|
||||
throw new ArgumentNullException(nameof(ApplicationArgs), "The application args cannot be null or empty.");
|
||||
if (string.IsNullOrWhiteSpace(DownloadUrl))
|
||||
throw new ArgumentNullException(nameof(DownloadUrl), "The download url cannot be null or empty.");
|
||||
if (string.IsNullOrWhiteSpace(Prefix))
|
||||
throw new ArgumentNullException(nameof(Prefix), "The prefix cannot be null or empty.");
|
||||
|
||||
OutputMessage("Starting upgrade process...");
|
||||
|
||||
var currentInstallPath = Path.GetDirectoryName(ApplicationArgs[0]);
|
||||
var upgradeStagingPath = Path.GetTempPath();
|
||||
var applicationZip = Path.Combine(upgradeStagingPath, $"{Prefix}Latest.zip");
|
||||
var extractPath = Path.Combine(upgradeStagingPath, $"{Prefix}Latest");
|
||||
|
||||
// Download the latest version
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
OutputMessage("Downloading latest version file...");
|
||||
#if DEBUG
|
||||
OutputMessage($"Url: {DownloadUrl}");
|
||||
OutputMessage($"Zip: {applicationZip}");
|
||||
#endif
|
||||
client.DownloadFile(DownloadUrl, applicationZip);
|
||||
}
|
||||
|
||||
// Unblock the downloaded file
|
||||
OutputMessage("Preparing downloaded file...");
|
||||
#if DEBUG
|
||||
OutputMessage($"Zip: {applicationZip}");
|
||||
#endif
|
||||
IOUtils.Unblock(applicationZip);
|
||||
|
||||
try
|
||||
{
|
||||
// Delete the old extraction directory
|
||||
if (Directory.Exists(extractPath))
|
||||
{
|
||||
#if DEBUG
|
||||
OutputMessage("Deleting extract directory...");
|
||||
OutputMessage($"Dir: {extractPath}");
|
||||
#endif
|
||||
Directory.Delete(extractPath, true);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// Extract latest version to extraction directory
|
||||
OutputMessage("Extracting latest version to staging area...");
|
||||
#if DEBUG
|
||||
OutputMessage($"Zip: {applicationZip}");
|
||||
OutputMessage($"Dir: {extractPath}");
|
||||
#endif
|
||||
ZipFile.ExtractToDirectory(applicationZip, extractPath);
|
||||
|
||||
// build a list of files to be updated
|
||||
var latestFiles = Directory.GetFiles(extractPath, "*.*", SearchOption.AllDirectories).ToList();
|
||||
|
||||
// build a list of files to be removed
|
||||
var deleteFiles = Directory.GetFiles(currentInstallPath, "*.*", SearchOption.AllDirectories).ToList();
|
||||
foreach (var latestFile in latestFiles)
|
||||
{
|
||||
var file = Path.Combine(currentInstallPath, latestFile.Replace($"{extractPath}\\", ""));
|
||||
if (deleteFiles.Contains(file))
|
||||
deleteFiles.Remove(file);
|
||||
}
|
||||
|
||||
OutputMessage("Upgrading application...");
|
||||
|
||||
// delete the obsolete files
|
||||
foreach (var deleteFile in deleteFiles)
|
||||
{
|
||||
if (File.Exists(deleteFile))
|
||||
{
|
||||
#if DEBUG
|
||||
OutputMessage($"Delete: {deleteFile}");
|
||||
#endif
|
||||
//File.Delete(deleteFile);
|
||||
}
|
||||
}
|
||||
|
||||
// remove the updater from the files to be updated
|
||||
var assemblyFile = Assembly.GetEntryAssembly().Location;
|
||||
var assemblyPath = Path.GetDirectoryName(assemblyFile);
|
||||
|
||||
var updaterFile = Path.Combine(extractPath, assemblyFile.Replace($"{assemblyPath}\\", ""));
|
||||
#if DEBUG
|
||||
OutputMessage($"Checking: {updaterFile}");
|
||||
#endif
|
||||
if (latestFiles.Contains(updaterFile))
|
||||
latestFiles.Remove(updaterFile);
|
||||
|
||||
var updaterConfigFile = Path.Combine(updaterFile, ".config");
|
||||
#if DEBUG
|
||||
OutputMessage($"Checking: {updaterConfigFile}");
|
||||
#endif
|
||||
if (latestFiles.Contains(updaterConfigFile))
|
||||
latestFiles.Remove(updaterConfigFile);
|
||||
|
||||
// Replace the current installation
|
||||
foreach (var latestFile in latestFiles)
|
||||
{
|
||||
var file = Path.Combine(currentInstallPath, latestFile.Replace($"{extractPath}\\", ""));
|
||||
if (File.Exists(latestFile))
|
||||
{
|
||||
#if DEBUG
|
||||
OutputMessage($"Copy: {latestFile} to {file}");
|
||||
#endif
|
||||
// check if the directory exists
|
||||
var filePath = Path.GetDirectoryName(file);
|
||||
if (!Directory.Exists(filePath))
|
||||
Directory.CreateDirectory(filePath);
|
||||
|
||||
// copy over the file
|
||||
File.Copy(latestFile, file, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Process Validate(string[] args)
|
||||
{
|
||||
OutputMessage("Validating update...");
|
||||
|
||||
// argument format - PID, DownloadUrl, Prefix
|
||||
if (args == null)
|
||||
throw new ArgumentNullException(nameof(args), "The arguments cannot be null or empty");
|
||||
if (args == null || args.Length != 3)
|
||||
throw new ArgumentOutOfRangeException(nameof(args), "The arguments do not contain valid information.");
|
||||
|
||||
// check if the passed pid is valid
|
||||
if (!int.TryParse(args[0], out int pid))
|
||||
throw new InvalidCastException("The process id value is not valid.");
|
||||
|
||||
DownloadUrl = args[1];
|
||||
if (string.IsNullOrWhiteSpace(DownloadUrl))
|
||||
throw new ArgumentNullException(nameof(DownloadUrl), "The download url cannot be null or empty.");
|
||||
|
||||
Prefix = args[2];
|
||||
if (string.IsNullOrWhiteSpace(Prefix))
|
||||
throw new ArgumentNullException(nameof(Prefix), "The prefix cannot be null or empty.");
|
||||
|
||||
// get the process associated with the pid
|
||||
var process = ProcessUtils.GetProcess(pid);
|
||||
if (process == null)
|
||||
throw new Exception("The process id value is not associated with a running application.");
|
||||
|
||||
// get a list of the running processes with the same name and file location
|
||||
var executablePath = ProcessUtils.GetMainModuleFilepath(pid);
|
||||
var processes = ProcessUtils.GetProcesses(process.ProcessName, executablePath);
|
||||
|
||||
// check if there is more than one instance of the application running
|
||||
if (processes.Length != 1)
|
||||
throw new Exception("The application to be updated has more than one instance running.");
|
||||
|
||||
// get the command line of the process
|
||||
var commandLine = ProcessUtils.GetCommandLineForProcess(pid);
|
||||
ApplicationArgs = ProcessUtils.CommandLineToArgs(commandLine);
|
||||
|
||||
if (ApplicationArgs == null || ApplicationArgs.Length == 0)
|
||||
throw new ArgumentNullException(nameof(ApplicationArgs), "The application args cannot be null or empty.");
|
||||
|
||||
return process;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue