using AcDream.Headless.Configuration; using AcDream.Headless.Credentials; using AcDream.Headless.Hosting; using AcDream.Headless.Platform; namespace AcDream.Headless; internal static class HeadlessEntryPoint { private const string HelpText = """ acdream-headless Usage: acdream-headless --help acdream-headless validate --config [path overrides] acdream-headless run --config [path overrides] [credentials] Commands: validate Validate a versioned headless configuration without connecting. run Run exactly one configured no-window session. Path overrides: --config-dir --data-dir --cache-dir Direct single-session credentials: -user -password --user --password """; internal static int Run( IReadOnlyList arguments, TextWriter output, TextWriter error) => Run( arguments, TextReader.Null, output, error, CancellationToken.None); internal static int Run( IReadOnlyList arguments, TextReader standardInput, TextWriter output, TextWriter error, CancellationToken cancellationToken) { ArgumentNullException.ThrowIfNull(arguments); ArgumentNullException.ThrowIfNull(standardInput); ArgumentNullException.ThrowIfNull(output); ArgumentNullException.ThrowIfNull(error); if (arguments.Count == 0 || IsHelp(arguments[0])) { output.WriteLine(HelpText); return (int)HeadlessExitCode.Success; } try { HeadlessCommandLine commandLine = HeadlessCommandLine.Parse(arguments); HeadlessConfiguration configuration = HeadlessConfigurationLoader.Load( commandLine.ConfigurationPath); HeadlessPathOverrides configuredPaths = configuration.Process?.Paths ?? new HeadlessPathOverrides(); HeadlessPathSet paths = HeadlessPathSet.Resolve( configuredPaths.Merge(commandLine.Paths)); if (commandLine.Command == "run") { using var host = new HeadlessProcessHost( configuration, paths, standardInput, output, directCredentials: commandLine.DirectCredentials); return (int)host.RunAsync(cancellationToken) .GetAwaiter() .GetResult(); } output.WriteLine( $"Configuration valid: version {configuration.Version}, " + $"{configuration.Sessions.Count} session(s)."); return (int)HeadlessExitCode.Success; } catch (HeadlessCommandLineException) { error.WriteLine("Invalid command. Run --help for usage."); return (int)HeadlessExitCode.UsageError; } catch (System.Text.Json.JsonException) { error.WriteLine( "Configuration invalid: the JSON document is invalid."); return (int)HeadlessExitCode.ConfigurationError; } catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or ArgumentException or NotSupportedException or HeadlessConfigurationException) { error.WriteLine($"Configuration invalid: {exception.Message}"); return (int)HeadlessExitCode.ConfigurationError; } catch (HeadlessCredentialException exception) { error.WriteLine($"Credential unavailable: {exception.Message}"); return (int)HeadlessExitCode.CredentialError; } catch (Exception exception) { error.WriteLine( $"Headless runtime failed: {exception.GetType().FullName}"); return (int)HeadlessExitCode.RuntimeError; } } private static bool IsHelp(string argument) => string.Equals(argument, "--help", StringComparison.Ordinal) || string.Equals(argument, "-h", StringComparison.Ordinal); }