feat(launcher): Campaign LA add Avalonia desktop shell
This commit is contained in:
parent
6c4cd2bbc6
commit
d0a9c65d85
31 changed files with 4831 additions and 16 deletions
|
|
@ -2,13 +2,47 @@ using System.Runtime.ExceptionServices;
|
|||
|
||||
namespace AcDream.Launcher.Core.Launching;
|
||||
|
||||
/// <summary>
|
||||
/// Test seam for one supervised launcher child. The Avalonia orchestration
|
||||
/// layer owns this interface through a factory and never constructs or drives
|
||||
/// <see cref="System.Diagnostics.Process"/> directly.
|
||||
/// </summary>
|
||||
public interface ILauncherProcessSupervisor : IDisposable
|
||||
{
|
||||
LauncherSessionState State { get; }
|
||||
|
||||
int? ExitCode { get; }
|
||||
|
||||
event EventHandler<LauncherSessionState>? StateChanged;
|
||||
|
||||
void Start(LauncherProcessSpec spec, string? password);
|
||||
|
||||
void Stop(TimeSpan timeout);
|
||||
}
|
||||
|
||||
public interface ILauncherProcessSupervisorFactory
|
||||
{
|
||||
ILauncherProcessSupervisor Create();
|
||||
}
|
||||
|
||||
public sealed class LauncherProcessSupervisorFactory(
|
||||
ILauncherChildProcessFactory? childProcessFactory = null)
|
||||
: ILauncherProcessSupervisorFactory
|
||||
{
|
||||
private readonly ILauncherChildProcessFactory _childProcessFactory =
|
||||
childProcessFactory ?? new SystemChildProcessFactory();
|
||||
|
||||
public ILauncherProcessSupervisor Create() =>
|
||||
new LauncherProcessSupervisor(_childProcessFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns a host process (App/Headless), feeds the account password to
|
||||
/// its stdin then closes it, and supervises its lifetime (Campaign LA
|
||||
/// spec §3/§6). One supervisor instance owns exactly one child process
|
||||
/// for its lifetime — start a new supervisor per launched session.
|
||||
/// </summary>
|
||||
public sealed class LauncherProcessSupervisor : IDisposable
|
||||
public sealed class LauncherProcessSupervisor : ILauncherProcessSupervisor
|
||||
{
|
||||
private readonly ILauncherChildProcessFactory _factory;
|
||||
private readonly object _gate = new();
|
||||
|
|
|
|||
|
|
@ -13,6 +13,64 @@ public sealed record ComposedSessionConfig(
|
|||
string StatusFilePath,
|
||||
SessionConfigDocument Document);
|
||||
|
||||
/// <summary>
|
||||
/// Injectable composition/write seam used by the canonical launcher
|
||||
/// orchestrator. Production delegates to <see cref="SessionConfigComposer"/>;
|
||||
/// tests can capture the exact request without writing a file or starting a
|
||||
/// client process.
|
||||
/// </summary>
|
||||
public interface ILauncherSessionConfigService
|
||||
{
|
||||
ComposedSessionConfig ComposeAndWrite(
|
||||
ServerProfile server,
|
||||
AccountProfile account,
|
||||
CharacterProfile character,
|
||||
LauncherInstallRecord install,
|
||||
ApplicationPathSet paths,
|
||||
string sessionId,
|
||||
int? loginCommandDelayMs = null);
|
||||
|
||||
ComposedSessionConfig ComposeProbeAndWrite(
|
||||
ServerProfile server,
|
||||
AccountProfile account,
|
||||
LauncherInstallRecord install,
|
||||
ApplicationPathSet paths,
|
||||
string sessionId);
|
||||
}
|
||||
|
||||
public sealed class LauncherSessionConfigService : ILauncherSessionConfigService
|
||||
{
|
||||
public ComposedSessionConfig ComposeAndWrite(
|
||||
ServerProfile server,
|
||||
AccountProfile account,
|
||||
CharacterProfile character,
|
||||
LauncherInstallRecord install,
|
||||
ApplicationPathSet paths,
|
||||
string sessionId,
|
||||
int? loginCommandDelayMs = null) =>
|
||||
SessionConfigComposer.ComposeAndWrite(
|
||||
server,
|
||||
account,
|
||||
character,
|
||||
install,
|
||||
paths,
|
||||
sessionId,
|
||||
loginCommandDelayMs);
|
||||
|
||||
public ComposedSessionConfig ComposeProbeAndWrite(
|
||||
ServerProfile server,
|
||||
AccountProfile account,
|
||||
LauncherInstallRecord install,
|
||||
ApplicationPathSet paths,
|
||||
string sessionId) =>
|
||||
SessionConfigComposer.ComposeProbeAndWrite(
|
||||
server,
|
||||
account,
|
||||
install,
|
||||
paths,
|
||||
sessionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the per-launch <see cref="SessionConfigDocument"/> from a
|
||||
/// profile character + install record (Campaign LA spec §6). Passwords
|
||||
|
|
@ -187,6 +245,23 @@ public static class SessionConfigComposer
|
|||
sessionId,
|
||||
loginCommandDelayMs);
|
||||
|
||||
return Write(composed);
|
||||
}
|
||||
|
||||
/// <summary>Probe counterpart to <see cref="ComposeAndWrite"/>. It
|
||||
/// writes the pinned <c>mode: "probe"</c> document and never includes
|
||||
/// a character selector, policy, plugin set, login commands, or password.
|
||||
/// </summary>
|
||||
public static ComposedSessionConfig ComposeProbeAndWrite(
|
||||
ServerProfile server,
|
||||
AccountProfile account,
|
||||
LauncherInstallRecord install,
|
||||
ApplicationPathSet paths,
|
||||
string sessionId) =>
|
||||
Write(ComposeProbe(server, account, install, paths, sessionId));
|
||||
|
||||
private static ComposedSessionConfig Write(ComposedSessionConfig composed)
|
||||
{
|
||||
string? directory = Path.GetDirectoryName(composed.ConfigFilePath);
|
||||
if (!string.IsNullOrEmpty(directory))
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue