[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:
@@ -54,6 +54,18 @@ move to `## Resolved` with a date + commit hash.
|
||||
**Why deferred:** `RemUnknownMessages.cs` declares the opnums (`:9-10`) but does not implement encoders/decoders. The Rust port matches that exactly per "port what is already proven."
|
||||
**Resolves when:** The .NET reference adds bodies for opnums 4 / 5 (or a captured frame establishes the on-wire shape). At that point port them into `rem_unknown.rs` alongside the existing `RemQueryInterface` codec.
|
||||
|
||||
### F12 — `NmxClient::create` (auto-resolving COM-activation factory)
|
||||
**Severity:** P1
|
||||
**Source:** M3 stream B, `crates/mxaccess-nmx/src/client.rs`
|
||||
**Why deferred:** `ManagedNmxService2Client.Create()` (`ManagedNmxService2Client.cs:30-64`) auto-discovers `(host, port, service_ipid)` by activating the `NmxSvc.NmxService` COM ProgID, marshalling the resulting `IUnknown` to an OBJREF, calling `IObjectExporter::ResolveOxid` against the OXID inside, then `IRemUnknown::RemQueryInterface` to get the `INmxService2` IPID. This requires `windows-rs` for `CoCreateInstance` / `CLSIDFromProgID` (the same gating dep as F6), plus the `ComObjRefProvider.MarshalIUnknownObjRef` port (also F6).
|
||||
**Resolves when:** F6 lands (windows-rs wired in + `ComObjRefProvider` port). At that point `NmxClient::create()` becomes ~30 lines that chain the existing primitives: COM activation → `MarshalIUnknownObjRef` → `ComObjRef::parse` → `object_exporter_client::resolve_oxid_with_managed_ntlm_packet_integrity` → `rem_unknown::encode_rem_query_interface_request` over a temporary transport → `NmxClient::connect`.
|
||||
|
||||
### F13 — `NmxClient` high-level write/advise/subscribe wrappers
|
||||
**Severity:** P1
|
||||
**Source:** M3 stream B, `crates/mxaccess-nmx/src/client.rs`
|
||||
**Why deferred:** The .NET `Write`, `Write2`, `WriteSecured2`, `AdviseSupervisory`, `SendObservedPreAdviseMetadata`, `RegisterReference`, and `UnAdvise` methods (`ManagedNmxService2Client.cs:303-466`) are short — each builds an inner NMX message via `mxaccess-codec` (`NmxWriteMessage`, `NmxItemControlMessage`, `NmxSecuredWrite2Message`, `NmxMetadataQueryMessage`, `NmxReferenceRegistrationMessage`), wraps it in an `NmxTransferEnvelope`, then calls `TransferData(...)`. They depend on `GalaxyTagMetadata` from M3 stream A (the Galaxy SQL resolver) for `PlatformId` / `EngineId` / `ToReferenceHandle(galaxyId)`.
|
||||
**Resolves when:** M3 stream A (`mxaccess-galaxy`) lands `GalaxyTagMetadata` (or an equivalent type) and `MxReferenceHandle` from `mxaccess-codec` is wired to it. At that point ~120 lines of wrappers go into `NmxClient` that delegate to the existing `transfer_data` opnum.
|
||||
|
||||
## Resolved
|
||||
|
||||
### F7 — Consolidate `Guid` type across `mxaccess-rpc`
|
||||
|
||||
Reference in New Issue
Block a user