Files
scadalink-design/lmxproxy/docs/requirements/Component-GrpcServer.md
Joseph Doherty 683aea0fbe 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>
2026-03-21 22:38:11 -04:00

5.8 KiB
Raw Blame History

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.