using System; using System.Collections.Generic; using System.IO; using MxGateway.Worker.Bootstrap; using MxGateway.Worker.Ipc; namespace MxGateway.Worker; public static class WorkerApplication { public static int Run(string[] args) { return Run( args, new EnvironmentVariableWorkerEnvironment(), new WorkerConsoleLogger(Console.Error), new WorkerPipeClient()); } public static int Run( string[] args, IWorkerEnvironment environment, IWorkerLogger logger) { return Run( args, environment, logger, new WorkerPipeClient()); } public static int Run( string[] args, IWorkerEnvironment environment, IWorkerLogger logger, IWorkerPipeClient pipeClient) { if (args is null) { throw new ArgumentNullException(nameof(args)); } if (environment is null) { throw new ArgumentNullException(nameof(environment)); } if (logger is null) { throw new ArgumentNullException(nameof(logger)); } if (pipeClient is null) { throw new ArgumentNullException(nameof(pipeClient)); } try { WorkerOptionsParser parser = new(environment); WorkerBootstrapResult result = parser.Parse(args); if (!result.Succeeded) { logger.Error("WorkerBootstrapFailed", new Dictionary { ["exit_code"] = result.ExitCode, ["errors"] = string.Join(";", result.Errors), }); return (int)result.ExitCode; } WorkerOptions options = result.Options ?? throw new InvalidOperationException("Successful bootstrap result did not include worker options."); logger.Information("WorkerBootstrapSucceeded", new Dictionary { ["session_id"] = options.SessionId, ["pipe_name"] = options.PipeName, ["protocol_version"] = options.ProtocolVersion, ["nonce"] = options.Nonce, }); pipeClient.RunAsync(options).GetAwaiter().GetResult(); logger.Information("WorkerPipeHandshakeSucceeded", new Dictionary { ["session_id"] = options.SessionId, ["pipe_name"] = options.PipeName, ["protocol_version"] = options.ProtocolVersion, }); return (int)WorkerExitCode.Success; } catch (WorkerFrameProtocolException exception) { logger.Error("WorkerPipeProtocolFailure", new Dictionary { ["exit_code"] = WorkerExitCode.ProtocolViolation, ["error_code"] = exception.ErrorCode, ["exception_type"] = exception.GetType().FullName, }); return (int)WorkerExitCode.ProtocolViolation; } catch (Exception exception) when (exception is IOException or TimeoutException) { logger.Error("WorkerPipeConnectionFailed", new Dictionary { ["exit_code"] = WorkerExitCode.PipeConnectionFailed, ["exception_type"] = exception.GetType().FullName, }); return (int)WorkerExitCode.PipeConnectionFailed; } catch (Exception exception) { logger.Error("WorkerBootstrapUnexpectedFailure", new Dictionary { ["exit_code"] = WorkerExitCode.UnexpectedFailure, ["exception_type"] = exception.GetType().FullName, }); return (int)WorkerExitCode.UnexpectedFailure; } } }