# 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.
