Files
mxaccess/rust
Joseph Doherty 9063f10b1b
rust / build / test / clippy / fmt (push) Has been cancelled
[M5] mxaccess-asb: register_items retry on InvalidConnectionId — LIVE PATH WORKS
End-to-end live path now functional: Connect → AuthenticateMe →
RegisterItems → Read → Disconnect. The example reads back the live
TestChildObject.TestInt value (99) over the wire on the first run.

Root-cause of the previous "InvalidConnectionId" mystery: it was
never an HMAC verification failure. `AuthenticateMe` is one-way
(`AsbContracts.cs:18`) and the server commits auth state
asynchronously after the request lands. A Register that follows too
quickly sees the connection in pre-authenticated state and returns
`AsbErrorCode.InvalidConnectionId` (= 1).

.NET's `MxAsbDataClient.RegisterMany` (`cs:191-204`) handles this
explicitly with a retry loop:

  for (int attempt = 1; attempt < 5
       && response.Result.ErrorCode == InvalidConnectionId; attempt++)
  {
      Thread.Sleep(TimeSpan.FromMilliseconds(100 * attempt));
      response = RegisterOnce(items);
  }

We now mirror the same pattern in `AsbClient::register_items_once`
followed by a retry loop in `register_items` — up to 5 attempts with
`100 * attempt` ms backoff.

Supporting changes:
- `RegisterItemsResponse` gains `result_code: Option<u32>` +
  `success: Option<bool>` so callers can read `Result.resultCodeField`
  + `successField` from the response. `decode_register_items_response`
  now tolerates an empty `<ASBIData />` Status array (server returns
  empty when the operation fails server-side) instead of erroring
  with `MissingField`. New helper `find_text_in_named_element` walks
  the body token stream.
- New public constant `RESULT_CODE_INVALID_CONNECTION_ID = 1` for
  callers that want to detect this status outside the retry path.
- The previously-failing test `decode_register_items_response_returns_
  missing_field_when_status_absent` was renamed and rewritten as
  `decode_register_items_response_returns_empty_status_when_absent`
  to match the new tolerant decode contract.

F31 closed. F30 (read-side dict-id resolution, landed in `eb6c689`)
was the unblocker — without it we couldn't see the
`<resultCodeField>1</>` element in the response and the failure mode
looked like a HMAC mismatch instead of a transient retryable error.

Workspace: 711 unit tests pass. Clippy clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:02:38 -04:00
..

mxaccess (Rust port)

Native Rust replacement for AVEVA / Wonderware MXAccess. See ../design/ for the architectural specification, ../src/ for the .NET reference (the executable spec), and ../CLAUDE.md for project-wide rules.

Status

M0 — Workspace skeleton. Stub types compile; nothing is implemented yet. See ../design/60-roadmap.md for the M0M6 milestone plan.

Layout

rust/
  Cargo.toml                 workspace root
  rust-toolchain.toml        1.85 stable
  crates/
    mxaccess-codec/          pure protocol codec, no I/O
    mxaccess-galaxy/         Galaxy SQL resolver (tiberius)
    mxaccess-rpc/            DCE/RPC + NTLMv2 + OXID + OBJREF
    mxaccess-callback/       INmxSvcCallback RPC server
    mxaccess-nmx/            INmxService2 client
    mxaccess-asb-nettcp/     net.tcp framing (MC-NMF + MC-NBFX/NBFS)
    mxaccess-asb/            IASBIDataV2 client
    mxaccess/                async session + Transport trait + public API
    mxaccess-compat/         LMXProxyServer-shaped facade

Build

cargo build --workspace
cargo test --workspace
cargo clippy --workspace -- -D warnings
cargo fmt --check

Live probes

. ..\tools\Setup-LiveProbeEnv.ps1
cargo test -p mxaccess --features live -- --ignored

The setup script fetches credentials from Infisical via wwtools/secrets/Get-Secret.ps1. Never inline plaintext credentials.

License

MIT — see ../LICENSE.