8023eccfa6
Client.Dotnet-001: MapRpcException typed only Unauthenticated and PermissionDenied; every other gRPC status collapsed to an untyped exception with the status code discarded. Added a nullable StatusCode to MxGatewayException, extracted the duplicated mappers into a shared RpcExceptionMapper that records the code for every status, and documented it. Client.Dotnet-002: the production retry branch (MxGatewayException wrapping RpcException) was never exercised. FakeGatewayTransport gained a MapTransportExceptions mode that runs thrown RpcExceptions through RpcExceptionMapper exactly as the production transport does. Client.Dotnet-003: MxGatewaySession.DisposeAsync disposed _closeLock while a concurrent CloseAsync could be parked in WaitAsync. DisposeAsync now drains in-flight CloseAsync callers before disposing the semaphore; the client's _disposed flag is accessed via Interlocked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
119 lines
3.7 KiB
C#
119 lines
3.7 KiB
C#
using Grpc.Core;
|
|
using MxGateway.Contracts.Proto.Galaxy;
|
|
|
|
namespace MxGateway.Client;
|
|
|
|
/// <summary>
|
|
/// gRPC implementation of IGalaxyRepositoryClientTransport.
|
|
/// </summary>
|
|
internal sealed class GrpcGalaxyRepositoryClientTransport(
|
|
MxGatewayClientOptions options,
|
|
GalaxyRepository.GalaxyRepositoryClient rawClient) : IGalaxyRepositoryClientTransport
|
|
{
|
|
/// <summary>
|
|
/// Gets the gateway client options.
|
|
/// </summary>
|
|
public MxGatewayClientOptions Options { get; } = options;
|
|
|
|
/// <summary>
|
|
/// Gets the underlying gRPC client.
|
|
/// </summary>
|
|
public GalaxyRepository.GalaxyRepositoryClient RawClient { get; } = rawClient;
|
|
|
|
/// <inheritdoc />
|
|
GalaxyRepository.GalaxyRepositoryClient? IGalaxyRepositoryClientTransport.RawClient => RawClient;
|
|
|
|
/// <inheritdoc />
|
|
public async Task<TestConnectionReply> TestConnectionAsync(
|
|
TestConnectionRequest request,
|
|
CallOptions callOptions)
|
|
{
|
|
try
|
|
{
|
|
return await RawClient.TestConnectionAsync(request, callOptions)
|
|
.ResponseAsync
|
|
.ConfigureAwait(false);
|
|
}
|
|
catch (RpcException exception)
|
|
{
|
|
throw RpcExceptionMapper.Map(exception, callOptions.CancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<GetLastDeployTimeReply> GetLastDeployTimeAsync(
|
|
GetLastDeployTimeRequest request,
|
|
CallOptions callOptions)
|
|
{
|
|
try
|
|
{
|
|
return await RawClient.GetLastDeployTimeAsync(request, callOptions)
|
|
.ResponseAsync
|
|
.ConfigureAwait(false);
|
|
}
|
|
catch (RpcException exception)
|
|
{
|
|
throw RpcExceptionMapper.Map(exception, callOptions.CancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<DiscoverHierarchyReply> DiscoverHierarchyAsync(
|
|
DiscoverHierarchyRequest request,
|
|
CallOptions callOptions)
|
|
{
|
|
try
|
|
{
|
|
return await RawClient.DiscoverHierarchyAsync(request, callOptions)
|
|
.ResponseAsync
|
|
.ConfigureAwait(false);
|
|
}
|
|
catch (RpcException exception)
|
|
{
|
|
throw RpcExceptionMapper.Map(exception, callOptions.CancellationToken);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async IAsyncEnumerable<DeployEvent> WatchDeployEventsAsync(
|
|
WatchDeployEventsRequest request,
|
|
CallOptions callOptions,
|
|
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken cancellationToken = default)
|
|
{
|
|
CancellationToken effectiveCancellationToken = cancellationToken.CanBeCanceled
|
|
? cancellationToken
|
|
: callOptions.CancellationToken;
|
|
|
|
using AsyncServerStreamingCall<DeployEvent> call = RawClient.WatchDeployEvents(request, callOptions);
|
|
|
|
IAsyncStreamReader<DeployEvent> responseStream = call.ResponseStream;
|
|
while (true)
|
|
{
|
|
DeployEvent? deployEvent;
|
|
try
|
|
{
|
|
if (!await responseStream.MoveNext(effectiveCancellationToken).ConfigureAwait(false))
|
|
{
|
|
break;
|
|
}
|
|
|
|
deployEvent = responseStream.Current;
|
|
}
|
|
catch (RpcException exception)
|
|
{
|
|
throw RpcExceptionMapper.Map(exception, effectiveCancellationToken);
|
|
}
|
|
|
|
yield return deployEvent;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
IAsyncEnumerable<DeployEvent> IGalaxyRepositoryClientTransport.WatchDeployEventsAsync(
|
|
WatchDeployEventsRequest request,
|
|
CallOptions callOptions)
|
|
{
|
|
return WatchDeployEventsAsync(request, callOptions);
|
|
}
|
|
}
|