using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using MxGateway.Contracts.Proto; using MxGateway.Worker.Sta; namespace MxGateway.Worker.MxAccess; public sealed class MxAccessStaSession : IDisposable { private readonly IMxAccessComObjectFactory factory; private readonly IMxAccessEventSink eventSink; private readonly StaRuntime staRuntime; private StaCommandDispatcher? commandDispatcher; private MxAccessSession? session; private bool disposed; public MxAccessStaSession() : this( new StaRuntime(), new MxAccessComObjectFactory(), new MxAccessBaseEventSink()) { } public MxAccessStaSession( StaRuntime staRuntime, IMxAccessComObjectFactory factory, IMxAccessEventSink eventSink) { this.staRuntime = staRuntime ?? throw new ArgumentNullException(nameof(staRuntime)); this.factory = factory ?? throw new ArgumentNullException(nameof(factory)); this.eventSink = eventSink ?? throw new ArgumentNullException(nameof(eventSink)); } public Task StartAsync( int workerProcessId, CancellationToken cancellationToken = default) { staRuntime.Start(); return staRuntime.InvokeAsync( () => { if (session is not null) { throw new InvalidOperationException("MXAccess COM session has already been created."); } session = MxAccessSession.Create(factory, eventSink); commandDispatcher = new StaCommandDispatcher( staRuntime, new MxAccessCommandExecutor(session)); return session.CreateWorkerReady(workerProcessId); }, cancellationToken); } public Task DispatchAsync(StaCommand command) { if (commandDispatcher is null) { throw new InvalidOperationException("MXAccess COM session has not been started."); } return commandDispatcher.DispatchAsync(command); } public Task> GetRegisteredServerHandlesAsync( CancellationToken cancellationToken = default) { if (session is null) { throw new InvalidOperationException("MXAccess COM session has not been started."); } return staRuntime.InvokeAsync( () => session.HandleRegistry.ServerHandles, cancellationToken); } public Task> GetRegisteredItemHandlesAsync( CancellationToken cancellationToken = default) { if (session is null) { throw new InvalidOperationException("MXAccess COM session has not been started."); } return staRuntime.InvokeAsync( () => session.HandleRegistry.ItemHandles, cancellationToken); } public void Dispose() { if (disposed) { return; } commandDispatcher?.RequestShutdown(); if (session is not null) { staRuntime.InvokeAsync(() => session.Dispose()).GetAwaiter().GetResult(); } staRuntime.Dispose(); disposed = true; } }