using System; using System.IO; using System.IO.Pipes; using System.Threading; using System.Threading.Tasks; using MxGateway.Worker.Bootstrap; namespace MxGateway.Worker.Ipc; public sealed class WorkerPipeClient : IWorkerPipeClient { public const int DefaultConnectTimeoutMilliseconds = 30000; private readonly int _connectTimeoutMilliseconds; private readonly Func _sessionFactory; public WorkerPipeClient() : this(DefaultConnectTimeoutMilliseconds) { } public WorkerPipeClient(int connectTimeoutMilliseconds) : this( connectTimeoutMilliseconds, (stream, frameOptions) => new WorkerPipeSession(stream, frameOptions)) { } public WorkerPipeClient( int connectTimeoutMilliseconds, Func sessionFactory) { if (connectTimeoutMilliseconds <= 0) { throw new ArgumentOutOfRangeException( nameof(connectTimeoutMilliseconds), "Worker pipe connect timeout must be greater than zero."); } _sessionFactory = sessionFactory ?? throw new ArgumentNullException(nameof(sessionFactory)); _connectTimeoutMilliseconds = connectTimeoutMilliseconds; } public async Task RunAsync( WorkerOptions options, CancellationToken cancellationToken = default) { if (options is null) { throw new ArgumentNullException(nameof(options)); } WorkerFrameProtocolOptions frameOptions = new(options); using NamedPipeClientStream pipe = new( ".", options.PipeName, PipeDirection.InOut, PipeOptions.Asynchronous); await ConnectAsync(pipe, cancellationToken).ConfigureAwait(false); WorkerPipeSession session = _sessionFactory(pipe, frameOptions); await session.RunAsync(cancellationToken).ConfigureAwait(false); } private Task ConnectAsync( NamedPipeClientStream pipe, CancellationToken cancellationToken) { return Task.Run( () => { cancellationToken.ThrowIfCancellationRequested(); pipe.Connect(_connectTimeoutMilliseconds); }, cancellationToken); } }