This commit is contained in:
Pavel Gross 2024-08-09 02:04:55 +03:00
parent 18126ea763
commit 0cfe60e3ab
22 changed files with 115 additions and 158 deletions

View file

@ -232,7 +232,7 @@ public class Client : IFrostFSClient
private async void CheckFrostFsVersionSupport(Context? ctx = default) private async void CheckFrostFsVersionSupport(Context? ctx = default)
{ {
var args = new PrmNodeInfo(ctx); var args = new PrmNodeInfo { Context = ctx };
var service = GetNetmapService(args); var service = GetNetmapService(args);
var localNodeInfo = await service.GetLocalNodeInfoAsync(args); var localNodeInfo = await service.GetLocalNodeInfoAsync(args);

View file

@ -1,8 +1,9 @@
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.ModelsV2;
using Grpc.Core.Interceptors;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using FrostFS.SDK.ModelsV2;
using Grpc.Core.Interceptors;
namespace FrostFS.SDK.ClientV2; namespace FrostFS.SDK.ClientV2;
@ -11,9 +12,17 @@ public class Context()
private List<Interceptor>? interceptors; private List<Interceptor>? interceptors;
public CancellationToken CancellationToken { get; set; } = default; public CancellationToken CancellationToken { get; set; } = default;
public TimeSpan Timeout { get; set; } = default; public TimeSpan Timeout { get; set; } = default;
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null; public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
/// <summary>
/// Provide OwnerId and Key can be created from string representaion
/// and cached on the client side
/// </summary>
public Credentials? Credentials { get; set; }
public Action<CallStatistics>? Callback { get; set; } public Action<CallStatistics>? Callback { get; set; }
public List<Interceptor> Interceptors public List<Interceptor> Interceptors

View 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;
}

View 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; }
}

View file

@ -1,8 +1,8 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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; 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> /// <value>Rules for polling the result</value>
public PrmWait? WaitParams { get; set; } public PrmWait? WaitParams { get; set; }
/// <summary> public string SessionKey { get; set; }
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc /> public SessionToken? SessionToken { get; set; }
public Context? Context { get; set; }
} }

View file

@ -1,9 +1,8 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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; public ContainerId ContainerId { get; set; } = containerId;
@ -13,11 +12,5 @@ public sealed class PrmContainerDelete(ContainerId containerId, Context? ctx = n
/// <value>Rules for polling the result</value> /// <value>Rules for polling the result</value>
public PrmWait? WaitParams { get; set; } public PrmWait? WaitParams { get; set; }
/// <summary> public SessionToken? SessionToken { get; set; }
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; } = ctx;
} }

View file

@ -1,17 +1,8 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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; public ContainerId ContainerId { get; set; } = containerId;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; } = ctx;
} }

View file

@ -2,13 +2,6 @@
namespace FrostFS.SDK.ClientV2.Parameters; 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; }
} }

View file

@ -2,13 +2,6 @@
namespace FrostFS.SDK.ClientV2.Parameters; namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmNetmapSnapshot(Context? context = default) : IContext public sealed class PrmNetmapSnapshot() : PrmBase
{ {
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; } = context;
} }

View file

@ -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) : PrmBase
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;
} }

View file

@ -1,14 +1,5 @@
using System.Collections.Specialized; namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2.Parameters; public sealed class PrmNodeInfo() : PrmBase
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;
} }

View file

@ -3,19 +3,12 @@ using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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 ContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId; public ObjectId ObjectId { get; set; } = objectId;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }
} }

View file

@ -1,21 +1,13 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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 ContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId; public ObjectId ObjectId { get; set; } = objectId;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }
} }

View file

@ -1,21 +1,13 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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 ContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId; public ObjectId ObjectId { get; set; } = objectId;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }
} }

View file

@ -1,10 +1,9 @@
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
using System.Collections.Specialized;
using System.IO; using System.IO;
namespace FrostFS.SDK.ClientV2.Parameters; namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmObjectPut : IContext, ISessionToken public sealed class PrmObjectPut : PrmBase, ISessionToken
{ {
/// <summary> /// <summary>
/// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object. /// Need to provide values like <c>ContainerId</c> and <c>ObjectType</c> to create and object.
@ -37,14 +36,6 @@ public sealed class PrmObjectPut : IContext, ISessionToken
/// </summary> /// </summary>
public byte[]? CustomBuffer { get; set; } public byte[]? CustomBuffer { get; set; }
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }

View file

@ -1,9 +1,8 @@
using System.Collections.Generic; using FrostFS.SDK.ModelsV2;
using System.Collections.Specialized; using System.Collections.Generic;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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> /// <summary>
/// Defines container for the search /// Defines container for the search
@ -17,14 +16,6 @@ public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilte
/// <value>Collection of filters</value> /// <value>Collection of filters</value>
public IEnumerable<IObjectFilter> Filters { get; set; } = filters; 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 /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }
} }

View file

@ -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) : PrmBase
public sealed class PrmSessionCreate(ulong expiration, Context? context = default) : IContext
{ {
public ulong Expiration { get; set; } = expiration; public ulong Expiration { get; set; } = expiration;
/// <summary>
/// FrostFS request X-Headers
/// </summary>
public NameValueCollection XHeaders { get; set; } = [];
/// <inheritdoc />
public Context? Context { get; set; } = context;
} }

View file

@ -1,19 +1,11 @@
using System.Collections.Specialized; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters; 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; 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 /> /// <inheritdoc />
public SessionToken? SessionToken { get; set; } public SessionToken? SessionToken { get; set; }
} }

View file

@ -10,11 +10,20 @@ using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2; using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ClientV2.Parameters; using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.Refs; using FrostFS.Refs;
using FrostFS.Session;
using FrostFS.Status;
namespace FrostFS.SDK.ClientV2; namespace FrostFS.SDK.ClientV2;
internal class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context) : ContextAccessor(context) internal class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context) : ContextAccessor(context), ISessionProvider
{ {
readonly SessionProvider sessions = new(context);
public async ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
{
return await sessions.GetOrCreateSession(args, ctx);
}
internal async Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args) internal async Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args)
{ {
GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders); GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders);
@ -58,6 +67,8 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
grpcContainer.OwnerId = Context.Owner.ToMessage(); grpcContainer.OwnerId = Context.Owner.ToMessage();
grpcContainer.Version = Context.Version.ToMessage(); grpcContainer.Version = Context.Version.ToMessage();
var sessionKey = args.SessionKey.LoadWif();
var request = new PutRequest var request = new PutRequest
{ {
Body = new PutRequest.Types.Body Body = new PutRequest.Types.Body
@ -82,12 +93,13 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
internal async Task DeleteContainerAsync(PrmContainerDelete args) internal async Task DeleteContainerAsync(PrmContainerDelete args)
{ {
var ctx = args.Context!; var ctx = args.Context!;
var request = new DeleteRequest var request = new DeleteRequest
{ {
Body = new DeleteRequest.Types.Body Body = new DeleteRequest.Types.Body
{ {
ContainerId = args.ContainerId.ToMessage(), ContainerId = args.ContainerId.ToMessage(),
Signature = Context.Key.ECDsaKey.SignRFC6979(args.ContainerId.ToMessage().Value) Signature = ctx.Credentials!.Key.SignRFC6979(args.ContainerId.ToMessage().Value)
} }
}; };
@ -97,6 +109,8 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
var response = await service.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken); var response = await service.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
Verifier.CheckResponse(response);
await WaitForContainer(WaitExpects.Removed, request.Body.ContainerId, args.WaitParams, ctx); await WaitForContainer(WaitExpects.Removed, request.Body.ContainerId, args.WaitParams, ctx);
Verifier.CheckResponse(response); Verifier.CheckResponse(response);

View file

@ -13,6 +13,8 @@ public class ClientEnvironment(Client client, ECDsa key, OwnerId owner, GrpcChan
private ArrayPool<byte> _arrayPool; private ArrayPool<byte> _arrayPool;
internal OwnerId Owner { get; } = owner; internal OwnerId Owner { get; } = owner;
public ClientKey SessionKey { get; set; }
internal GrpcChannel Channel { get; private set; } = channel; internal GrpcChannel Channel { get; private set; } = channel;
internal ModelsV2.Version Version { get; } = version; internal ModelsV2.Version Version { get; } = version;
internal NetworkSettings? NetworkSettings { get; set; } internal NetworkSettings? NetworkSettings { get; set; }

View file

@ -49,4 +49,22 @@ public static class RequestConstructor
sessionToken.Signature = key.SignMessagePart(sessionToken.Body); sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
} }
public static void CreateContainerTokenContext(this Session.SessionToken sessionToken,
ContainerID? containerId,
ContainerSessionContext.Types.Verb verb,
ECDsa key)
{
if (sessionToken.Body.Container?.ContainerId != null)
return;
sessionToken.Body.Container = new() { Verb = verb };
if (containerId != null)
sessionToken.Body.Container.ContainerId = containerId;
else
sessionToken.Body.Container.Wildcard = true;
sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
}
} }

View file

@ -253,7 +253,7 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam); 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.NotNull(container);
Assert.True(callbackInvoked); Assert.True(callbackInvoked);
@ -338,7 +338,7 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam); 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.NotNull(container);
var bytes = GetRandomBytes(objectSize); var bytes = GetRandomBytes(objectSize);
@ -417,13 +417,13 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam); var containerId = await client.CreateContainerAsync(createContainerParam);
var context = new Context var ctx = new Context
{ {
Timeout = TimeSpan.FromSeconds(10), Timeout = TimeSpan.FromSeconds(10),
Interceptors = new([new MetricsInterceptor()]) 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); Assert.NotNull(container);