Generate high-level requirements and 10 component documents derived from source code and protocol specs. Uses lmxproxy_updates.md (v2 TypedValue/QualityCode) as the source of truth, with v1 string-based encoding documented as legacy context. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
72 lines
4.5 KiB
Markdown
72 lines
4.5 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## What This Is
|
|
|
|
LmxProxy is a gRPC proxy that bridges ScadaLink's Data Connection Layer to AVEVA System Platform via the ArchestrA MXAccess COM API. It has two projects:
|
|
|
|
- **Host** (`ZB.MOM.WW.LmxProxy.Host`) — .NET Framework 4.8, x86-only Windows service. Hosts a gRPC server (Grpc.Core) that fronts an MxAccessClient talking to ArchestrA MXAccess. Runs as a Windows service via Topshelf.
|
|
- **Client** (`ZB.MOM.WW.LmxProxy.Client`) — .NET 10, AnyCPU library. Code-first gRPC client (protobuf-net.Grpc) consumed by ScadaLink's DCL. This is a NuGet-packable library.
|
|
|
|
The two projects use **different gRPC stacks**: Host uses proto-file-generated code (`Grpc.Core` + `Grpc.Tools`), Client uses code-first contracts (`protobuf-net.Grpc` with `[DataContract]`/`[ServiceContract]` attributes). They are wire-compatible because both target the same `scada.ScadaService` gRPC service.
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
dotnet build ZB.MOM.WW.LmxProxy.slnx # Build entire solution
|
|
dotnet build src/ZB.MOM.WW.LmxProxy.Host # Host only (requires x86 platform)
|
|
dotnet build src/ZB.MOM.WW.LmxProxy.Client # Client only
|
|
```
|
|
|
|
The Host project requires the `ArchestrA.MXAccess.dll` COM interop assembly in `lib/`. It targets x86 exclusively (MXAccess is 32-bit COM).
|
|
|
|
## Architecture
|
|
|
|
### Host Service Startup Chain
|
|
|
|
`Program.Main` → Topshelf `HostFactory` → `LmxProxyService.Start()` which:
|
|
1. Validates configuration (`appsettings.json` bound to `LmxProxyConfiguration`)
|
|
2. Creates `MxAccessClient` (the `IScadaClient` impl that wraps ArchestrA.MXAccess COM)
|
|
3. Connects to MxAccess synchronously at startup
|
|
4. Starts connection monitor loop (auto-reconnect)
|
|
5. Creates `SubscriptionManager`, `SessionManager`, `PerformanceMetrics`, `ApiKeyService`
|
|
6. Creates `ScadaGrpcService` (the proto-generated service impl) with all dependencies
|
|
7. Starts Grpc.Core `Server` on configured port (default 50051)
|
|
8. Starts HTTP status web server (default port 8080)
|
|
|
|
### Key Host Components
|
|
|
|
- `MxAccessClient` — Partial class split across 6 files (Connection, ReadWrite, Subscription, EventHandlers, NestedTypes, main). Wraps `LMXProxyServer` COM object. Uses semaphores for concurrency control.
|
|
- `ScadaGrpcService` — Inherits proto-generated `ScadaService.ScadaServiceBase`. All RPCs validate session first, then delegate to `IScadaClient`. Values are string-serialized on the wire (v1 protocol).
|
|
- `SessionManager` — Tracks client sessions by GUID.
|
|
- `SubscriptionManager` — Manages MxAccess subscriptions, fans out updates via `System.Threading.Channels`.
|
|
- `ApiKeyInterceptor` — gRPC server interceptor for API key validation.
|
|
|
|
### Client Architecture
|
|
|
|
- `ILmxProxyClient` — Public interface for consumers. Connect/Read/Write/Subscribe/Dispose.
|
|
- `LmxProxyClient` — Partial class split across multiple files (Connection, Subscription, Metrics, etc.). Uses `protobuf-net.Grpc` code-first contracts (`IScadaService` in `Domain/ScadaContracts.cs`).
|
|
- `LmxProxyClientBuilder` — Fluent builder for configuring client instances.
|
|
- `Domain/ScadaContracts.cs` — All gRPC message types as `[DataContract]` POCOs and the `IScadaService` interface with `[ServiceContract]`.
|
|
- Value conversion: Client parses string values from wire using double → bool → string heuristic in `ConvertToVtq()`. Writes use `.ToString()` via `ConvertToString()`.
|
|
|
|
### Protocol
|
|
|
|
Proto definition: `src/ZB.MOM.WW.LmxProxy.Host/Grpc/Protos/scada.proto`
|
|
|
|
Currently v1 protocol (string-encoded values, string quality). A v2 protocol spec exists in `docs/lmxproxy_updates.md` that introduces `TypedValue` (protobuf oneof) and `QualityCode` (OPC UA status codes) — not yet implemented.
|
|
|
|
RPCs: Connect, Disconnect, GetConnectionState, Read, ReadBatch, Write, WriteBatch, WriteBatchAndWait, Subscribe (server streaming), CheckApiKey.
|
|
|
|
### Configuration
|
|
|
|
Host configured via `appsettings.json` bound to `LmxProxyConfiguration`. Key sections: GrpcPort, Connection (timeouts, auto-reconnect), Subscription (channel capacity), Tls, WebServer, Serilog, RetryPolicies, HealthCheck.
|
|
|
|
## Important Constraints
|
|
|
|
- Host **must** target x86 and .NET Framework 4.8 (ArchestrA.MXAccess is 32-bit COM interop).
|
|
- Host uses `Grpc.Core` (the deprecated C-core gRPC library), not `Grpc.Net`. This is required because .NET 4.8 doesn't support `Grpc.Net.Server`.
|
|
- Client uses `Grpc.Net.Client` and targets .NET 10 — it runs in the ScadaLink central/site clusters.
|
|
- The solution file is `.slnx` format (XML-based, not the older text format).
|