Update-Pruefung regelmaessig und ab Werk an, Installation nur auf Klick
Richards Vorgabe vom 14.09.2026 (#587): Updates nie automatisch installieren, aber regelmaessig pruefen und darauf hinweisen. Bisher pruefte der Desktop genau einmal beim Start, das WebUI nur beim Seitenaufruf, und ab Werk gar nicht (UpdateCheckEnabled=false). Eine wochenlang laufende oder frisch installierte Anwendung erfuhr nie von einem neuen Release. - UpdateCheckEnabled ab Werk true, neu UpdateCheckIntervalHours (6, 1..168) - UpdateCheckBackgroundService: erste Pruefung nach 30 s, dann im Takt; laeuft auch ohne WebUI und kopflos; Hinweis im Log einmal je neuer Fassung - Registrierung ueber AddPolyTraderUpdateCheck, nicht mehr am WebUI - Desktop-Banner haengt an UpdateStatusService.Checked; "Spaeter" blendet bis zur naechsten neueren Fassung aus - WebUI-Banner holt alle 10 Minuten den vorgehaltenen Stand Auf der Linux-VM geprueft: 0.1.9 ohne Handeinstellung erkennt 0.2.0, ein Hinweis im Log, Banner erscheint, "Spaeter" blendet aus, Beenden in 0,1 s. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -368,6 +368,9 @@ namespace PolyTrader.App.Avalonia
|
||||
services.AddHostedService(sp => sp.GetRequiredService<WatchdogHeartbeatService>());
|
||||
services.AddHostedService(sp => sp.GetRequiredService<DeploymentcenterErrorReporter>());
|
||||
|
||||
// #587: regelmäßige Update-Prüfung mit Hinweis - installiert nie selbst.
|
||||
PolyTrader.Web.Updates.UpdateCheckServiceCollectionExtensions.AddPolyTraderUpdateCheck(services);
|
||||
|
||||
// Shell-Zustand (Fensterverwaltung). Auch im kopflosen Betrieb harmlos.
|
||||
services.AddSingleton<AvaloniaUiHost>();
|
||||
})
|
||||
|
||||
@@ -20,6 +20,7 @@ using PolyTrader.Core.Modularity;
|
||||
using PolyTrader.Core.Persistence;
|
||||
using PolyTrader.Core.Security;
|
||||
using PolyTrader.Modules.Supervisor.Persistence;
|
||||
using PolyTrader.Web.Updates;
|
||||
using PolyTraderSharp;
|
||||
using PolyTraderSharp.Models;
|
||||
using PolyTraderSharp.Services;
|
||||
@@ -51,8 +52,11 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
|
||||
private int _statusTicks;
|
||||
|
||||
/// <summary>Ergebnis der letzten Update-Prüfung – für den Klick auf „Jetzt installieren …".</summary>
|
||||
private UpdateCheckResult? _updateCheck;
|
||||
/// <summary>Fassung aus der letzten Update-Prüfung – für den Klick auf „Jetzt installieren …".</summary>
|
||||
private string? _updateVersion;
|
||||
|
||||
/// <summary>Mit „Später" ausgeblendete Fassung – das Banner kommt erst für eine noch neuere wieder.</summary>
|
||||
private string? _dismissedVersion;
|
||||
|
||||
public LauncherWindow() => AvaloniaXamlLoader.Load(this);
|
||||
|
||||
@@ -84,16 +88,25 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
|
||||
this.FindControl<Button>("btnInstallUpdate")!.Click += async (_, _) => await InstallUpdateAsync();
|
||||
this.FindControl<Button>("btnDismissUpdate")!.Click += (_, _) =>
|
||||
{
|
||||
_dismissedVersion = _updateVersion;
|
||||
this.FindControl<Border>("pnlUpdateBanner")!.IsVisible = false;
|
||||
};
|
||||
|
||||
_statusTimer.Tick += (_, _) => UpdateStatus();
|
||||
_statusTimer.Start();
|
||||
UpdateStatus();
|
||||
RefreshData();
|
||||
|
||||
// D-4: einmalige, stille Prüfung beim Start - fire-and-forget, darf den Start nie
|
||||
// verzögern oder blockieren. Nur aktiv, wenn Deploymentcenter:UpdateCheckEnabled gesetzt ist.
|
||||
_ = CheckForUpdateAsync();
|
||||
// #587: Geprüft wird regelmäßig im Hintergrund (UpdateCheckBackgroundService), hier nur angezeigt.
|
||||
// Bis zum 14.09.2026 prüfte diese Seite genau einmal beim Start - eine wochenlang laufende
|
||||
// Anwendung erfuhr nie von einem neuen Release. Kein Abmelden, siehe ThemeChanged unten.
|
||||
var updates = services.GetService<UpdateStatusService>();
|
||||
if (updates != null)
|
||||
{
|
||||
updates.Checked += OnUpdateChecked;
|
||||
if (updates.Last is { } last) OnUpdateChecked(last);
|
||||
}
|
||||
|
||||
// Die Umschalterflaechen werden im Code gesetzt und folgen dem Thema nicht von selbst.
|
||||
// Kein Abmelden: die Seite lebt in der Einfenster-Shell bis zum Programmende, ein
|
||||
@@ -185,56 +198,29 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
// ===== Update-Prüfung (D-4) =====
|
||||
|
||||
/// <summary>
|
||||
/// Prüft beim Start still auf ein neues Release. Installiert NIE automatisch (Leitentscheidung
|
||||
/// 4 aus dem Umsetzungsplan) - ein `is_critical`-Release ändert nur den Hinweistext, nicht das
|
||||
/// Verhalten. Wirft nie: ein nicht erreichbares Deploymentcenter darf den Start nicht stören.
|
||||
/// Zeigt das Ergebnis einer Hintergrundprüfung an. Installiert NIE automatisch (Leitentscheidung 4,
|
||||
/// bestätigt am 14.09.2026) - ein `is_critical`-Release ändert nur den Hinweistext, nicht das Verhalten.
|
||||
/// Kein Update, Fehler oder fehlende Lizenz blenden das Banner aus; die Einzelheiten stehen im WebUI
|
||||
/// unter Einstellungen → Version & Updates.
|
||||
/// </summary>
|
||||
private async Task CheckForUpdateAsync()
|
||||
private void OnUpdateChecked(UpdateCheckSnapshot snapshot)
|
||||
{
|
||||
try
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
var dcOptions = _services.GetService<DeploymentcenterOptions>();
|
||||
if (dcOptions == null || !dcOptions.UpdateCheckEnabled || string.IsNullOrWhiteSpace(dcOptions.BaseUrl))
|
||||
return;
|
||||
|
||||
var settings = _services.GetService<ServerSettings>();
|
||||
string? licenseKey = null;
|
||||
try { licenseKey = SecretProtection.Unprotect(settings?.LicenseKey ?? string.Empty); }
|
||||
catch { /* nicht lesbarer Schlüssel -> Prüfung läuft ohne Zugangsdaten weiter */ }
|
||||
|
||||
var updateClient = new UpdateClient();
|
||||
var result = await updateClient.CheckForUpdateAsync(
|
||||
baseUrl: dcOptions.BaseUrl,
|
||||
projectId: dcOptions.ProjectSlug,
|
||||
currentVersion: BuildInfo.Version,
|
||||
channel: dcOptions.Channel,
|
||||
credentials: ReleaseCredentials.FromLicenseKey(licenseKey));
|
||||
|
||||
if (result.Unauthorized)
|
||||
var banner = this.FindControl<Border>("pnlUpdateBanner")!;
|
||||
if (!snapshot.UpdateAvailable || string.IsNullOrEmpty(snapshot.LatestVersion))
|
||||
{
|
||||
// Kein Netzwerkfehler: die Lizenz trägt nicht mehr für den Paketabruf. Kein
|
||||
// Alarm im Launcher nötig - die Lizenzprüfung selbst (D-2) hat das schon gemeldet.
|
||||
_updateVersion = null;
|
||||
banner.IsVisible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.UpdateAvailable || result.LatestRelease == null) return;
|
||||
|
||||
_updateCheck = result;
|
||||
string version = result.LatestRelease.Version;
|
||||
string critical = result.IsCritical ? " (empfohlenes Sicherheitsupdate)" : "";
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
this.FindControl<TextBlock>("lblUpdateInfo")!.Text =
|
||||
$"Update verfügbar: v{version}{critical}. {result.LatestRelease.Changelog}".TrimEnd();
|
||||
this.FindControl<Border>("pnlUpdateBanner")!.IsVisible = true;
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Update-Prüfung darf den Start nie stören - stiller Rückzug, kein Log-Spam beim
|
||||
// vermutlich häufigsten Fall (Deploymentcenter nicht erreichbar).
|
||||
}
|
||||
_updateVersion = snapshot.LatestVersion;
|
||||
string critical = snapshot.IsCritical ? " (empfohlenes Sicherheitsupdate)" : "";
|
||||
this.FindControl<TextBlock>("lblUpdateInfo")!.Text =
|
||||
$"Update verfügbar: v{snapshot.LatestVersion}{critical}. {snapshot.Changelog}".TrimEnd();
|
||||
banner.IsVisible = !string.Equals(_dismissedVersion, snapshot.LatestVersion, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -244,7 +230,7 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
/// </summary>
|
||||
private async Task InstallUpdateAsync()
|
||||
{
|
||||
if (_updateCheck?.LatestRelease == null) return;
|
||||
if (_updateVersion == null) return;
|
||||
|
||||
var dcOptions = _services.GetService<DeploymentcenterOptions>();
|
||||
if (dcOptions == null) return;
|
||||
@@ -259,7 +245,7 @@ namespace PolyTrader.App.Avalonia.Views
|
||||
}
|
||||
|
||||
bool confirmed = await DialogWindow.Confirm(this, "Update installieren",
|
||||
$"Version {_updateCheck.LatestRelease.Version} herunterladen und PolyTrader danach " +
|
||||
$"Version {_updateVersion} herunterladen und PolyTrader danach " +
|
||||
"neu starten?\n\nOffene Vorgänge werden dabei genauso geordnet beendet wie über „Beenden\".",
|
||||
"Installieren");
|
||||
if (!confirmed) return;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
"WatchdogIntervalSeconds": 60,
|
||||
"WatchdogEnabled": false,
|
||||
"ErrorReportingEnabled": false,
|
||||
"UpdateCheckEnabled": false
|
||||
"_UpdateCheck_comment": "Prueft regelmaessig auf ein neues Release und weist darauf hin. Installiert wird nie automatisch, nur auf Klick im Desktop.",
|
||||
"UpdateCheckEnabled": true,
|
||||
"UpdateCheckIntervalHours": 6
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
|
||||
Reference in New Issue
Block a user