[M3] mxaccess-nmx: NmxClient — 9 raw INmxService2 opnums (stream B)

Lands M3 stream B raw opnum surface: an async NmxClient over the
mxaccess-rpc transport that dispatches all 9 INmxService2 procedures
(GetPartnerVersion, RegisterEngine2 + WithoutCallback, UnregisterEngine,
Connect, AddSubscriberEngine, RemoveSubscriberEngine,
SetHeartbeatSendInterval, TransferData) plus a NonZeroHresult error
variant that mirrors ThrowIfFailed (cs:563-574).

New
- crates/mxaccess-nmx/src/client.rs (~580 LoC, 8 tests including 5
  real-socket tokio tests against a hand-rolled DCE/RPC server) — port
  of the raw opnum surface from ManagedNmxService2Client.cs.
- NmxClient::connect builds the NTLM-packet-integrity bind path; for
  tests, NmxClient::from_bound_transport accepts a transport bound any
  way the caller likes (the test server doesn't validate signatures).
- fresh_orpc_this generates a per-call Cid via rand::random(), mirroring
  the .NET reference's Guid.NewGuid() at every call site.
- NmxClientError::NonZeroHresult unifies the .NET reference's
  Marshal.ThrowExceptionForHR + InvalidOperationException branches so
  callers see one typed surface for "transport-OK + LMX rejected".

Cargo.toml: added tokio, tracing, thiserror, rand to mxaccess-nmx.

Two layers of the .NET reference are deliberately out of scope this
iteration; both logged as new followups in design/followups.md:

- F12 (P1): the auto-resolving Create() factory, which needs windows-rs
  COM activation (gated by F6) + ComObjRefProvider port.
- F13 (P1): the high-level Write*/Advise*/UnAdvise/RegisterReference
  helpers, which depend on GalaxyTagMetadata from M3 stream A (the
  Galaxy SQL resolver crate, not yet started).

Test count delta: 389 -> 397 (+8). All four DoD gates green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-05 08:06:15 -04:00
parent ecfcc3f429
commit 0c772d273d
5 changed files with 605 additions and 1 deletions
+10 -1
View File
@@ -1,6 +1,11 @@
//! `mxaccess-nmx` — `INmxService2` client + raw NMX session façade.
//!
//! M0 stub. Real implementation lands in M3 — see `design/60-roadmap.md`.
//! M3 stream B landed: the [`client`] module ports the raw opnum surface
//! of `src/MxNativeClient/ManagedNmxService2Client.cs` (the 9
//! `INmxService2` procedures over `mxaccess_rpc::transport`). The
//! auto-resolving COM-activation factory and the high-level
//! `Write*`/`Advise*` wrappers are deferred — see the module-level docs
//! for what's deliberately out of scope for this iteration.
//!
//! Opnums (verified against `src/MxNativeClient/NmxComContracts.cs:55-73`,
//! and on the wire — sequential because `INmxService2 : INmxService` continues
@@ -16,3 +21,7 @@
//! - `11` GetPartnerVersion
#![forbid(unsafe_code)]
pub mod client;
pub use client::{NmxClient, NmxClientError};