[#28] Client: Use external GRPC Channnel

Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
Pavel Gross 2024-12-06 09:01:33 +03:00
parent 9bb7b5eff8
commit c9418a1894
27 changed files with 520 additions and 438 deletions

View file

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Frostfs.V2.Ape;
@ -12,7 +11,6 @@ using FrostFS.Session;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Options;
@ -27,8 +25,6 @@ namespace FrostFS.SDK.Client;
public class FrostFSClient : IFrostFSClient
{
private bool isDisposed;
internal ContainerServiceClient? ContainerServiceClient { get; set; }
internal ContainerServiceProvider? ContainerServiceProvider { get; set; }
@ -49,9 +45,19 @@ public class FrostFSClient : IFrostFSClient
internal ClientContext ClientCtx { get; set; }
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, Func<string, ChannelBase> grpcChannelFactory)
{
return new FrostFSClient(clientOptions, channelOptions);
if (clientOptions is null)
{
throw new ArgumentNullException(nameof(clientOptions));
}
if (grpcChannelFactory is null)
{
throw new ArgumentNullException(nameof(grpcChannelFactory));
}
return new FrostFSClient(clientOptions, grpcChannelFactory);
}
/// <summary>
@ -66,7 +72,7 @@ public class FrostFSClient : IFrostFSClient
/// <returns></returns>
public static IFrostFSClient GetTestInstance(
IOptions<ClientSettings> settings,
GrpcChannelOptions? channelOptions,
Func<string, ChannelBase> grpcChannelFactory,
NetmapServiceClient netmapService,
SessionServiceClient sessionService,
ContainerServiceClient containerService,
@ -77,12 +83,38 @@ public class FrostFSClient : IFrostFSClient
throw new ArgumentNullException(nameof(settings));
}
return new FrostFSClient(settings, channelOptions, containerService, netmapService, sessionService, objectService);
if (grpcChannelFactory is null)
{
throw new ArgumentNullException(nameof(grpcChannelFactory));
}
if (netmapService is null)
{
throw new ArgumentNullException(nameof(netmapService));
}
if (sessionService is null)
{
throw new ArgumentNullException(nameof(sessionService));
}
if (containerService is null)
{
throw new ArgumentNullException(nameof(containerService));
}
if (objectService is null)
{
throw new ArgumentNullException(nameof(objectService));
}
return new FrostFSClient(
settings, channel: grpcChannelFactory(settings.Value.Host), containerService, netmapService, sessionService, objectService);
}
private FrostFSClient(
IOptions<ClientSettings> settings,
GrpcChannelOptions? channelOptions,
ChannelBase channel,
ContainerServiceClient containerService,
NetmapServiceClient netmapService,
SessionServiceClient sessionService,
@ -99,7 +131,7 @@ public class FrostFSClient : IFrostFSClient
client: this,
key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
channel: channel,
version: new FrostFsVersion(2, 13))
{
SessionCache = new SessionCache(0),
@ -113,7 +145,7 @@ public class FrostFSClient : IFrostFSClient
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
}
private FrostFSClient(IOptions<ClientSettings> settings, GrpcChannelOptions? channelOptions)
private FrostFSClient(IOptions<ClientSettings> settings, Func<string, ChannelBase> grpcChannelFactory)
{
var clientSettings = (settings?.Value) ?? throw new ArgumentNullException(nameof(settings), "Options value must be initialized");
@ -121,13 +153,11 @@ public class FrostFSClient : IFrostFSClient
var ecdsaKey = clientSettings.Key.LoadWif();
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
ClientCtx = new ClientContext(
this,
key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: channel,
channel: grpcChannelFactory(settings.Value.Host),
version: new FrostFsVersion(2, 13))
{
SessionCache = new SessionCache(0),
@ -145,7 +175,7 @@ public class FrostFSClient : IFrostFSClient
client: this,
key: new ClientKey(prm.Key),
owner: FrostFsOwner.FromKey(prm.Key!),
channel: InitGrpcChannel(prm.Address, null), //prm.GrpcChannelOptions),
channel: prm.GrpcChannelFactory(prm.Address),
version: new FrostFsVersion(2, 13))
{
SessionCache = cache,
@ -154,21 +184,6 @@ public class FrostFSClient : IFrostFSClient
};
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing && !isDisposed)
{
ClientCtx?.Dispose();
isDisposed = true;
}
}
#region ApeManagerImplementation
public Task<ReadOnlyMemory<byte>> AddChainAsync(PrmApeChainAdd args, CallContext ctx)
{
@ -246,9 +261,14 @@ public class FrostFSClient : IFrostFSClient
return GetObjectService().GetRangeHashAsync(args, ctx);
}
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args, CallContext ctx)
public Task<IObjectWriter> PutObjectAsync(PrmObjectPut args, CallContext ctx)
{
return GetObjectService().PutObjectAsync(args, ctx);
return GetObjectService().PutStreamObjectAsync(args, ctx);
}
public Task<FrostFsObjectId> PutClientCutObjectAsync(PrmObjectClientCutPut args, CallContext ctx)
{
return GetObjectService().PutClientCutObjectAsync(args, ctx);
}
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx)
@ -308,9 +328,6 @@ public class FrostFSClient : IFrostFSClient
private CallInvoker? CreateInvoker()
{
if (isDisposed)
throw new FrostFsInvalidObjectException("Client is disposed.");
CallInvoker? callInvoker = null;
if (ClientCtx.Interceptors != null)
@ -441,27 +458,6 @@ public class FrostFSClient : IFrostFSClient
return ObjectServiceProvider;
}
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
{
try
{
var uri = new Uri(host);
if (channelOptions != null)
return GrpcChannel.ForAddress(uri, channelOptions);
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
{
HttpHandler = new HttpClientHandler()
});
}
catch (UriFormatException e)
{
throw new ArgumentException($"Host '{host}' has invalid format. Error: {e.Message}");
}
}
public async Task<string?> Dial(CallContext ctx)
{
var service = GetAccouningService();
@ -474,9 +470,4 @@ public class FrostFSClient : IFrostFSClient
{
throw new NotImplementedException();
}
public void Close()
{
Dispose();
}
}