feat(launcher): implement verified atomic updates
This commit is contained in:
parent
2198a0cc8e
commit
2d2a5b5046
34 changed files with 6755 additions and 61 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using AcDream.Launcher.Core.Launching;
|
||||
using AcDream.Launcher.Core.Profiles;
|
||||
using AcDream.Launcher.Core.Status;
|
||||
using AcDream.Launcher.Core.Updates;
|
||||
using AcDream.Platform;
|
||||
|
||||
namespace AcDream.Launcher.Core.Orchestration;
|
||||
|
|
@ -26,6 +27,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
private readonly ILauncherProcessSupervisorFactory _supervisorFactory;
|
||||
private readonly IStatusEventSourceFactory _statusSourceFactory;
|
||||
private readonly Func<string> _sessionIdFactory;
|
||||
private readonly UpdateSessionBarrier _updateSessionBarrier;
|
||||
private readonly List<ManagedActivity> _activities = [];
|
||||
|
||||
private LauncherInstallRecord? _installRecord;
|
||||
|
|
@ -42,7 +44,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
ILauncherProcessSupervisorFactory? supervisorFactory = null,
|
||||
IStatusEventSourceFactory? statusSourceFactory = null,
|
||||
Func<string>? sessionIdFactory = null,
|
||||
string? installationStatus = null)
|
||||
string? installationStatus = null,
|
||||
UpdateSessionBarrier? updateSessionBarrier = null)
|
||||
{
|
||||
_profileStore = profileStore ?? throw new ArgumentNullException(nameof(profileStore));
|
||||
_paths = paths ?? throw new ArgumentNullException(nameof(paths));
|
||||
|
|
@ -53,6 +56,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
_supervisorFactory = supervisorFactory ?? new LauncherProcessSupervisorFactory();
|
||||
_statusSourceFactory = statusSourceFactory ?? new StatusFileTailerFactory();
|
||||
_sessionIdFactory = sessionIdFactory ?? CreateSessionId;
|
||||
_updateSessionBarrier = updateSessionBarrier
|
||||
?? new UpdateSessionBarrier(paths.DataDirectory);
|
||||
_installationStatus = installationStatus
|
||||
?? (installRecord is null
|
||||
? FirstRunRequired
|
||||
|
|
@ -629,10 +634,18 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
{
|
||||
ILauncherProcessSupervisor? supervisor = null;
|
||||
string? password = request.Password;
|
||||
bool hostStarted = false;
|
||||
try
|
||||
{
|
||||
request.Cancellation.Token.ThrowIfCancellationRequested();
|
||||
|
||||
UpdateSessionBarrier.SessionLease sessionLease =
|
||||
_updateSessionBarrier.AcquireSession();
|
||||
lock (_gate)
|
||||
{
|
||||
request.Activity.UpdateSessionLease = sessionLease;
|
||||
}
|
||||
|
||||
ComposedSessionConfig composed = request.IsProbe
|
||||
? _configService.ComposeProbeAndWrite(
|
||||
request.Server,
|
||||
|
|
@ -674,6 +687,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
request.Activity.LaunchMode!.Value,
|
||||
composed.ConfigFilePath);
|
||||
supervisor.Start(processSpec, password);
|
||||
hostStarted = true;
|
||||
|
||||
request.Password = null;
|
||||
password = null;
|
||||
|
|
@ -728,6 +742,10 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
finally
|
||||
{
|
||||
request.Password = null;
|
||||
if (!hostStarted)
|
||||
{
|
||||
ReleaseUpdateSessionLease(request.Activity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -735,6 +753,7 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
ManagedActivity activity,
|
||||
LauncherSessionState processState)
|
||||
{
|
||||
UpdateSessionBarrier.SessionLease? sessionLease = null;
|
||||
try
|
||||
{
|
||||
lock (_gate)
|
||||
|
|
@ -774,10 +793,13 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
{
|
||||
activity.Status = activity.HostTerminalStatus;
|
||||
}
|
||||
sessionLease = activity.UpdateSessionLease;
|
||||
activity.UpdateSessionLease = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sessionLease?.Dispose();
|
||||
RaiseStateChanged();
|
||||
}
|
||||
catch
|
||||
|
|
@ -1192,6 +1214,15 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
activity.Supervisor.Dispose();
|
||||
activity.Supervisor = null;
|
||||
}
|
||||
|
||||
ReleaseUpdateSessionLease(activity);
|
||||
}
|
||||
|
||||
private static void ReleaseUpdateSessionLease(ManagedActivity activity)
|
||||
{
|
||||
UpdateSessionBarrier.SessionLease? lease =
|
||||
Interlocked.Exchange(ref activity.UpdateSessionLease, null);
|
||||
lease?.Dispose();
|
||||
}
|
||||
|
||||
private void ThrowIfDisposed()
|
||||
|
|
@ -1252,6 +1283,8 @@ public sealed class LauncherOrchestrator : ILauncherOrchestrator
|
|||
|
||||
public CancellationTokenSource? StartCancellation { get; set; }
|
||||
|
||||
public UpdateSessionBarrier.SessionLease? UpdateSessionLease;
|
||||
|
||||
public object StatusReadGate { get; } = new();
|
||||
|
||||
public bool IsActive => State is not (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue