using System; using System.Collections.Generic; using MxGateway.Contracts; namespace MxGateway.Worker.Bootstrap; public sealed class WorkerOptionsParser { private const string SessionIdOptionName = "--session-id"; private const string PipeNameOptionName = "--pipe-name"; private const string ProtocolVersionOptionName = "--protocol-version"; private readonly IWorkerEnvironment _environment; public WorkerOptionsParser(IWorkerEnvironment environment) { _environment = environment ?? throw new ArgumentNullException(nameof(environment)); } public WorkerBootstrapResult Parse(string[] args) { if (args is null) { throw new ArgumentNullException(nameof(args)); } Dictionary values = new(StringComparer.OrdinalIgnoreCase); List errors = []; for (int index = 0; index < args.Length; index++) { string arg = args[index]; if (!IsKnownOption(arg)) { errors.Add($"Unknown option '{arg}'."); continue; } if (index + 1 >= args.Length || args[index + 1].StartsWith("--", StringComparison.Ordinal)) { errors.Add($"Option '{arg}' requires a value."); continue; } values[arg] = args[index + 1]; index++; } string? sessionId = ReadRequired(values, SessionIdOptionName, errors); string? pipeName = ReadRequired(values, PipeNameOptionName, errors); string? protocolVersionText = ReadRequired(values, ProtocolVersionOptionName, errors); if (errors.Count > 0) { return WorkerBootstrapResult.Failure(WorkerExitCode.InvalidArguments, errors); } if (!uint.TryParse(protocolVersionText, out uint protocolVersion) || protocolVersion != GatewayContractInfo.WorkerProtocolVersion) { return WorkerBootstrapResult.Failure( WorkerExitCode.InvalidProtocolVersion, [$"Unsupported protocol version '{protocolVersionText}'."]); } string? nonce = _environment.GetEnvironmentVariable(WorkerOptions.NonceEnvironmentVariableName); if (string.IsNullOrWhiteSpace(nonce)) { return WorkerBootstrapResult.Failure( WorkerExitCode.MissingNonce, ["Required worker nonce environment variable is missing."]); } return WorkerBootstrapResult.Success(new WorkerOptions( sessionId!, pipeName!, protocolVersion, nonce!)); } private static string? ReadRequired( IReadOnlyDictionary values, string optionName, List errors) { if (!values.TryGetValue(optionName, out string value) || string.IsNullOrWhiteSpace(value)) { errors.Add($"Required option '{optionName}' is missing."); return null; } return value; } private static bool IsKnownOption(string optionName) { return optionName is SessionIdOptionName or PipeNameOptionName or ProtocolVersionOptionName; } }