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.
5.8 KiB
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, andConnectedSinceUtcTicksfrom 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
successisfalseif 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, pollsflag_tagatpoll_interval_msintervals using type-awareTypedValueEquals()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). Returnsflag_reachedboolean andelapsed_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=falseand a descriptive message. Exceptions do not propagate as gRPC status codes (except Subscribe, which throwsRpcExceptionfor 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
RpcExceptionwithStatusCode.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.