Server updates from the web panel with progress screen

- Updater checks git.mbm.wtf every 6 h (and on demand) for a newer <Version>
  on main, shows the new commits and the required mod version
- Install: download the source, build it with dotnet publish into
  data/app/current, warn players and restart (exit code 75 for Docker/systemd,
  self-relaunch on Windows). At startup a newer installed update is loaded in
  its own AssemblyLoadContext; after 3 failed starts the built-in version runs
- Panel: Update page, sidebar badge, full-screen progress overlay (download,
  build, install, restart) that survives the restart and reloads the panel
- Panel sessions survive restarts (hashed tokens in data/panel_sessions.json)
- Docker image is based on the .NET SDK so it can build updates
- Version 2.9.0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 21:07:09 +02:00
co-authored by Claude Opus 5.5
parent 1a2431db3a
commit 1ab9a01efb
12 changed files with 1084 additions and 13 deletions
+14 -1
View File
@@ -36,6 +36,10 @@ public sealed class ServerHost
public ServerConfig Config { get; private set; }
public GameServer Server { get; private set; }
public AdminPanel Panel { get; private set; }
/// <summary>Server-Updates (Prüfen/Installieren im Panel).</summary>
public Updater Updater { get; }
/// <summary>Rückgabewert von Run - Updater.RestartExitCode nach einem installierten Update.</summary>
public int ExitCode { get; private set; }
public HostState State { get; private set; } = HostState.Stopped;
public string LastError { get; private set; }
public DateTime StateSince { get; private set; } = DateTime.UtcNow;
@@ -50,6 +54,7 @@ public sealed class ServerHost
this.dataDir = dataDir;
this.configPath = configPath;
this.offline = offline;
Updater = new Updater(this, dataDir);
}
// ---------------------------------------------------------------- Steuerung (Konsole, Panel, Signale)
@@ -120,6 +125,13 @@ public sealed class ServerHost
return "Restarting - the server is back in a few seconds";
}
/// <summary>Update installiert: Weltzustand speichern, beenden und neu starten (Docker/systemd bzw. selbst).</summary>
public void ExitForUpdate()
{
ExitCode = Updater.RestartExitCode;
RequestExit();
}
/// <summary>Ganzes Programm beenden (Strg+C, docker stop, "exit").</summary>
public void RequestExit()
{
@@ -136,6 +148,7 @@ public sealed class ServerHost
if (!Listen(Config.Port)) return 1;
if (Panel == null)
GameServer.Log("Web panel is disabled (PanelEnabled in server.json)");
if (!offline) Updater.StartBackground();
while (!exitRequested)
{
@@ -185,7 +198,7 @@ public sealed class ServerHost
try { listener?.Stop(); } catch { }
Panel?.Stop();
GameServer.Log("Bye.");
return 0;
return ExitCode;
}
void HandleHostCommands()