# MXAccess Gateway Agent Guide Repository: https://gitea.dohertylan.com/dohertj2/mxaccessgw This project builds a gateway that gives modern clients full MXAccess parity without requiring those clients to load MXAccess COM, run as x86, or own an STA message pump. Treat the installed MXAccess COM component as the compatibility baseline. ## Core Contract Preserve MXAccess behavior first: - public MXAccess command semantics, - native MXAccess event families, - STA/message-pump delivery behavior, - installed-provider quirks, - HRESULT/status/value marshaling, - per-client isolation. Do not simplify, normalize, or "fix" MXAccess behavior unless an explicit non-parity mode is being implemented and tested. `MxAsbClient` and managed NMX are future acceleration paths only; they do not define the parity contract. ## Architecture The intended split is: ```text client -> gRPC over TCP -> .NET 10 x64 gateway -> session manager -> per-session .NET Framework 4.8 x86 worker process -> dedicated STA thread -> MXAccess COM instance -> Windows/COM message pump -> command queue -> event sink ``` The gateway must never instantiate or call MXAccess directly. All MXAccess COM interaction belongs in the worker process on its dedicated STA thread. The worker must not host public gRPC. Gateway-to-worker communication should use a small local IPC protocol, with named pipes and protobuf-framed messages as the default design. ## Runtime Targets - Gateway: .NET 10, C#, x64 preferred, ASP.NET Core gRPC. - Worker: .NET Framework 4.8, C#, x86 by default. - Worker IPC: one bidirectional named pipe per worker. - Worker process model: one external client session maps to one worker by default. ## Expected Layout Prefer this structure unless there is a strong reason to adjust it: ```text src/MxGateway.Contracts/ Protos/ mxaccess_gateway.proto mxaccess_worker.proto Generated/ src/MxGateway.Server/ Program.cs Sessions/ Workers/ Grpc/ Metrics/ src/MxGateway.Worker/ Program.cs Ipc/ Sta/ MxAccess/ Conversion/ src/MxGateway.Tests/ contract tests gateway session tests fake worker tests src/MxGateway.Worker.Tests/ value/status conversion tests STA queue tests src/MxGateway.IntegrationTests/ optional live MXAccess tests ``` The contracts project may multi-target, or the `.proto` files may be shared as source inputs to both gateway and worker builds. ## Public API Shape The external API should be session-oriented. Initial rollout should prefer unary `OpenSession`, `CloseSession`, and `Invoke`, plus server-streaming `StreamEvents`. Add a bidirectional `Session` stream after the command and event model is stable. Do not compress MXAccess into generic verbs too early. Use a command enum with method-specific payloads so parity can be tested method by method. Core MXAccess commands to represent: - `Register` - `Unregister` - `AddItem` - `AddItem2` - `RemoveItem` - `Advise` - `UnAdvise` - `AdviseSupervisory` - `AddBufferedItem` - `SetBufferedUpdateInterval` - `Suspend` - `Activate` - `Write` - `Write2` - `WriteSecured` - `WriteSecured2` - `AuthenticateUser` - `ArchestrAUserToId` Diagnostics may include `Ping`, `GetSessionState`, `GetWorkerInfo`, `DrainEvents`, and `ShutdownWorker`. ## Event Requirements Represent every public MXAccess event family: - `OnDataChange` - `OnWriteComplete` - `OperationComplete` - `OnBufferedDataChange` Preserve per-worker event order. The gateway must not reorder events emitted by the same MXAccess instance. Event DTOs should carry event family, session id, server handle, item handle, value, quality, timestamp, `MXSTATUS_PROXY[]` equivalent, raw HRESULT/status fields when available, event sequence, worker timestamp, and gateway receive timestamp. ## Value And Status Rules Use a protobuf value union that can represent COM `VARIANT` values and arrays. When a value cannot be losslessly converted, preserve both the best typed projection and enough raw diagnostic metadata to reproduce the case. Represent `MXSTATUS_PROXY` explicitly. Do not collapse status arrays into a single success flag. Command replies should include protocol status, COM HRESULT if available, MXAccess return values, method-specific out parameters, and status arrays where the MXAccess method emits them. ## Worker Rules Each worker owns: - one process, - one MXAccess session, - one dedicated STA thread, - one MXAccess COM object, - one inbound command queue, - one outbound event queue. All MXAccess operations must run on the STA. A plain blocking queue is not enough for the STA; the STA loop must pump Windows/COM messages and service queued commands. Do not block the STA on pipe writes, gRPC calls, or slow consumers. Event handlers should convert event args, enqueue outbound events, and return to pumping messages. On graceful shutdown, reject new commands, optionally clean up active MXAccess handles, detach events, release the COM object, uninitialize COM, and exit. If graceful shutdown exceeds the configured timeout, the gateway may kill the worker. ## IPC Rules Default pipe name shape: ```text mxaccess-gateway-{gatewayProcessId}-{sessionId} ``` Frame messages as: ```text uint32 little-endian payload_length payload_length bytes protobuf WorkerEnvelope ``` Every envelope should include protocol version, session id, monotonic sender sequence, correlation id, and a typed body. Protocol version mismatch should fail session creation. Pipe security should be local-machine only, with ACLs restricted to the gateway identity and launched worker identity. Prefer a per-session nonce handshake. ## Gateway Rules The gateway is responsible for: - public TCP/gRPC API, - authn/authz when needed, - session creation and teardown, - worker launch and lifecycle management, - command routing, - event streaming, - leases, heartbeats, timeouts, and quotas, - worker kill/restart policy, - metrics and structured logs. The gRPC layer should stay thin: validate request, find session, call the session worker client, map worker replies to public replies, and stream events. Keep MXAccess-specific translation logic testable outside the gRPC handlers. Gateway restart should not try to reattach old workers in the first version. Terminate orphaned workers on startup if that behavior is implemented. ## Command, Timeout, And Cancellation Semantics Command lifecycle: ```text client gRPC command gateway validates session and payload gateway assigns correlation id gateway writes WorkerCommand to pipe worker queues command to STA STA executes MXAccess method worker captures return/out/status/HRESULT worker sends WorkerCommandReply gateway completes gRPC response ``` Canceling a gRPC call should stop waiting in the gateway, but it cannot safely abort an in-flight COM call on the STA. Hard cancellation means killing the worker process. If a command wedges the STA beyond a configured grace period, the gateway should kill the worker and fail the session. ## Backpressure Policy Worker outbound events must use a bounded queue. For parity testing, prefer fail-fast behavior over silent drops. Production coalescing or drop policies must be explicit and observable. The gateway should preserve per-session event order, apply backpressure from slow gRPC streams, and disconnect or coalesce only according to an explicit policy. ## Security And Logging Use TLS for remote gRPC when crossing machine boundaries. Authentication may be Windows auth, mTLS, or a deployment-specific token. Commands that write, authenticate users, or alter runtime state need explicit authorization design. Never log passwords or raw credential values for `AuthenticateUser`, `WriteSecured`, or related secured operations. Do not log full values by default; make value logging opt-in and redacted. ## Testing Expectations Use focused tests for: - contract/protobuf compatibility, - gateway session state and worker lifecycle, - gateway behavior with a fake worker, - worker value/status conversion, - STA queue and message-pump behavior. Live MXAccess integration tests are optional but should be isolated because they depend on installed COM components and provider behavior. Parity tests should compare direct MXAccess behavior against the gateway: - return values, - HRESULTs and exceptions, - event sequence, - value projection, - quality/status arrays, - invalid handle behavior, - cross-server handle behavior, - cleanup behavior. Known important parity areas: - `WriteSecured` may fail before a value-bearing NMX body is emitted. - `WriteSecured2` can succeed in observed native paths. - `OperationComplete` is distinct from write completion. - `OnBufferedDataChange` has a distinct public event shape. - Invalid handles and cross-server handles have specific exception/status behavior. - STA message pumping is required for event delivery. ## Implementation Priority Build the smallest end-to-end slice first: 1. .NET 10 gateway starts. 2. Client calls `OpenSession`. 3. Gateway launches .NET Framework 4.8 x86 worker. 4. Worker creates STA and MXAccess COM object. 5. Client calls `Register`. 6. Client calls `AddItem`. 7. Client calls `Advise`. 8. Worker forwards one `OnDataChange` event to the gateway. 9. Gateway streams the event to the client. 10. Client calls `CloseSession`. 11. Gateway shuts down the worker. That slice proves the high-risk requirements: process isolation, STA ownership, message pumping, command routing, and event streaming.