using Grpc.Core; using ZB.MOM.WW.MxGateway.Contracts.Proto; namespace ZB.MOM.WW.MxGateway.Client; /// /// gRPC implementation of IMxGatewayClientTransport. /// internal sealed class GrpcMxGatewayClientTransport( MxGatewayClientOptions options, MxAccessGateway.MxAccessGatewayClient rawClient) : IMxGatewayClientTransport { /// /// Gets the gateway client options. /// public MxGatewayClientOptions Options { get; } = options; /// /// Gets the underlying gRPC client. /// public MxAccessGateway.MxAccessGatewayClient RawClient { get; } = rawClient; /// MxAccessGateway.MxAccessGatewayClient? IMxGatewayClientTransport.RawClient => RawClient; /// public async Task OpenSessionAsync( OpenSessionRequest request, CallOptions callOptions) { try { return await RawClient.OpenSessionAsync(request, callOptions) .ResponseAsync .ConfigureAwait(false); } catch (RpcException exception) { throw MapRpcException(exception, callOptions.CancellationToken); } } /// public async Task CloseSessionAsync( CloseSessionRequest request, CallOptions callOptions) { try { return await RawClient.CloseSessionAsync(request, callOptions) .ResponseAsync .ConfigureAwait(false); } catch (RpcException exception) { throw MapRpcException(exception, callOptions.CancellationToken); } } /// public async Task InvokeAsync( MxCommandRequest request, CallOptions callOptions) { try { return await RawClient.InvokeAsync(request, callOptions) .ResponseAsync .ConfigureAwait(false); } catch (RpcException exception) { throw MapRpcException(exception, callOptions.CancellationToken); } } /// public async IAsyncEnumerable StreamEventsAsync( StreamEventsRequest request, CallOptions callOptions, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) { CancellationToken effectiveCancellationToken = cancellationToken.CanBeCanceled ? cancellationToken : callOptions.CancellationToken; using AsyncServerStreamingCall call = RawClient.StreamEvents(request, callOptions); IAsyncStreamReader responseStream = call.ResponseStream; while (true) { MxEvent? gatewayEvent; try { if (!await responseStream.MoveNext(effectiveCancellationToken).ConfigureAwait(false)) { break; } gatewayEvent = responseStream.Current; } catch (RpcException exception) { throw MapRpcException(exception, effectiveCancellationToken); } yield return gatewayEvent; } } /// IAsyncEnumerable IMxGatewayClientTransport.StreamEventsAsync( StreamEventsRequest request, CallOptions callOptions) { return StreamEventsAsync(request, callOptions); } /// public async Task AcknowledgeAlarmAsync( AcknowledgeAlarmRequest request, CallOptions callOptions) { try { return await RawClient.AcknowledgeAlarmAsync(request, callOptions) .ResponseAsync .ConfigureAwait(false); } catch (RpcException exception) { throw MapRpcException(exception, callOptions.CancellationToken); } } /// public async IAsyncEnumerable QueryActiveAlarmsAsync( QueryActiveAlarmsRequest request, CallOptions callOptions, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) { CancellationToken effectiveCancellationToken = cancellationToken.CanBeCanceled ? cancellationToken : callOptions.CancellationToken; using AsyncServerStreamingCall call = RawClient.QueryActiveAlarms(request, callOptions); IAsyncStreamReader responseStream = call.ResponseStream; while (true) { ActiveAlarmSnapshot? snapshot; try { if (!await responseStream.MoveNext(effectiveCancellationToken).ConfigureAwait(false)) { break; } snapshot = responseStream.Current; } catch (RpcException exception) { throw MapRpcException(exception, effectiveCancellationToken); } yield return snapshot; } } /// IAsyncEnumerable IMxGatewayClientTransport.QueryActiveAlarmsAsync( QueryActiveAlarmsRequest request, CallOptions callOptions) { return QueryActiveAlarmsAsync(request, callOptions); } /// public async IAsyncEnumerable StreamAlarmsAsync( StreamAlarmsRequest request, CallOptions callOptions, [System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default) { CancellationToken effectiveCancellationToken = cancellationToken.CanBeCanceled ? cancellationToken : callOptions.CancellationToken; using AsyncServerStreamingCall call = RawClient.StreamAlarms(request, callOptions); IAsyncStreamReader responseStream = call.ResponseStream; while (true) { AlarmFeedMessage? message; try { if (!await responseStream.MoveNext(effectiveCancellationToken).ConfigureAwait(false)) { break; } message = responseStream.Current; } catch (RpcException exception) { throw MapRpcException(exception, effectiveCancellationToken); } yield return message; } } /// IAsyncEnumerable IMxGatewayClientTransport.StreamAlarmsAsync( StreamAlarmsRequest request, CallOptions callOptions) { return StreamAlarmsAsync(request, callOptions); } private static Exception MapRpcException( RpcException exception, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested || exception.StatusCode == StatusCode.Cancelled) { return new OperationCanceledException( exception.Status.Detail, exception, cancellationToken); } return exception.StatusCode switch { StatusCode.Unauthenticated => new MxGatewayAuthenticationException( exception.Status.Detail, innerException: exception), StatusCode.PermissionDenied => new MxGatewayAuthorizationException( exception.Status.Detail, innerException: exception), _ => new MxGatewayException(exception.Status.Detail, exception), }; } }