fix(launcher): close LA4 review findings

This commit is contained in:
Erik 2026-08-14 19:02:20 +02:00
parent d0a9c65d85
commit 10a712d66b
19 changed files with 1631 additions and 134 deletions

View file

@ -4,20 +4,59 @@ using AcDream.Launcher.Core.Profiles;
namespace AcDream.Launcher.Core.Orchestration;
/// <summary>
/// Host executable paths supplied by the current installation. LA10 will
/// resolve these from the versioned <c>app/current</c> pointer; LA4 keeps the
/// mapping injectable and host-agnostic.
/// Resolves and validates the co-deployed graphical/headless hosts. LA10 will
/// replace the directory lookup with its versioned-current resolver; until
/// then a missing host disables the corresponding action instead of deferring
/// failure until process creation.
/// </summary>
public sealed record LauncherExecutableSet(
string GraphicalHostPath,
string HeadlessHostPath,
string? WorkingDirectory = null)
public sealed class LauncherExecutableSet
{
private readonly Func<string, bool> _fileExists;
public LauncherExecutableSet(
string graphicalHostPath,
string headlessHostPath,
string? workingDirectory = null,
Func<string, bool>? fileExists = null)
{
ArgumentException.ThrowIfNullOrWhiteSpace(graphicalHostPath);
ArgumentException.ThrowIfNullOrWhiteSpace(headlessHostPath);
GraphicalHostPath = graphicalHostPath;
HeadlessHostPath = headlessHostPath;
WorkingDirectory = workingDirectory;
_fileExists = fileExists ?? File.Exists;
}
public string GraphicalHostPath { get; }
public string HeadlessHostPath { get; }
public string? WorkingDirectory { get; }
public LauncherCapability GetAvailability(LaunchMode mode)
{
string path = mode == LaunchMode.Headless
? HeadlessHostPath
: GraphicalHostPath;
if (_fileExists(path))
{
return LauncherCapability.Available;
}
string host = mode == LaunchMode.Headless
? "headless host"
: "graphical client";
return LauncherCapability.Unavailable(
$"The co-deployed {host} is missing at '{path}'. Reinstall or update "
+ "the client before launching.");
}
public LauncherProcessSpec CreatePlaySpec(
LaunchMode mode,
string configFilePath)
{
ArgumentException.ThrowIfNullOrWhiteSpace(configFilePath);
RequireAvailable(mode);
return mode == LaunchMode.Headless
? new LauncherProcessSpec(
@ -33,6 +72,7 @@ public sealed record LauncherExecutableSet(
public LauncherProcessSpec CreateProbeSpec(string configFilePath)
{
ArgumentException.ThrowIfNullOrWhiteSpace(configFilePath);
RequireAvailable(LaunchMode.Headless);
return new LauncherProcessSpec(
HeadlessHostPath,
["--config", configFilePath],
@ -49,4 +89,14 @@ public sealed record LauncherExecutableSet(
Path.Combine(fullDirectory, "acdream-headless" + executableSuffix),
fullDirectory);
}
private void RequireAvailable(LaunchMode mode)
{
LauncherCapability capability = GetAvailability(mode);
if (!capability.IsAvailable)
{
throw new LauncherOperationException(
capability.Reason ?? "The selected launcher host is unavailable.");
}
}
}