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
+11
View File
@@ -486,6 +486,17 @@ async Task PanelTests()
using (var da = new System.IO.Compression.ZipArchive(new MemoryStream(downZip)))
Check(down.IsSuccessStatusCode && da.GetEntry("defaultES2File.txt") != null, "The current save can be downloaded as ZIP");
// Updates: Versionen vergleichen, Status im Panel, Installieren nur mit verfügbarem Update
Check(Updater.ParseCsprojVersion("<Project><PropertyGroup><Version>2.10.1</Version></PropertyGroup></Project>") == "2.10.1"
&& Updater.ParseModVersion("public const string ModVersion = \"2.9\";") == "2.9", "Update versions are read from the source");
Check(Updater.IsNewer("2.10.0", "2.9.0") && !Updater.IsNewer("2.9.0", "2.9.0") && !Updater.IsNewer("2.8.5", "2.9.0") && !Updater.IsNewer("x", "2.9.0"),
"Versions are compared numerically (2.10 > 2.9)");
var upd = await Call(owner, "GET", "api/update");
Check(upd.status == 200 && upd.json.GetProperty("current").GetString() == Updater.CurrentVersion && upd.json.GetProperty("step").GetString() == "idle",
"The panel shows the installed server version: " + upd.json);
Check((await Call(owner, "POST", "api/update/install")).status == 409, "Installing without an available update is refused");
Check(Updater.RunInstalled(Array.Empty<string>(), dir) == null, "Without an installed update the built-in version runs");
// Lizenz: Master fällt aus -> der laufende Server läuft bis zum nächsten Neustart weiter
LicenseCache.Save(dir, "test", "Tester", "Test", DateTime.UtcNow.AddHours(-5));
var cachedLicense = LicenseCache.Load(dir, "test");