Crate topology
Workspace layout
The workspace lives at c:\Users\dohertj2\Desktop\mxaccess\rust\ (sibling of src/) per the CLAUDE.md directive. The .NET tooling does not look there; cargo treats it as the workspace root.
Dependency graph
No cycles. ASB and NMX paths never depend on each other. The mxaccess-nmx → mxaccess-galaxy arrow is feature-gated behind galaxy-resolver (default-on); consumers building NMX with a custom Resolver can drop it.
Per-crate detail
mxaccess-codec
|
|
| Role |
Pure encoder/decoder for NMX wire types and ASB variant |
| Targets |
All Rust targets theoretically (codec is pure, no platform-bound deps); Linux/macOS support is a stretch goal, gated on MX_LIVE integration tests against a remote AVEVA install. See 60-roadmap.md and 70-risks-and-open-questions.md Q3. |
| Public deps |
bytes, byteorder, uuid, widestring, thiserror |
| Private deps |
proptest (dev) |
| Optional features |
serde (derives Serialize/Deserialize on public types) |
| Tests |
Round-trip every captured fixture; proptest generators for primitives; cross-implementation parity vs dotnet run --project src\MxNativeCodec.Tests |
mxaccess-galaxy
|
|
| Role |
Galaxy Repository SQL resolver: tag → metadata, user → identity |
| Targets |
All Rust targets, but Linux integrated-security is a stretch goal — see auth note below |
| Deps |
mxaccess-codec, tokio, tokio-util, futures-util, thiserror, tracing (tiberius is now an optional dep, see below) |
| Optional features |
galaxy-resolver (default-off; pulls tiberius and exposes the SQL-backed resolver. Consumers that only need NMX/ASB with a custom Resolver impl can leave this off and avoid pulling TDS, native-tls/rustls, and the winauth stack). auth-windows (default-on for Windows when galaxy-resolver is on; selects tiberius's winauth SSPI feature for integrated security against domain-joined SQL Server). On Linux, auth-windows does not apply: integrated security against an MSSQL Galaxy DB requires tiberius's integrated-auth-gssapi feature plus a configured Kerberos KDC and krb5.conf on the client. Galaxy databases in practice are domain-joined Windows boxes using NTLM/Kerberos integrated auth, so Linux clients without an MIT/Heimdal stack will fail to authenticate; flagged as a stretch goal and tracked in 70-risks-and-open-questions.md. SQL-login fallback is always available cross-platform. |
| Tests |
Mock SQL fixtures; live integration test gated on MX_GALAXY_DB env var |
The .NET reference keeps GalaxyRepositoryTagResolver.cs inside the MxNativeClient namespace (src/MxNativeClient/GalaxyRepositoryTagResolver.cs:4). Splitting it into mxaccess-galaxy is a Rust-side improvement, not a porting fault: the resolver's only inputs are SQL connection options, its only output is MxReferenceHandle (a mxaccess-codec type), and the Rust trait Resolver is exposed by mxaccess-nmx so consumers can plug in their own implementation. With galaxy-resolver feature-gated, mxaccess-nmx does not transitively pull tiberius for consumers who do not need it.
Resolver input contract — tag_name-form only. The Galaxy DB carries two distinct name fields per object: tag_name (the runtime read/write name, e.g. DelmiaReceiver_001) and contained_name (the hierarchy-browsing path, e.g. TestMachine_001.DelmiaReceiver). These are asymmetric and cannot be used interchangeably — wwtools/grdb/README.md calls this out as a critical distinction. GalaxyRepositoryTagResolver.ResolveSql keys on g.tag_name = @objectTagName; passing a contained-name will silently miss. The Rust Resolver trait takes a tag_name-form &str (e.g. "TestObject.TestInt" resolves the TestObject tag plus the TestInt attribute on it). If a future consumer needs contained-name → tag-name translation, add it as a separate translator that calls wwtools/grdb/queries/hierarchy.sql-style logic; do not mix the two paths inside mxaccess-galaxy.
Galaxy schema version probe. R10 in 70-risks-and-open-questions.md flags older Galaxy schema layouts as untested. wwtools/grdb/ confirms a dbo.schema_version table exists with version_number / version_string / cdi_version columns. The Rust resolver should query this at session construction and fail loud (ConfigError::Galaxy { reason: format!("schema version {version_string} is outside tested range") }) if the version is outside the proven set.
mxaccess-rpc
|
|
| Role |
DCE/RPC PDU codec + NTLMv2 + OBJREF + OXID resolution + RemQI |
| Targets |
x86_64-pc-windows-msvc (primary), x86_64-pc-windows-gnu, x86_64-unknown-linux-gnu (NTLM-only paths) |
| Deps |
mxaccess-codec, bytes, byteorder, tokio, hmac, md-5, rc4, rand, uuid, thiserror, tracing (all crypto crates pinned to the digest 0.11/cipher 0.5 generation per the workspace dependency table) |
| Optional features |
windows-com (default-on Windows; pulls windows for GUID/ObjRef helpers) |
| Tests |
Unit tests for NTLM message construction + PDU framing; integration tests against captured ObjectExporter responses |
mxaccess-callback
|
|
| Role |
TCP listener + RPC server for INmxSvcCallback and IRemUnknown |
| Deps |
mxaccess-rpc, mxaccess-codec, tokio, futures-util, tracing, thiserror |
| Tests |
Unit test that exercises the dispatch table with synthetic Bind/Request PDUs |
mxaccess-nmx
|
|
| Role |
INmxService2 client + raw NMX session façade. Exposes a Resolver trait so consumers can plug in any tag-handle resolver. |
| Deps |
mxaccess-codec, mxaccess-rpc, mxaccess-callback, tokio, tracing, thiserror |
| Optional features |
galaxy-resolver (default-on; pulls mxaccess-galaxy and re-exports its SQL-backed Resolver impl. Off → mxaccess-nmx builds without tiberius/TDS, and the consumer supplies their own Resolver.) |
| Tests |
Round-trip TransferData fixtures; live probe gated on MX_LIVE |
mxaccess-asb-nettcp
|
|
| Role |
net.tcp framing layer. Implements MC-NMF (.NET Message Framing) + MC-NBFX/NBFS (.NET Binary XML / dictionary string table) — the default binary message encoder for NetTcpBinding. Reference WCF construction in src/MxAsbClient/MxAsbDataClient.cs:660-685 is new NetTcpBinding(SecurityMode.None) with no encoder override, which selects BinaryMessageEncodingBindingElement by default — i.e. not SOAP/XML on the wire. The previous name mxaccess-asb-soap was a misnomer. |
| Visibility |
Workspace-internal crate, published alongside the rest of the workspace (no publish = false — Cargo refuses cargo publish of mxaccess-asb if a path-dep here lacks a published version). |
| Deps |
bytes, tokio, [an MC-NBFX/NBFS impl — TODO: evaluate wcf-binary crate or hand-roll a dictionary-table codec], quick-xml (only for the small ASB control-plane XML payloads such as request.ToXml() at src/MxAsbClient/AsbSystemAuthenticator.cs:79, not for net.tcp framing), flate2, aes, hmac, md-5, sha1 (note crate rename — sha-1 is deprecated upstream, sha1 is the maintained successor), sha2, pbkdf2, num-bigint, rand, tracing. All RustCrypto crates are pinned to the digest 0.11/cipher 0.5 generation; see workspace [workspace.dependencies] table. |
| Tests |
Unit tests for net.tcp/MC-NMF framing + DH handshake against captured payloads from AsbMessageDumpBehavior |
mxaccess-asb
|
|
| Role |
IASBIDataV2 client |
| Deps |
mxaccess-codec, mxaccess-asb-nettcp, tokio, tracing, thiserror |
| Optional features |
dpapi (default-on for Windows targets) — see SecretProvider below |
| Tests |
Round-trip Variant fixtures; live probe gated on MX_LIVE |
mxaccess-asb always exposes a SecretProvider trait (single fallible async fn fetch(&self) -> Result<Zeroizing<Vec<u8>>, Error>) that the ASB authenticator calls to obtain the shared secret used for the DH-passphrase derivation (src/MxAsbClient/AsbSystemAuthenticator.cs:28, 134-142 — the secret is mandatory for the handshake; without it ASB cannot authenticate). The trait is always present — not feature-gated — so consumers can plug in any source (env var, file, KeyVault, hardcoded test fixture). The dpapi feature provides a default Windows-only implementation that reads the secret via windows::Win32::Security::Cryptography::CryptUnprotectData. With dpapi=off, the crate still compiles and works; the consumer must provide a SecretProvider impl explicitly, otherwise Session::builder() fails at construction time with Error::ConfigurationIncomplete { missing: "secret_provider" }.
mxaccess
|
|
| Role |
Public async API: Session, Subscription, Transport trait |
| Deps |
mxaccess-codec, tokio, tokio-util, futures-util, tracing, thiserror, async-trait, arc-swap (for cheap clones of session state) |
| Optional features |
nmx (default-on Windows; pulls mxaccess-nmx), asb (default-on; pulls mxaccess-asb), metrics (optional metrics instrumentation), serde (forwards to codec) |
| Tests |
Integration tests gated on env vars; in-memory Transport for unit tests |
mxaccess-compat
|
|
| Role |
LMXProxyServer-shaped methods on top of Session |
| Deps |
mxaccess |
| Tests |
Method-equivalence tests against captured MxNativeCompatibilityServer outputs |
Build / test commands
To be added to CLAUDE.md "Common commands" once rust/ exists:
Toolchain & MSRV
- MSRV is 1.85, set both in
rust-toolchain.toml and in [workspace.package].rust-version. Both must stay in lock-step; CI fails if they drift. 1.85 is the floor required by the pinned RustCrypto generation (digest 0.11 / cipher 0.5 family — aes 0.9, hmac 0.13, md-5 0.11, sha1 0.11, pbkdf2 0.13) and by the latest uuid 1.x; lowering it forces an older crypto generation that conflicts on the resolved digest/cipher traits.
- Edition 2024 (stable since Rust 1.85, 2025-02). Since MSRV is already 1.85, edition 2024 is a free upgrade.
rustfmt default config + 100-column lines committed.
clippy with -D warnings in CI.
clippy::unwrap_used, clippy::expect_used set to deny in mxaccess, mxaccess-codec, mxaccess-rpc, mxaccess-nmx, mxaccess-asb. Allowed in tests via #[cfg(test)] overrides. UTF-16LE name decoding in mxaccess-codec (MxReferenceHandle parsing) must use a fallible helper that maps String::from_utf16 errors into a typed codec error rather than .unwrap()-ing — there is no panicking decode path on the hot wire-parse surface.
Feature gates summary
| Feature |
Default |
Crate |
Effect |
nmx |
yes (Windows) |
mxaccess |
Enables NmxTransport, pulls mxaccess-nmx |
asb |
yes |
mxaccess |
Enables AsbTransport, pulls mxaccess-asb |
metrics |
no |
mxaccess |
Emits metrics counters/histograms |
serde |
no |
mxaccess, mxaccess-codec |
Derives Serialize/Deserialize |
dpapi |
yes (Windows) |
mxaccess-asb |
Provides the Windows DPAPI default SecretProvider impl. Off → consumer must supply their own SecretProvider (the trait is always present). |
galaxy-resolver |
yes |
mxaccess-nmx |
Pulls mxaccess-galaxy and exposes the SQL-backed Resolver. Off → mxaccess-nmx ships without tiberius/TDS; consumer supplies a custom Resolver. |
auth-windows |
yes (Windows) |
mxaccess-galaxy |
Integrated security (SSPI/winauth) for SQL Server. Windows-only; Linux integrated security is a separate stretch goal that requires tiberius's integrated-auth-gssapi feature + a configured Kerberos KDC. SQL-login fallback works cross-platform without this feature. |
windows-com |
yes (Windows) |
mxaccess-rpc |
Uses windows crate for GUID/IID helpers |
live (test-only) |
no |
mxaccess, mxaccess-nmx, mxaccess-asb |
Enables tests that hit a live AVEVA install |
Workspace Cargo.toml skeleton
Pin minor versions in CI; keep workspace-level dependency table consistent across crates.
License
MIT (resolved 2026-05-05; see 70-risks-and-open-questions.md Q2). LICENSE file lives at the project root (c:\Users\dohertj2\Desktop\mxaccess\LICENSE). All crate Cargo.tomls inherit license = "MIT" via workspace.package so each crate publishes correctly. Workspace deps listed above are MIT/Apache-2.0 compatible; MIT alone satisfies every dep's downstream license obligation. The windows crate proxy/stub IDL re-emissions are flagged for legal review only if vendored from Microsoft headers — not applicable to typical windows-rs-generated code.