Files
scadalink-design/deprecated/lmxproxy/docs/requirements/Component-GrpcServer.md
Joseph Doherty 9dccf8e72f deprecate(lmxproxy): move all LmxProxy code, tests, and docs to deprecated/
LmxProxy is no longer needed. Moved the entire lmxproxy/ workspace, DCL
adapter files, and related docs to deprecated/. Removed LmxProxy registration
from DataConnectionFactory, project reference from DCL, protocol option from
UI, and cleaned up all requirement docs.
2026-04-08 15:56:23 -04:00

87 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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"`, 64191 → `"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.