[#21] Client: Allows multinenant client
All checks were successful
DCO / DCO (pull_request) Successful in 27s
All checks were successful
DCO / DCO (pull_request) Successful in 27s
Using one client for several owners Signed-off-by: Pavel Gross <p.gross@yando.com>
This commit is contained in:
parent
18126ea763
commit
2a28806ace
30 changed files with 349 additions and 281 deletions
|
@ -35,6 +35,11 @@ public class Client : IFrostFSClient
|
|||
return new Client(clientOptions, channelOptions);
|
||||
}
|
||||
|
||||
public static IFrostFSClient GetSingleOwnerInstance(IOptions<SingleOwnerClientSettings> clientOptions, GrpcChannelOptions? channelOptions = null)
|
||||
{
|
||||
return new Client(clientOptions, channelOptions);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
|
||||
/// </summary>
|
||||
|
@ -46,7 +51,7 @@ public class Client : IFrostFSClient
|
|||
/// <param name="objectService">Object.ObjectService.ObjectServiceClient implementation</param>
|
||||
/// <returns></returns>
|
||||
public static IFrostFSClient GetTestInstance(
|
||||
IOptions<ClientSettings> clientOptions,
|
||||
IOptions<SingleOwnerClientSettings> clientOptions,
|
||||
GrpcChannelOptions? channelOptions,
|
||||
NetmapService.NetmapServiceClient netmapService,
|
||||
SessionService.SessionServiceClient sessionService,
|
||||
|
@ -57,18 +62,18 @@ public class Client : IFrostFSClient
|
|||
}
|
||||
|
||||
private Client(
|
||||
IOptions<ClientSettings> settings,
|
||||
GrpcChannelOptions? channelOptions,
|
||||
ContainerService.ContainerServiceClient containerService,
|
||||
NetmapService.NetmapServiceClient netmapService,
|
||||
SessionService.SessionServiceClient sessionService,
|
||||
ObjectService.ObjectServiceClient objectService)
|
||||
IOptions<SingleOwnerClientSettings> settings,
|
||||
GrpcChannelOptions? channelOptions,
|
||||
ContainerService.ContainerServiceClient containerService,
|
||||
NetmapService.NetmapServiceClient netmapService,
|
||||
SessionService.SessionServiceClient sessionService,
|
||||
ObjectService.ObjectServiceClient objectService)
|
||||
{
|
||||
var ecdsaKey = settings.Value.Key.LoadWif();
|
||||
OwnerId.FromKey(ecdsaKey);
|
||||
|
||||
ClientCtx = new ClientEnvironment(
|
||||
this,
|
||||
client: this,
|
||||
key: ecdsaKey,
|
||||
owner: OwnerId.FromKey(ecdsaKey),
|
||||
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
|
||||
|
@ -86,6 +91,25 @@ public class Client : IFrostFSClient
|
|||
|
||||
clientSettings.Validate();
|
||||
|
||||
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
|
||||
|
||||
ClientCtx = new ClientEnvironment(
|
||||
this,
|
||||
key: null,
|
||||
owner: null,
|
||||
channel: channel,
|
||||
version: new Version(2, 13));
|
||||
|
||||
// TODO: define timeout logic
|
||||
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
|
||||
}
|
||||
|
||||
private Client(IOptions<SingleOwnerClientSettings> options, GrpcChannelOptions? channelOptions)
|
||||
{
|
||||
var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
|
||||
|
||||
clientSettings.Validate();
|
||||
|
||||
var ecdsaKey = clientSettings.Key.LoadWif();
|
||||
|
||||
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
|
||||
|
@ -221,22 +245,22 @@ public class Client : IFrostFSClient
|
|||
#endregion
|
||||
|
||||
#region ToolsImplementation
|
||||
public ObjectId CalculateObjectId(ObjectHeader header)
|
||||
public ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
|
||||
{
|
||||
if (header == null)
|
||||
throw new ArgumentNullException(nameof(header));
|
||||
|
||||
return ObjectTools.CalculateObjectId(header, ClientCtx);
|
||||
return ObjectTools.CalculateObjectId(header, ctx);
|
||||
}
|
||||
#endregion
|
||||
|
||||
private async void CheckFrostFsVersionSupport(Context? ctx = default)
|
||||
{
|
||||
var args = new PrmNodeInfo(ctx);
|
||||
var args = new PrmNodeInfo { Context = ctx };
|
||||
var service = GetNetmapService(args);
|
||||
var localNodeInfo = await service.GetLocalNodeInfoAsync(args);
|
||||
|
||||
if (!localNodeInfo.Version.IsSupported(ClientCtx.Version))
|
||||
if (!localNodeInfo.Version.IsSupported(args.Context!.Version))
|
||||
{
|
||||
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
|
||||
throw new ApplicationException(msg);
|
||||
|
@ -250,6 +274,31 @@ public class Client : IFrostFSClient
|
|||
|
||||
ctx.Context ??= new Context();
|
||||
|
||||
if (ctx.Context.Key == null)
|
||||
{
|
||||
if (ClientCtx.Key == null)
|
||||
{
|
||||
throw new Exception("Key is not initialized.");
|
||||
}
|
||||
|
||||
ctx.Context.Key = ClientCtx.Key.ECDsaKey;
|
||||
}
|
||||
|
||||
if (ctx.Context.OwnerId == null)
|
||||
{
|
||||
ctx.Context.OwnerId = ClientCtx.Owner ?? OwnerId.FromKey(ctx.Context.Key);
|
||||
}
|
||||
|
||||
if (ctx.Context.Version == null)
|
||||
{
|
||||
if (ClientCtx.Version == null)
|
||||
{
|
||||
throw new Exception("Version is not initialized.");
|
||||
}
|
||||
|
||||
ctx.Context.Version = ClientCtx.Version;
|
||||
}
|
||||
|
||||
CallInvoker? callInvoker = null;
|
||||
if (ctx.Context.Interceptors != null && ctx.Context.Interceptors.Count > 0)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,6 @@ public interface IFrostFSClient : IDisposable
|
|||
#endregion
|
||||
|
||||
#region Tools
|
||||
ObjectId CalculateObjectId(ObjectHeader header);
|
||||
ObjectId CalculateObjectId(ObjectHeader header, Context ctx);
|
||||
#endregion
|
||||
}
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core.Interceptors;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
@ -10,8 +13,18 @@ public class Context()
|
|||
{
|
||||
private List<Interceptor>? interceptors;
|
||||
|
||||
private ByteString publicKeyCache;
|
||||
|
||||
public ECDsa Key { get; set; }
|
||||
|
||||
public OwnerId OwnerId { get; set; }
|
||||
|
||||
public ModelsV2.Version Version { get; set; }
|
||||
|
||||
public CancellationToken CancellationToken { get; set; } = default;
|
||||
|
||||
public TimeSpan Timeout { get; set; } = default;
|
||||
|
||||
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
||||
|
||||
public Action<CallStatistics>? Callback { get; set; }
|
||||
|
@ -20,5 +33,18 @@ public class Context()
|
|||
{
|
||||
get { return this.interceptors ??= []; }
|
||||
set { this.interceptors = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public ByteString PublicKeyCache
|
||||
{
|
||||
get
|
||||
{
|
||||
if (publicKeyCache == null)
|
||||
{
|
||||
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
|
||||
}
|
||||
|
||||
return publicKeyCache;
|
||||
}
|
||||
}
|
||||
}
|
11
src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs
Normal file
11
src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
using FrostFS.SDK.ModelsV2;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public class Credentials(ECDsa key, OwnerId ownerId)
|
||||
{
|
||||
public ECDsa Key { get; } = key;
|
||||
|
||||
public OwnerId OwnerId { get; } = ownerId;
|
||||
}
|
14
src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs
Normal file
14
src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System.Collections.Specialized;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public class PrmBase() : IContext
|
||||
{
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmContainerCreate(ModelsV2.Container container) : IContext
|
||||
public sealed class PrmContainerCreate(ModelsV2.Container container) : PrmBase, ISessionToken
|
||||
{
|
||||
public ModelsV2.Container Container { get; set; } = container;
|
||||
|
||||
|
@ -12,11 +12,7 @@ public sealed class PrmContainerCreate(ModelsV2.Container container) : IContext
|
|||
/// <value>Rules for polling the result</value>
|
||||
public PrmWait? WaitParams { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
public string SessionKey { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmContainerDelete(ContainerId containerId, Context? ctx = null) : IContext
|
||||
public sealed class PrmContainerDelete(ContainerId containerId) : PrmBase, ISessionToken
|
||||
{
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
|
@ -12,12 +11,6 @@ public sealed class PrmContainerDelete(ContainerId containerId, Context? ctx = n
|
|||
/// </summary>
|
||||
/// <value>Rules for polling the result</value>
|
||||
public PrmWait? WaitParams { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = ctx;
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,17 +1,8 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmContainerGet(ContainerId containerId, Context? ctx = null) : IContext
|
||||
public sealed class PrmContainerGet(ContainerId containerId) : PrmBase
|
||||
{
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = ctx;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,6 @@
|
|||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmContainerGetAll() : IContext
|
||||
public sealed class PrmContainerGetAll() : PrmBase()
|
||||
{
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
}
|
||||
|
|
|
@ -2,13 +2,6 @@
|
|||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmNetmapSnapshot(Context? context = default) : IContext
|
||||
{
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = context;
|
||||
public sealed class PrmNetmapSnapshot() : PrmBase
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
using System.Collections.Specialized;
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmNetworkSettings(Context? context = default) : IContext
|
||||
{
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = context;
|
||||
public sealed class PrmNetworkSettings() : PrmBase
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1,14 +1,5 @@
|
|||
using System.Collections.Specialized;
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmNodeInfo(Context? context = default) : IContext
|
||||
{
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = context;
|
||||
public sealed class PrmNodeInfo() : PrmBase
|
||||
{
|
||||
}
|
||||
|
|
|
@ -3,19 +3,12 @@ using FrostFS.SDK.ModelsV2;
|
|||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmObjectDelete(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
|
||||
public sealed class PrmObjectDelete(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
|
||||
{
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
public ObjectId ObjectId { get; set; } = objectId;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmObjectGet(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
|
||||
public sealed class PrmObjectGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
|
||||
{
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
public ObjectId ObjectId { get; set; } = objectId;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmObjectHeadGet(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
|
||||
public sealed class PrmObjectHeadGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
|
||||
{
|
||||
public ContainerId ContainerId { get; set; } = containerId;
|
||||
|
||||
public ObjectId ObjectId { get; set; } = objectId;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using FrostFS.SDK.ModelsV2;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmObjectPut : IContext, ISessionToken
|
||||
public sealed class PrmObjectPut : PrmBase, ISessionToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object.
|
||||
|
@ -30,21 +30,13 @@ public sealed class PrmObjectPut : IContext, ISessionToken
|
|||
/// Overrides default size of the buffer for stream transferring.
|
||||
/// </summary>
|
||||
/// <value>Size of the buffer</value>
|
||||
public int BufferMaxSize { get; set; }
|
||||
public int BufferMaxSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
|
||||
/// </summary>
|
||||
public byte[]? CustomBuffer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using System.Collections.Generic;
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilter[] filters) : IContext, ISessionToken
|
||||
public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilter[] filters) : PrmBase, ISessionToken
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines container for the search
|
||||
|
@ -16,15 +15,7 @@ public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilte
|
|||
/// </summary>
|
||||
/// <value>Collection of filters</value>
|
||||
public IEnumerable<IObjectFilter> Filters { get; set; } = filters;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; }
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,16 +1,6 @@
|
|||
using System.Collections.Specialized;
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmSessionCreate(ulong expiration, Context? context = default) : IContext
|
||||
public sealed class PrmSessionCreate(ulong expiration) : PrmBase
|
||||
{
|
||||
public ulong Expiration { get; set; } = expiration;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = context;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,11 @@
|
|||
using System.Collections.Specialized;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Parameters;
|
||||
|
||||
public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject, Context? context = null) : IContext, ISessionToken
|
||||
public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject) : PrmBase, ISessionToken
|
||||
{
|
||||
public FrostFsObject FrostFsObject { get; set; } = frostFsObject;
|
||||
|
||||
/// <summary>
|
||||
/// FrostFS request X-Headers
|
||||
/// </summary>
|
||||
public NameValueCollection XHeaders { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public Context? Context { get; set; } = context;
|
||||
|
||||
/// <inheritdoc />
|
||||
public SessionToken? SessionToken { get; set; }
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
{
|
||||
internal async Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args)
|
||||
{
|
||||
GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders);
|
||||
GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders, args.Context!);
|
||||
|
||||
var response = await service.GetAsync(request, null, args.Context!.Deadline, args.Context.CancellationToken);
|
||||
|
||||
|
@ -34,12 +34,12 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
{
|
||||
Body = new ListRequest.Types.Body
|
||||
{
|
||||
OwnerId = Context.Owner.ToMessage()
|
||||
OwnerId = ctx.OwnerId.ToMessage()
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await service.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -55,20 +55,20 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
{
|
||||
var ctx = args.Context!;
|
||||
var grpcContainer = args.Container.ToMessage();
|
||||
grpcContainer.OwnerId = Context.Owner.ToMessage();
|
||||
grpcContainer.Version = Context.Version.ToMessage();
|
||||
grpcContainer.OwnerId = ctx.OwnerId.ToMessage();
|
||||
grpcContainer.Version = ctx.Version.ToMessage();
|
||||
|
||||
var request = new PutRequest
|
||||
{
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
Container = grpcContainer,
|
||||
Signature = Context.Key.ECDsaKey.SignRFC6979(grpcContainer)
|
||||
Signature = ctx.Key.SignRFC6979(grpcContainer)
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await service.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -87,13 +87,13 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
Body = new DeleteRequest.Types.Body
|
||||
{
|
||||
ContainerId = args.ContainerId.ToMessage(),
|
||||
Signature = Context.Key.ECDsaKey.SignRFC6979(args.ContainerId.ToMessage().Value)
|
||||
Signature = ctx.Key.SignRFC6979(args.ContainerId.ToMessage().Value)
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await service.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -102,7 +102,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
Verifier.CheckResponse(response);
|
||||
}
|
||||
|
||||
private GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders)
|
||||
private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, Context ctx)
|
||||
{
|
||||
var request = new GetRequest
|
||||
{
|
||||
|
@ -113,7 +113,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
};
|
||||
|
||||
request.AddMetaHeader(xHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
|
|||
|
||||
private async Task WaitForContainer(WaitExpects expect, ContainerID id, PrmWait? waitParams, Context ctx)
|
||||
{
|
||||
var request = GetContainerRequest(id, null);
|
||||
var request = GetContainerRequest(id, null, ctx);
|
||||
|
||||
async Task action()
|
||||
{
|
||||
|
|
|
@ -49,7 +49,7 @@ internal class NetmapServiceProvider : ContextAccessor
|
|||
};
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -63,7 +63,7 @@ internal class NetmapServiceProvider : ContextAccessor
|
|||
var request = new NetworkInfoRequest();
|
||||
|
||||
request.AddMetaHeader(null);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -79,7 +79,7 @@ internal class NetmapServiceProvider : ContextAccessor
|
|||
var request = new NetmapSnapshotRequest();
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
|
|
@ -46,11 +46,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
request.Body.Address,
|
||||
ObjectSessionContext.Types.Verb.Head,
|
||||
Context.Key.ECDsaKey);
|
||||
ctx.Key);
|
||||
|
||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await client!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -80,11 +80,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
request.Body.Address,
|
||||
ObjectSessionContext.Types.Verb.Get,
|
||||
Context.Key.ECDsaKey);
|
||||
ctx.Key);
|
||||
|
||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
return await GetObject(request, ctx);
|
||||
}
|
||||
|
@ -109,10 +109,10 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
request.Body.Address,
|
||||
ObjectSessionContext.Types.Verb.Delete,
|
||||
Context.Key.ECDsaKey);
|
||||
ctx.Key);
|
||||
|
||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await client.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -139,11 +139,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
new Address { ContainerId = request.Body.ContainerId },
|
||||
ObjectSessionContext.Types.Verb.Search,
|
||||
Context.Key.ECDsaKey);
|
||||
ctx.Key);
|
||||
|
||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var objectsIds = SearchObjects(request, ctx);
|
||||
|
||||
|
@ -177,7 +177,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
internal async Task<ObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
|
||||
{
|
||||
var ctx = args.Context!;
|
||||
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, env);
|
||||
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
|
||||
|
||||
var request = new PutSingleRequest
|
||||
{
|
||||
|
@ -192,11 +192,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId},
|
||||
ObjectSessionContext.Types.Verb.Put,
|
||||
Context.Key.ECDsaKey);
|
||||
ctx.Key);
|
||||
|
||||
request.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
var response = await client.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
|
@ -226,7 +226,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
if (args.MaxObjectSizeCache == 0)
|
||||
{
|
||||
var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings(ctx));
|
||||
var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings() { Context = ctx });
|
||||
args.MaxObjectSizeCache = (int)networkSettings.MaxObjectSize;
|
||||
}
|
||||
|
||||
|
@ -331,7 +331,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
|
||||
while (objectLimitSize == 0 || sentBytes < objectLimitSize)
|
||||
{
|
||||
// send chanks limited to default or user's settings
|
||||
// send chunks limited to default or user's settings
|
||||
var bufferSize = objectLimitSize > 0 ?
|
||||
(int)Math.Min(objectLimitSize - sentBytes, chunkSize)
|
||||
: chunkSize;
|
||||
|
@ -350,8 +350,8 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
Chunk = ByteString.CopyFrom(chunkBuffer, 0, bytesCount)
|
||||
}
|
||||
};
|
||||
|
||||
chunkRequest.Sign(Context.Key.ECDsaKey);
|
||||
|
||||
chunkRequest.Sign(ctx.Key);
|
||||
|
||||
await stream.Write(chunkRequest);
|
||||
}
|
||||
|
@ -374,14 +374,14 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
{
|
||||
var header = args.Header!;
|
||||
|
||||
header.OwnerId = Context.Owner;
|
||||
header.Version = Context.Version;
|
||||
header.OwnerId = ctx.OwnerId;
|
||||
header.Version = ctx.Version;
|
||||
|
||||
var grpcHeader = header.ToMessage();
|
||||
|
||||
if (header.Split != null)
|
||||
{
|
||||
ObjectTools.SetSplitValues(grpcHeader, header.Split, env);
|
||||
ObjectTools.SetSplitValues(grpcHeader, header.Split, ctx);
|
||||
}
|
||||
|
||||
var oid = new ObjectID { Value = grpcHeader.Sha256() };
|
||||
|
@ -402,12 +402,12 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
|
|||
sessionToken.CreateObjectTokenContext(
|
||||
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
|
||||
ObjectSessionContext.Types.Verb.Put,
|
||||
Context.Key.ECDsaKey
|
||||
ctx.Key
|
||||
);
|
||||
|
||||
initRequest.AddMetaHeader(args.XHeaders, sessionToken);
|
||||
|
||||
initRequest.Sign(Context.Key.ECDsaKey);
|
||||
initRequest.Sign(ctx.Key);
|
||||
|
||||
return await PutObjectInit(initRequest, ctx);
|
||||
}
|
||||
|
|
|
@ -17,17 +17,18 @@ internal class SessionServiceProvider : ContextAccessor
|
|||
|
||||
internal async Task<SessionToken> CreateSessionAsync(PrmSessionCreate args)
|
||||
{
|
||||
var ctx = args.Context!;
|
||||
var request = new CreateRequest
|
||||
{
|
||||
Body = new CreateRequest.Types.Body
|
||||
{
|
||||
OwnerId = Context.Owner.ToMessage(),
|
||||
OwnerId = ctx.OwnerId.ToMessage(),
|
||||
Expiration = args.Expiration
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader(args.XHeaders);
|
||||
request.Sign(Context.Key.ECDsaKey);
|
||||
request.Sign(ctx.Key);
|
||||
|
||||
return await CreateSession(request, args.Context!);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ internal class SessionProvider(ClientEnvironment env)
|
|||
{
|
||||
if (args.SessionToken is null)
|
||||
{
|
||||
return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue, ctx));
|
||||
return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue) { Context = ctx });
|
||||
}
|
||||
|
||||
return new Session.SessionToken().Deserialize(args.SessionToken.Token);
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
using FrostFS.SDK.ModelsV2;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Net.Client;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using System.Buffers;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public class ClientEnvironment(Client client, ECDsa key, OwnerId owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
|
||||
public class ClientEnvironment(Client client, ECDsa? key, OwnerId? owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
|
||||
{
|
||||
private ArrayPool<byte> _arrayPool;
|
||||
|
||||
internal OwnerId Owner { get; } = owner;
|
||||
internal OwnerId? Owner { get; } = owner;
|
||||
|
||||
internal GrpcChannel Channel { get; private set; } = channel;
|
||||
|
||||
internal ModelsV2.Version Version { get; } = version;
|
||||
|
||||
internal NetworkSettings? NetworkSettings { get; set; }
|
||||
|
||||
internal Client Client { get; } = client;
|
||||
|
||||
internal ClientKey Key { get; } = new ClientKey(key);
|
||||
internal ClientKey? Key { get; } = key != null ? new ClientKey(key) : null;
|
||||
|
||||
/// <summary>
|
||||
/// Custom pool is used for predefined sizes of buffers like grpc chunk
|
||||
|
|
|
@ -7,26 +7,25 @@ using FrostFS.Refs;
|
|||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using static FrostFS.Object.Header.Types;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
internal class ObjectTools
|
||||
{
|
||||
internal static ObjectId CalculateObjectId(ObjectHeader header, ClientEnvironment env)
|
||||
internal static ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
|
||||
{
|
||||
var grpcHeader = CreateHeader(header, [], env);
|
||||
var grpcHeader = CreateHeader(header, [], ctx);
|
||||
|
||||
if (header.Split != null)
|
||||
SetSplitValues(grpcHeader, header.Split, env);
|
||||
SetSplitValues(grpcHeader, header.Split, ctx);
|
||||
|
||||
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
|
||||
}
|
||||
|
||||
internal static Object.Object CreateObject(FrostFsObject @object, ClientEnvironment env)
|
||||
internal static Object.Object CreateObject(FrostFsObject @object, Context ctx)
|
||||
{
|
||||
@object.Header.OwnerId = env.Owner;
|
||||
@object.Header.Version = env.Version;
|
||||
@object.Header.OwnerId = ctx.OwnerId;
|
||||
@object.Header.Version = ctx.Version;
|
||||
|
||||
var grpcHeader = @object.Header.ToMessage();
|
||||
|
||||
|
@ -36,7 +35,7 @@ internal class ObjectTools
|
|||
var split = @object.Header.Split;
|
||||
if (split != null)
|
||||
{
|
||||
SetSplitValues(grpcHeader, split, env);
|
||||
SetSplitValues(grpcHeader, split, ctx);
|
||||
}
|
||||
|
||||
var obj = new Object.Object
|
||||
|
@ -48,14 +47,14 @@ internal class ObjectTools
|
|||
|
||||
obj.Signature = new Refs.Signature
|
||||
{
|
||||
Key = env.Key.PublicKeyProto,
|
||||
Sign = ByteString.CopyFrom(env.Key.ECDsaKey.SignData(obj.ObjectId.ToByteArray())),
|
||||
Key = ctx.PublicKeyCache,
|
||||
Sign = ByteString.CopyFrom(ctx.Key.SignData(obj.ObjectId.ToByteArray())),
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
internal static void SetSplitValues(Header grpcHeader, ModelsV2.Split split, ClientEnvironment env)
|
||||
internal static void SetSplitValues(Header grpcHeader, ModelsV2.Split split, Context ctx)
|
||||
{
|
||||
grpcHeader.Split = new Header.Types.Split
|
||||
{
|
||||
|
@ -67,14 +66,14 @@ internal class ObjectTools
|
|||
|
||||
if (split.ParentHeader is not null)
|
||||
{
|
||||
var grpcParentHeader = CreateHeader(split.ParentHeader, [], env);
|
||||
var grpcParentHeader = CreateHeader(split.ParentHeader, [], ctx);
|
||||
|
||||
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
|
||||
grpcHeader.Split.ParentHeader = grpcParentHeader;
|
||||
grpcHeader.Split.ParentSignature = new Refs.Signature
|
||||
{
|
||||
Key = env.Key.PublicKeyProto,
|
||||
Sign = ByteString.CopyFrom(env.Key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||
Key = ctx.PublicKeyCache,
|
||||
Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||
};
|
||||
|
||||
split.Parent = grpcHeader.Split.Parent.ToModel();
|
||||
|
@ -83,12 +82,12 @@ internal class ObjectTools
|
|||
grpcHeader.Split.Previous = split.Previous?.ToMessage();
|
||||
}
|
||||
|
||||
internal static Header CreateHeader(ObjectHeader header, byte[]? payload, ClientEnvironment env)
|
||||
internal static Header CreateHeader(ObjectHeader header, byte[]? payload, Context ctx)
|
||||
{
|
||||
var grpcHeader = header.ToMessage();
|
||||
|
||||
grpcHeader.OwnerId = env.Owner.ToMessage();
|
||||
grpcHeader.Version = env.Version.ToMessage();
|
||||
grpcHeader.OwnerId = ctx.OwnerId.ToMessage();
|
||||
grpcHeader.Version = ctx.Version.ToMessage();
|
||||
|
||||
if (payload != null) // && payload.Length > 0
|
||||
grpcHeader.PayloadHash = Sha256Checksum(payload);
|
||||
|
|
|
@ -1,28 +1,64 @@
|
|||
using Google.Protobuf;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class ClientSettings
|
||||
{
|
||||
private static readonly string errorTemplate = "{0} is required parameter";
|
||||
|
||||
public string Key { get; set; } = string.Empty;
|
||||
protected static readonly string errorTemplate = "{0} is required parameter";
|
||||
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
public void Validate()
|
||||
public virtual void Validate()
|
||||
{
|
||||
StringBuilder? error = null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Key))
|
||||
(error ??= new StringBuilder()).AppendLine(string.Format(errorTemplate, nameof(Key)));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Host))
|
||||
(error ??= new StringBuilder()).AppendLine(string.Format(errorTemplate, nameof(Host)));
|
||||
|
||||
if (error != null)
|
||||
throw new ArgumentException(error.ToString());
|
||||
var errors = CheckFields();
|
||||
if (errors != null)
|
||||
ThrowException(errors);
|
||||
}
|
||||
|
||||
protected List<string>? CheckFields()
|
||||
{
|
||||
List<string>? errors = null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Host))
|
||||
(errors ??= []).Add(string.Format(errorTemplate, nameof(Host)));
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
protected static void ThrowException(List<string> errors)
|
||||
{
|
||||
StringBuilder messages = new();
|
||||
|
||||
foreach (var error in errors)
|
||||
{
|
||||
messages.AppendLine(error);
|
||||
}
|
||||
|
||||
throw new ArgumentException(messages.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public class SingleOwnerClientSettings : ClientSettings
|
||||
{
|
||||
public string Key { get; set; } = string.Empty;
|
||||
|
||||
public override void Validate()
|
||||
{
|
||||
var errors = CheckFields();
|
||||
if (errors != null)
|
||||
ThrowException(errors);
|
||||
}
|
||||
|
||||
protected List<string>? CheckFields()
|
||||
{
|
||||
List<string>? errors = base.CheckFields();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Key))
|
||||
(errors ??= []).Add(string.Format(errorTemplate, nameof(Key)));
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
|
@ -16,12 +16,12 @@ public abstract class ContainerTestsBase
|
|||
{
|
||||
protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
protected IOptions<ClientSettings> Settings { get; set; }
|
||||
protected IOptions<SingleOwnerClientSettings> Settings { get; set; }
|
||||
protected ContainerMocker Mocker { get; set; }
|
||||
|
||||
protected ContainerTestsBase()
|
||||
{
|
||||
Settings = Options.Create(new ClientSettings
|
||||
Settings = Options.Create(new SingleOwnerClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
|
|
|
@ -19,7 +19,7 @@ public abstract class ObjectTestsBase
|
|||
{
|
||||
protected static readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
protected IOptions<ClientSettings> Settings { get; set; }
|
||||
protected IOptions<SingleOwnerClientSettings> Settings { get; set; }
|
||||
protected ContainerId ContainerId { get; set; }
|
||||
|
||||
protected NetworkMocker NetworkMocker { get; set; } = new NetworkMocker(key);
|
||||
|
@ -31,7 +31,7 @@ public abstract class ObjectTestsBase
|
|||
{
|
||||
var ecdsaKey = key.LoadWif();
|
||||
|
||||
Settings = Options.Create(new ClientSettings
|
||||
Settings = Options.Create(new SingleOwnerClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
|
@ -71,14 +71,17 @@ public class ObjectTest : ObjectTestsBase
|
|||
public async void GetObjectTest()
|
||||
{
|
||||
var client = GetClient();
|
||||
var objectId = client.CalculateObjectId(Mocker.ObjectHeader!);
|
||||
|
||||
var context = new Context
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(2)
|
||||
};
|
||||
var ecdsaKey = key.LoadWif();
|
||||
|
||||
var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = context });
|
||||
var ctx = new Context {
|
||||
Key = ecdsaKey,
|
||||
OwnerId = OwnerId.FromKey(ecdsaKey),
|
||||
Version = new ModelsV2.Version(2, 13) };
|
||||
|
||||
var objectId = client.CalculateObjectId(Mocker.ObjectHeader!, ctx);
|
||||
|
||||
var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = ctx });
|
||||
|
||||
Assert.NotNull(result);
|
||||
|
||||
|
|
|
@ -13,21 +13,46 @@ using System.Diagnostics;
|
|||
|
||||
using static FrostFS.Session.SessionToken.Types.Body;
|
||||
using FrostFS.SDK.ClientV2.Parameters;
|
||||
using FrostFS.SDK.Tests;
|
||||
|
||||
namespace FrostFS.SDK.SmokeTests;
|
||||
|
||||
public class SmokeTests
|
||||
public abstract class SmokeTestsBase
|
||||
{
|
||||
protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
protected readonly string url = "http://172.23.32.4:8080";
|
||||
|
||||
protected ECDsa Key { get; }
|
||||
|
||||
protected OwnerId OwnerId { get; }
|
||||
|
||||
protected ModelsV2.Version Version { get; }
|
||||
|
||||
protected Context Ctx { get; }
|
||||
|
||||
protected SmokeTestsBase()
|
||||
{
|
||||
Key = key.LoadWif();
|
||||
OwnerId = OwnerId.FromKey(Key);
|
||||
Version = new ModelsV2.Version(2, 13);
|
||||
|
||||
Ctx = new Context { Key = Key, OwnerId = OwnerId, Version = Version };
|
||||
}
|
||||
}
|
||||
|
||||
public class SmokeTests : SmokeTestsBase
|
||||
{
|
||||
private static readonly PrmWait lightWait = new (100, 1);
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
private readonly string url = "http://172.23.32.4:8080";
|
||||
|
||||
[Fact]
|
||||
public async void NetworkMapTest()
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
|
||||
var result = await client.GetNetmapSnapshotAsync();
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async void NetworkMapTest(bool isSingleOnwerClient)
|
||||
{
|
||||
using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
|
||||
|
||||
PrmNetmapSnapshot? prm = isSingleOnwerClient ? default : new () { Context = Ctx };
|
||||
var result = await client.GetNetmapSnapshotAsync(prm);
|
||||
|
||||
Assert.True(result.Epoch > 0);
|
||||
Assert.Single(result.NodeInfoCollection);
|
||||
|
@ -41,12 +66,17 @@ public class SmokeTests
|
|||
Assert.Equal(9, item.Attributes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void NodeInfoTest()
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
|
||||
var result = await client.GetNodeInfoAsync();
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async void NodeInfoTest(bool isSingleOnwerClient)
|
||||
{
|
||||
using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
|
||||
|
||||
PrmNodeInfo? prm = isSingleOnwerClient ? default : new() { Context = Ctx };
|
||||
|
||||
var result = await client.GetNodeInfoAsync(prm);
|
||||
|
||||
Assert.Equal(2, result.Version.Major);
|
||||
Assert.Equal(13, result.Version.Minor);
|
||||
|
@ -64,25 +94,25 @@ public class SmokeTests
|
|||
Callback = (cs) => Console.WriteLine($"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds")
|
||||
};
|
||||
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
var result = await client.GetNodeInfoAsync();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetSessionTest()
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public async void GetSessionTest(bool isSingleOnwerClient)
|
||||
{
|
||||
var ecdsaKey = this.key.LoadWif();
|
||||
using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
|
||||
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
PrmSessionCreate? prm = isSingleOnwerClient ? new PrmSessionCreate(100) : new PrmSessionCreate(100) { Context = Ctx };
|
||||
|
||||
var token = await client.CreateSessionAsync(new PrmSessionCreate(100));
|
||||
var token = await client.CreateSessionAsync(prm);
|
||||
|
||||
var session = new Session.SessionToken().Deserialize(token.Token);
|
||||
|
||||
var owner = OwnerId.FromKey(ecdsaKey);
|
||||
|
||||
var ownerHash = Base58.Decode(owner.Value);
|
||||
var ownerHash = Base58.Decode(OwnerId.Value);
|
||||
|
||||
Assert.NotNull(session);
|
||||
Assert.Null(session.Body.Container);
|
||||
|
@ -97,7 +127,7 @@ public class SmokeTests
|
|||
[Fact]
|
||||
public async void CreateObjectWithSessionToken()
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
|
@ -144,7 +174,7 @@ public class SmokeTests
|
|||
[Fact]
|
||||
public async void FilterTest()
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
|
@ -230,7 +260,7 @@ public class SmokeTests
|
|||
[InlineData(6 * 1024 * 1024 + 100)]
|
||||
public async void SimpleScenarioTest(int objectSize)
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
|
@ -253,7 +283,7 @@ public class SmokeTests
|
|||
|
||||
var containerId = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId,ctx));
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
|
||||
Assert.NotNull(container);
|
||||
Assert.True(callbackInvoked);
|
||||
|
||||
|
@ -318,7 +348,7 @@ public class SmokeTests
|
|||
[InlineData(6 * 1024 * 1024 + 100)]
|
||||
public async void SimpleScenarioWithSessionTest(int objectSize)
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue));
|
||||
|
||||
|
@ -338,7 +368,7 @@ public class SmokeTests
|
|||
|
||||
var containerId = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId,ctx));
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
|
||||
Assert.NotNull(container);
|
||||
|
||||
var bytes = GetRandomBytes(objectSize);
|
||||
|
@ -406,7 +436,7 @@ public class SmokeTests
|
|||
[InlineData(200)]
|
||||
public async void ClientCutScenarioTest(int objectSize)
|
||||
{
|
||||
using var client = Client.GetInstance(GetOptions(this.key, this.url));
|
||||
using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
|
||||
|
||||
await Cleanup(client);
|
||||
|
||||
|
@ -417,13 +447,13 @@ public class SmokeTests
|
|||
|
||||
var containerId = await client.CreateContainerAsync(createContainerParam);
|
||||
|
||||
var context = new Context
|
||||
var ctx = new Context
|
||||
{
|
||||
Timeout = TimeSpan.FromSeconds(10),
|
||||
Interceptors = new([new MetricsInterceptor()])
|
||||
};
|
||||
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId, context));
|
||||
var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
|
||||
|
||||
Assert.NotNull(container);
|
||||
|
||||
|
@ -499,11 +529,19 @@ public class SmokeTests
|
|||
return bytes;
|
||||
}
|
||||
|
||||
private static IOptions<ClientSettings> GetOptions(string key, string url)
|
||||
private static IOptions<SingleOwnerClientSettings> GetSingleOwnerOptions(string key, string url)
|
||||
{
|
||||
return Options.Create(new SingleOwnerClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = url
|
||||
});
|
||||
}
|
||||
|
||||
private static IOptions<ClientSettings> GetOptions(string url)
|
||||
{
|
||||
return Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = url
|
||||
});
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue