feat(launcher): implement verified atomic updates
This commit is contained in:
parent
2198a0cc8e
commit
2d2a5b5046
34 changed files with 6755 additions and 61 deletions
|
|
@ -4,6 +4,7 @@ using AcDream.Launcher.Core.Installation;
|
|||
using AcDream.Launcher.Core.Launching;
|
||||
using AcDream.Launcher.Core.Orchestration;
|
||||
using AcDream.Launcher.Core.Profiles;
|
||||
using AcDream.Launcher.Core.Updates;
|
||||
|
||||
namespace AcDream.Launcher.ViewModels;
|
||||
|
||||
|
|
@ -25,7 +26,8 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
public LauncherWindowViewModel(
|
||||
ILauncherOrchestrator orchestrator,
|
||||
IUiDispatcher dispatcher,
|
||||
ILauncherInstaller? installer = null)
|
||||
ILauncherInstaller? installer = null,
|
||||
ILauncherUpdater? updater = null)
|
||||
{
|
||||
_orchestrator = orchestrator ?? throw new ArgumentNullException(nameof(orchestrator));
|
||||
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
|
||||
|
|
@ -38,17 +40,16 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
OnInstallCompleted,
|
||||
() => CanInteract,
|
||||
() => !IsBusy && Sessions.All(session => !session.IsActive));
|
||||
UpdatePromptShell = new LauncherShellViewModel(
|
||||
"Client update",
|
||||
"Review a signed release manifest, verify the downloaded archive, "
|
||||
+ "and atomically switch the installed client version. The updater "
|
||||
+ "transaction lands in Campaign LA slice LA10.",
|
||||
"Updater shell ready — implementation arrives in LA10.",
|
||||
() => CanInteract);
|
||||
UpdatePrompt = new LauncherUpdateViewModel(
|
||||
updater ?? new UnavailableLauncherUpdater(),
|
||||
dispatcher,
|
||||
OnClientVersionChanged,
|
||||
() => CanInteract,
|
||||
() => !IsBusy && Sessions.All(session => !session.IsActive));
|
||||
|
||||
EditorDialog.PropertyChanged += OnModalPropertyChanged;
|
||||
FirstRunWizardShell.PropertyChanged += OnModalPropertyChanged;
|
||||
UpdatePromptShell.PropertyChanged += OnModalPropertyChanged;
|
||||
UpdatePrompt.PropertyChanged += OnModalPropertyChanged;
|
||||
|
||||
AddServerCommand = new RelayCommand(OpenAddServerDialog, () => CanInteract);
|
||||
AddAccountCommand = new RelayCommand(OpenAddAccountDialog, CanAddAccount);
|
||||
|
|
@ -92,7 +93,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
|
||||
public FirstRunInstallerViewModel FirstRunWizardShell { get; }
|
||||
|
||||
public LauncherShellViewModel UpdatePromptShell { get; }
|
||||
public LauncherUpdateViewModel UpdatePrompt { get; }
|
||||
|
||||
public LauncherTreeNodeViewModel? SelectedNode
|
||||
{
|
||||
|
|
@ -136,7 +137,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
public bool IsModalOpen =>
|
||||
EditorDialog.IsOpen
|
||||
|| FirstRunWizardShell.IsOpen
|
||||
|| UpdatePromptShell.IsOpen;
|
||||
|| UpdatePrompt.IsOpen;
|
||||
|
||||
private bool CanInteract => !IsBusy && !IsModalOpen;
|
||||
|
||||
|
|
@ -300,6 +301,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
}
|
||||
|
||||
RefreshFromCore();
|
||||
_ = UpdatePrompt.StartupCheckAsync();
|
||||
}
|
||||
|
||||
public void PollStatus()
|
||||
|
|
@ -333,8 +335,9 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
_orchestrator.StateChanged -= OnOrchestratorStateChanged;
|
||||
EditorDialog.PropertyChanged -= OnModalPropertyChanged;
|
||||
FirstRunWizardShell.PropertyChanged -= OnModalPropertyChanged;
|
||||
UpdatePromptShell.PropertyChanged -= OnModalPropertyChanged;
|
||||
UpdatePrompt.PropertyChanged -= OnModalPropertyChanged;
|
||||
FirstRunWizardShell.Dispose();
|
||||
UpdatePrompt.Dispose();
|
||||
}
|
||||
|
||||
private void OnOrchestratorStateChanged(object? sender, EventArgs e) =>
|
||||
|
|
@ -350,7 +353,8 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
{
|
||||
if (e.PropertyName != nameof(ProfileEditorDialogViewModel.IsOpen)
|
||||
&& e.PropertyName != nameof(LauncherShellViewModel.IsOpen)
|
||||
&& e.PropertyName != nameof(FirstRunInstallerViewModel.IsOpen))
|
||||
&& e.PropertyName != nameof(FirstRunInstallerViewModel.IsOpen)
|
||||
&& e.PropertyName != nameof(LauncherUpdateViewModel.IsOpen))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
@ -376,9 +380,9 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
{
|
||||
FirstRunWizardShell.Close();
|
||||
}
|
||||
else if (UpdatePromptShell.IsOpen)
|
||||
else if (UpdatePrompt.IsOpen)
|
||||
{
|
||||
UpdatePromptShell.IsOpen = false;
|
||||
UpdatePrompt.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -976,6 +980,13 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
RefreshFromCore();
|
||||
}
|
||||
|
||||
private void OnClientVersionChanged()
|
||||
{
|
||||
OperationStatus = "Versioned client activation changed.";
|
||||
LastError = null;
|
||||
RefreshFromCore();
|
||||
}
|
||||
|
||||
private void NotifyCommandStates()
|
||||
{
|
||||
AddServerCommand.NotifyCanExecuteChanged();
|
||||
|
|
@ -996,7 +1007,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
|
|||
session.NotifyCommandState();
|
||||
}
|
||||
FirstRunWizardShell.NotifyCommandStates();
|
||||
UpdatePromptShell.NotifyCommandStates();
|
||||
UpdatePrompt.NotifyCommandStates();
|
||||
}
|
||||
|
||||
private readonly record struct SelectionKey(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue