mirror of
https://github.com/wwiinnddyy/LanMountainDesktop.git
synced 2026-06-20 23:54:26 +08:00
Introduce a new update subsystem: shared contracts for manifests, messages, paths and state (LanMountainDesktop.Shared.Contracts.Update). Add IPC and reporting infrastructure for installer progress (IUpdateProgressReporter, LauncherUpdateProgressIpcServer, NullUpdateProgressReporter) and integrate progress/complete reporting into UpdateEngineService. Add multiple update service components and providers (CompositeManifestProvider, GithubReleaseManifestProvider, PlondsApiManifestProvider, UpdateDownloadEngine, UpdateOrchestrator, UpdateInstallGateway, CLI launcher bridge, launcher bridge interfaces, observable helper, state store, progress subject, JSON context). Update settings and models to support UseGhProxyMirror and PLONDS/GitHub fallback logic, plus localization strings and UI/viewmodel files for update settings and progress. Misc: installer script tweak and a small change in Plonds generator. This adds end-to-end support for checking, downloading and reporting update progress and results.
80 lines
2.3 KiB
C#
80 lines
2.3 KiB
C#
using System;
|
|
using LanMountainDesktop.Services.Settings;
|
|
using LanMountainDesktop.Shared.Contracts.Update;
|
|
using SettingsUpdateSettingsState = LanMountainDesktop.Services.Settings.UpdateSettingsState;
|
|
|
|
namespace LanMountainDesktop.Services.Update;
|
|
|
|
internal sealed class UpdateStateStore
|
|
{
|
|
private readonly ISettingsFacadeService _settingsFacade;
|
|
private readonly object _sync = new();
|
|
|
|
private const int AutoDowngradeThreshold = 3;
|
|
private int _consecutiveFailCount;
|
|
|
|
public UpdateStateStore(ISettingsFacadeService settingsFacade)
|
|
{
|
|
_settingsFacade = settingsFacade ?? throw new ArgumentNullException(nameof(settingsFacade));
|
|
CurrentPhase = UpdatePhase.Idle;
|
|
}
|
|
|
|
public UpdatePhase CurrentPhase { get; private set; }
|
|
|
|
public event Action<UpdatePhase>? PhaseChanged;
|
|
public event Action<UpdateProgressReport>? ProgressChanged;
|
|
|
|
public void TransitionTo(UpdatePhase newPhase)
|
|
{
|
|
lock (_sync)
|
|
{
|
|
if (CurrentPhase == newPhase)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CurrentPhase = newPhase;
|
|
}
|
|
|
|
PhaseChanged?.Invoke(newPhase);
|
|
ProgressChanged?.Invoke(new UpdateProgressReport(
|
|
newPhase,
|
|
$"Phase changed to {newPhase}",
|
|
0,
|
|
null,
|
|
null));
|
|
}
|
|
|
|
public SettingsUpdateSettingsState GetSettings()
|
|
{
|
|
return _settingsFacade.Update.Get();
|
|
}
|
|
|
|
public void SaveSettings(SettingsUpdateSettingsState state)
|
|
{
|
|
_settingsFacade.Update.Save(state);
|
|
}
|
|
|
|
public UpdateManifest? PendingManifest { get; set; }
|
|
|
|
public void RecordFailure(string errorMessage)
|
|
{
|
|
Interlocked.Increment(ref _consecutiveFailCount);
|
|
AppLogger.Warn("UpdateStateStore", $"Update failure recorded (consecutive: {_consecutiveFailCount}): {errorMessage}");
|
|
}
|
|
|
|
public void RecordSuccess(string appliedVersion)
|
|
{
|
|
Interlocked.Exchange(ref _consecutiveFailCount, 0);
|
|
|
|
var state = GetSettings();
|
|
SaveSettings(state with
|
|
{
|
|
PendingUpdateVersion = appliedVersion,
|
|
LastUpdateCheckUtcMs = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
|
|
});
|
|
}
|
|
|
|
public bool ShouldAutoDowngrade => Volatile.Read(ref _consecutiveFailCount) >= AutoDowngradeThreshold;
|
|
}
|