Skip to content

Commit f69e827

Browse files
Grpc transport based class (#87)
* Make ClientBase abstract class * Create GrpcTransport.cs based class like Java SDK * Fix issue * fix linter
1 parent 8c88e2e commit f69e827

File tree

4 files changed

+139
-20
lines changed

4 files changed

+139
-20
lines changed

src/Ydb.Sdk/src/Driver.cs

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -294,23 +294,9 @@ private CallOptions GetCallOptions(RequestSettings settings, bool streaming)
294294
return options;
295295
}
296296

297-
private static StatusCode ConvertStatusCode(Grpc.Core.StatusCode rpcStatusCode)
298-
{
299-
return rpcStatusCode switch
300-
{
301-
Grpc.Core.StatusCode.Unavailable => StatusCode.ClientTransportUnavailable,
302-
Grpc.Core.StatusCode.DeadlineExceeded => StatusCode.ClientTransportTimeout,
303-
Grpc.Core.StatusCode.ResourceExhausted => StatusCode.ClientTransportResourceExhausted,
304-
Grpc.Core.StatusCode.Unimplemented => StatusCode.ClientTransportUnimplemented,
305-
_ => StatusCode.ClientTransportUnknown
306-
};
307-
}
308-
309297
private static Status ConvertStatus(Grpc.Core.Status rpcStatus)
310298
{
311-
return new Status(
312-
ConvertStatusCode(rpcStatus.StatusCode),
313-
new List<Issue> { new(rpcStatus.Detail) });
299+
return rpcStatus.ConvertStatus();
314300
}
315301

316302
internal sealed class UnaryResponse<TResponse>

src/Ydb.Sdk/src/DriverConfig.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,10 @@ namespace Ydb.Sdk;
66
public class DriverConfig
77
{
88
public string Endpoint { get; }
9-
109
public string Database { get; }
11-
1210
public ICredentialsProvider Credentials { get; }
13-
1411
public X509Certificate? CustomServerCertificate { get; }
15-
1612
public TimeSpan DefaultTransportTimeout { get; }
17-
1813
public TimeSpan DefaultStreamingTransportTimeout { get; }
1914

2015
internal TimeSpan EndpointDiscoveryInterval = TimeSpan.FromMinutes(1);

src/Ydb.Sdk/src/GrpcTransport.cs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using Grpc.Core;
2+
using Grpc.Net.Client;
3+
using Microsoft.Extensions.Logging;
4+
5+
namespace Ydb.Sdk;
6+
7+
// TODO Experimental [for Driver with fix call options]
8+
public abstract class GrpcTransport : IDisposable, IAsyncDisposable
9+
{
10+
protected readonly ILogger Logger;
11+
protected readonly DriverConfig Config;
12+
13+
internal GrpcTransport(DriverConfig driverConfig, ILogger logger)
14+
{
15+
Logger = logger;
16+
Config = driverConfig;
17+
}
18+
19+
~GrpcTransport()
20+
{
21+
Dispose(false);
22+
}
23+
24+
public void Dispose()
25+
{
26+
Dispose(true);
27+
GC.SuppressFinalize(this);
28+
}
29+
30+
public ValueTask DisposeAsync()
31+
{
32+
Dispose(true);
33+
GC.SuppressFinalize(this);
34+
return default;
35+
}
36+
37+
protected abstract void Dispose(bool disposing);
38+
39+
internal async Task<TResponse> UnaryCall<TRequest, TResponse>(
40+
Method<TRequest, TResponse> method,
41+
RequestSettings settings,
42+
TRequest request
43+
) where TRequest : class where TResponse : class
44+
{
45+
var (endpoint, channel) = GetChannel();
46+
var callInvoker = channel.CreateCallInvoker();
47+
48+
Logger.LogTrace("Unary call, method: {MethodName}, endpoint: {Endpoint}", method.Name, endpoint);
49+
50+
try
51+
{
52+
using var call = callInvoker.AsyncUnaryCall(
53+
method: method,
54+
host: null,
55+
options: GetCallOptions(settings, false),
56+
request: request
57+
);
58+
59+
return await call.ResponseAsync;
60+
}
61+
catch (RpcException e)
62+
{
63+
OnRpcError(endpoint, e);
64+
throw new TransportException(e);
65+
}
66+
}
67+
68+
protected abstract (string, GrpcChannel) GetChannel();
69+
70+
protected abstract void OnRpcError(string endpoint, RpcException e);
71+
72+
private CallOptions GetCallOptions(RequestSettings settings, bool streaming)
73+
{
74+
var meta = new Grpc.Core.Metadata
75+
{
76+
{ Metadata.RpcDatabaseHeader, Config.Database }
77+
};
78+
79+
var authInfo = Config.Credentials.GetAuthInfo();
80+
if (authInfo != null)
81+
{
82+
meta.Add(Metadata.RpcAuthHeader, authInfo);
83+
}
84+
85+
if (settings.TraceId.Length > 0)
86+
{
87+
meta.Add(Metadata.RpcTraceIdHeader, settings.TraceId);
88+
}
89+
90+
var transportTimeout = streaming
91+
? Config.DefaultStreamingTransportTimeout
92+
: Config.DefaultTransportTimeout;
93+
94+
if (settings.TransportTimeout != null)
95+
{
96+
transportTimeout = settings.TransportTimeout.Value;
97+
}
98+
99+
var options = new CallOptions(
100+
headers: meta
101+
);
102+
103+
if (transportTimeout != TimeSpan.Zero)
104+
{
105+
options = options.WithDeadline(DateTime.UtcNow + transportTimeout);
106+
}
107+
108+
return options;
109+
}
110+
}
111+
112+
public class TransportException : Exception
113+
{
114+
internal TransportException(RpcException e) : base($"Transport exception: {e.Message}", e)
115+
{
116+
Status = e.Status.ConvertStatus();
117+
}
118+
119+
public Status Status { get; }
120+
}

src/Ydb.Sdk/src/Status.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,3 +247,21 @@ public StatusUnsuccessfulException(Status status)
247247

248248
public Status Status { get; }
249249
}
250+
251+
internal static class StatusExtensions
252+
{
253+
internal static Status ConvertStatus(this Grpc.Core.Status rpcStatus)
254+
{
255+
return new Status(
256+
rpcStatus.StatusCode switch
257+
{
258+
Grpc.Core.StatusCode.Unavailable => StatusCode.ClientTransportUnavailable,
259+
Grpc.Core.StatusCode.DeadlineExceeded => StatusCode.ClientTransportTimeout,
260+
Grpc.Core.StatusCode.ResourceExhausted => StatusCode.ClientTransportResourceExhausted,
261+
Grpc.Core.StatusCode.Unimplemented => StatusCode.ClientTransportUnimplemented,
262+
_ => StatusCode.ClientTransportUnknown
263+
},
264+
new List<Issue> { new(rpcStatus.Detail) }
265+
);
266+
}
267+
}

0 commit comments

Comments
 (0)