docs: add LmxProxy requirements documentation with v2 protocol as authoritative design
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>
This commit is contained in:
86
lmxproxy/docs/requirements/Component-GrpcServer.md
Normal file
86
lmxproxy/docs/requirements/Component-GrpcServer.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# Component: GrpcServer
|
||||
|
||||
## Purpose
|
||||
|
||||
The gRPC service implementation that receives client RPCs, validates sessions, and delegates operations to the MxAccessClient. It is the network-facing entry point for all SCADA operations.
|
||||
|
||||
## Location
|
||||
|
||||
`src/ZB.MOM.WW.LmxProxy.Host/Grpc/ScadaGrpcService.cs` — inherits proto-generated `ScadaService.ScadaServiceBase`.
|
||||
|
||||
## Responsibilities
|
||||
|
||||
- Implement all 10 gRPC RPCs defined in `scada.proto`.
|
||||
- Validate session IDs on all data operations before processing.
|
||||
- Delegate read/write/subscribe operations to the MxAccessClient.
|
||||
- Convert between gRPC message types and internal domain types (Vtq, Quality).
|
||||
- Track operation timing and success/failure via PerformanceMetrics.
|
||||
- Handle errors gracefully, returning structured error responses rather than throwing.
|
||||
|
||||
## 1. RPC Implementations
|
||||
|
||||
### 1.1 Connection Management
|
||||
|
||||
- **Connect**: Creates a new session via SessionManager if MxAccess is connected. Returns the session ID (32-character hex GUID). Rejects if MxAccess is disconnected.
|
||||
- **Disconnect**: Terminates the session via SessionManager.
|
||||
- **GetConnectionState**: Returns `IsConnected`, `ClientId`, and `ConnectedSinceUtcTicks` from the MxAccessClient.
|
||||
|
||||
### 1.2 Read Operations
|
||||
|
||||
- **Read**: Validates session, applies Polly retry policy, calls MxAccessClient.ReadAsync(), returns VtqMessage. On invalid session, returns a VtqMessage with `Quality.Bad`.
|
||||
- **ReadBatch**: Validates session, reads all tags via MxAccessClient.ReadBatchAsync() with semaphore-controlled concurrency (max 10 concurrent). Returns results in request order. Batch reads are partially successful — individual tags may have Bad quality (with current UTC timestamp) while the overall response succeeds. If a tag read throws an exception, its VTQ is returned with Bad quality.
|
||||
|
||||
### 1.3 Write Operations
|
||||
|
||||
- **Write**: Validates session, parses the string value using the type heuristic, calls MxAccessClient.WriteAsync().
|
||||
- **WriteBatch**: Validates session, writes all items in parallel via MxAccessClient with semaphore concurrency control. Returns per-item success/failure results. Overall `success` is `false` if any item fails (all-or-nothing at the reporting level).
|
||||
- **WriteBatchAndWait**: Validates session, writes all items first. If any write fails, returns immediately with `success=false`. If writes succeed, polls `flag_tag` at `poll_interval_ms` intervals using type-aware `TypedValueEquals()` comparison (same oneof case required, native type equality, case-sensitive strings, null equals null only). Default timeout: 5000ms, default poll interval: 100ms. If flag matches before timeout: `success=true`, `flag_reached=true`. If timeout expires: `success=true`, `flag_reached=false` (timeout is not an error). Returns `flag_reached` boolean and `elapsed_ms`.
|
||||
|
||||
### 1.4 Subscription
|
||||
|
||||
- **Subscribe**: Validates session (throws `RpcException(Unauthenticated)` on invalid). Creates a subscription handle via SubscriptionManager. Streams VtqMessage items from the subscription channel to the client. Cleans up the subscription on stream cancellation or error.
|
||||
|
||||
### 1.5 API Key Check
|
||||
|
||||
- **CheckApiKey**: Returns validity and role information from the interceptor context.
|
||||
|
||||
## 2. Value and Quality Handling
|
||||
|
||||
### 2.1 Values (TypedValue)
|
||||
|
||||
Read responses and subscription updates return values as `TypedValue` (protobuf oneof carrying native types). Write requests receive `TypedValue` and apply the value directly to MxAccess by its native type. If the `oneof` case doesn't match the tag's expected data type, the write returns `WriteResult` with `success=false` indicating type mismatch. No string serialization or parsing heuristics are used.
|
||||
|
||||
### 2.2 Quality (QualityCode)
|
||||
|
||||
Quality is returned as a `QualityCode` message with `uint32 status_code` (OPC UA-compatible) and `string symbolic_name`. The server maps MxAccess quality codes to OPC UA status codes per the quality table in Component-Protocol. Specific error scenarios return specific quality codes (e.g., tag not found → `BadConfigurationError`, comms loss → `BadCommunicationFailure`).
|
||||
|
||||
### 2.3 Current Implementation (V1 Legacy)
|
||||
|
||||
The current codebase still uses v1 string-based encoding. During v2 migration, the following v1 behavior will be removed:
|
||||
- `ConvertValueToString()` — serializes values to strings (bool → lowercase, DateTime → ISO-8601, arrays → JSON, others → `.ToString()`).
|
||||
- `ParseValue()` — parses string values in order: bool → int → long → double → DateTime → raw string.
|
||||
- Three-state string quality mapping: ≥192 → `"Good"`, 64–191 → `"Uncertain"`, <64 → `"Bad"`.
|
||||
|
||||
## 3. Error Handling
|
||||
|
||||
- All RPC methods catch exceptions and return error responses with `success=false` and a descriptive message. Exceptions do not propagate as gRPC status codes (except Subscribe, which throws `RpcException` for invalid sessions).
|
||||
- Each operation is wrapped in a PerformanceMetrics timing scope that records duration and success/failure.
|
||||
|
||||
## 4. Session Validation
|
||||
|
||||
- All data operations (Read, ReadBatch, Write, WriteBatch, WriteBatchAndWait, Subscribe) validate the session ID before processing.
|
||||
- Invalid session on read/write operations returns a response with Bad quality VTQ.
|
||||
- Invalid session on Subscribe throws `RpcException` with `StatusCode.Unauthenticated`.
|
||||
|
||||
## Dependencies
|
||||
|
||||
- **MxAccessClient** (IScadaClient) — all SCADA operations are delegated here.
|
||||
- **SessionManager** — session creation, validation, and termination.
|
||||
- **SubscriptionManager** — subscription lifecycle for the Subscribe RPC.
|
||||
- **PerformanceMetrics** — operation timing and success/failure tracking.
|
||||
|
||||
## Interactions
|
||||
|
||||
- **ApiKeyInterceptor** intercepts all RPCs before they reach ScadaGrpcService, enforcing API key authentication and role-based write authorization.
|
||||
- **SubscriptionManager** provides the channel that Subscribe streams from.
|
||||
- **StatusReportService** reads PerformanceMetrics data that ScadaGrpcService populates.
|
||||
Reference in New Issue
Block a user