FOCAS Tier-C PR C — IPC path end-to-end #171

Merged
dohertj2 merged 1 commits from focas-tier-c-pr-c-ipc-proxy into v2 2026-04-20 14:13:35 -04:00
Owner

Third of 5 PRs splitting #220. Ships the wire path from IFocasClient calls in the .NET 10 driver, over a named-pipe or in-memory Stream, to the .NET 4.8 Host's FwlibFrameHandler, dispatched to an IFocasBackend. Keeps the existing IFocasClient DI seam untouched so in-process unit tests are unaffected.

Proxy side (.NET 10)

  • Ipc/FocasIpcClient — single-connection pipe client with call-gate to serialize concurrent callers; supports real NamedPipeClientStream and arbitrary Stream for in-memory loopback.
  • Ipc/IpcFocasClientIFocasClient forwarding every call as an IPC frame. Connect caches the SessionId; Read decodes typed values via FocasDataTypeCode; Write routes PMC bits through the first-class PmcBitWriteRequest so the RMW critical section stays on the Host.
  • Ipc/IpcFocasClientFactory — DI factory producing one IpcFocasClient per pipe connection.
  • FocasIpcException — surfaces Host ErrorResponse frames as typed exceptions.

Host side (.NET 4.8 x86)

  • Backend/IFocasBackend — the Host's view of a FOCAS session (Open/Close/Read/Write/PmcBitWrite/Probe).
  • Backend/FakeFocasBackend — in-memory, RMW-aware bit writes; used by tests + as an operational stub.
  • Backend/UnconfiguredFocasBackend — safe default returning structured failure pointing at docs/v2/focas-deployment.md.
  • Ipc/FwlibFrameHandler — replaces StubFrameHandler with real dispatch; catches backend exceptions as ErrorResponse instead of tearing down the pipe.
  • Program.cs picks backend from OTOPCUA_FOCAS_BACKEND env var.

Tests (13 new)

  • Proxy: 7 IPC round-trip tests via IpcLoopback — connect happy, connect rejection, read decode, write round-trip, PMC bit-write routes to RMW frame, probe, ErrorResponse → typed exception.
  • Host: 6 handler tests via FakeFocasBackend — OpenSession allocates id, read-without-session fails, full open/write/read preserves value, PmcBitWrite sets specified bit, Probe reports healthy, UnconfiguredBackend ErrorCode=NoFwlibBackend.

Total FOCAS-family tests green: 205 (172 driver + 24 Shared + 9 Host).

What's deferred

  • Real Fwlib32.dll P/Invoke inside the Host (FwlibHostedBackend) — hardware-dependent.
  • Supervisor + respawn: PR D.
  • MMF + NSSM install scripts: PR E.
Third of 5 PRs splitting #220. Ships the wire path from IFocasClient calls in the .NET 10 driver, over a named-pipe or in-memory Stream, to the .NET 4.8 Host's FwlibFrameHandler, dispatched to an IFocasBackend. Keeps the existing IFocasClient DI seam untouched so in-process unit tests are unaffected. ## Proxy side (.NET 10) - `Ipc/FocasIpcClient` — single-connection pipe client with call-gate to serialize concurrent callers; supports real `NamedPipeClientStream` and arbitrary `Stream` for in-memory loopback. - `Ipc/IpcFocasClient` — `IFocasClient` forwarding every call as an IPC frame. Connect caches the SessionId; Read decodes typed values via FocasDataTypeCode; Write routes PMC bits through the first-class PmcBitWriteRequest so the RMW critical section stays on the Host. - `Ipc/IpcFocasClientFactory` — DI factory producing one IpcFocasClient per pipe connection. - `FocasIpcException` — surfaces Host ErrorResponse frames as typed exceptions. ## Host side (.NET 4.8 x86) - `Backend/IFocasBackend` — the Host's view of a FOCAS session (Open/Close/Read/Write/PmcBitWrite/Probe). - `Backend/FakeFocasBackend` — in-memory, RMW-aware bit writes; used by tests + as an operational stub. - `Backend/UnconfiguredFocasBackend` — safe default returning structured failure pointing at `docs/v2/focas-deployment.md`. - `Ipc/FwlibFrameHandler` — replaces StubFrameHandler with real dispatch; catches backend exceptions as ErrorResponse instead of tearing down the pipe. - `Program.cs` picks backend from `OTOPCUA_FOCAS_BACKEND` env var. ## Tests (13 new) - Proxy: 7 IPC round-trip tests via `IpcLoopback` — connect happy, connect rejection, read decode, write round-trip, PMC bit-write routes to RMW frame, probe, ErrorResponse → typed exception. - Host: 6 handler tests via FakeFocasBackend — OpenSession allocates id, read-without-session fails, full open/write/read preserves value, PmcBitWrite sets specified bit, Probe reports healthy, UnconfiguredBackend ErrorCode=NoFwlibBackend. **Total FOCAS-family tests green: 205** (172 driver + 24 Shared + 9 Host). ## What's deferred - Real Fwlib32.dll P/Invoke inside the Host (`FwlibHostedBackend`) — hardware-dependent. - Supervisor + respawn: PR D. - MMF + NSSM install scripts: PR E.
dohertj2 added 1 commit 2026-04-20 14:13:25 -04:00
FOCAS Tier-C PR C — IPC path end-to-end: Proxy IpcFocasClient + Host FwlibFrameHandler + IFocasBackend abstraction. Third of 5 PRs for #220. Ships the wire path from IFocasClient calls in the .NET 10 driver, over a named-pipe (or in-memory stream) to the .NET 4.8 Host's FwlibFrameHandler, dispatched to an IFocasBackend. Keeps the existing IFocasClient DI seam intact so existing unit tests are unaffected (172/172 still pass). Proxy side adds Ipc/FocasIpcClient (owns one pipe stream + call gate so concurrent callers don't interleave frames, supports both real NamedPipeClientStream and arbitrary Stream for in-memory test loopback) and Ipc/IpcFocasClient (implements IFocasClient by forwarding every call as an IPC frame — Connect sends OpenSessionRequest and caches the SessionId; Read sends ReadRequest and decodes the typed value via FocasDataTypeCode; Write sends WriteRequest for non-bit data or PmcBitWriteRequest when it's a PMC bit so the RMW critical section stays on the Host; Probe sends ProbeRequest; Dispose best-effort sends CloseSessionRequest); plus FocasIpcException surfacing Host-side ErrorResponse frames as typed exceptions. Host side adds Backend/IFocasBackend (the Host's view of one FOCAS session — Open/Close/Read/Write/PmcBitWrite/Probe) with two implementations: FakeFocasBackend (in-memory, per-address value store, honors bit-write RMW semantics against the containing byte — used by tests and as an OTOPCUA_FOCAS_BACKEND=fake operational stub) and UnconfiguredFocasBackend (structured failure pointing at docs/v2/focas-deployment.md — the safe default when OTOPCUA_FOCAS_BACKEND is unset or hardware isn't configured). Ipc/FwlibFrameHandler replaces StubFrameHandler: deserializes each request DTO, delegates to the IFocasBackend, re-serializes into the matching response kind. Catches backend exceptions and surfaces them as ErrorResponse{backend-exception} rather than tearing down the pipe. Program.cs now picks the backend from OTOPCUA_FOCAS_BACKEND env var (fake/unconfigured/fwlib32; fwlib32 still maps to Unconfigured because the real Fwlib32 P/Invoke integration is a hardware-dependent follow-up — #220 captures it). Tests: 7 new IPC round-trip tests on the Proxy side (IpcFocasClient vs. an IpcLoopback fake server: connect happy path, connect rejection, read decode, write round-trip, PMC bit write routes to first-class RMW frame, probe, ErrorResponse surfaces as typed exception) + 6 new Host-side tests on FwlibFrameHandler (OpenSession allocates id, read-without-session fails, full open/write/read round-trip preserves value, PmcBitWrite sets the specified bit, Probe reports healthy with open session, UnconfiguredBackend returns pointed-at-docs error with ErrorCode=NoFwlibBackend). Existing 165 FOCAS unit tests + 24 Shared tests + 3 Host handshake tests all unchanged. Total post-PR: 172+24+9 = 205 FOCAS-family tests green. What's NOT in this PR: the actual Fwlib32.dll P/Invoke integration inside the Host (FwlibHostedBackend) lands as a hardware-dependent follow-up since no CNC is available for validation; supervisor + respawn + crash-loop breaker comes in PR D; MMF + NSSM install scripts in PR E. 3892555631
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 9034294b77 into v2 2026-04-20 14:13:35 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dohertj2/lmxopcua#171