diff --git a/.editorconfig b/.editorconfig
index 7a29e50..482baac 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -214,7 +214,7 @@ dotnet_diagnostic.CA1700.severity = warning
dotnet_diagnostic.CA1707.severity = warning
# CA1708: Identifiers should differ by more than case
-dotnet_diagnostic.CA1708.severity = warning
+dotnet_diagnostic.CA1708.severity = none
# CA1710: Identifiers should have correct suffix
dotnet_diagnostic.CA1710.severity = warning
@@ -232,7 +232,7 @@ dotnet_diagnostic.CA1713.severity = warning
dotnet_diagnostic.CA1715.severity = warning
# CA1716: Identifiers should not match keywords
-dotnet_diagnostic.CA1716.severity = warning
+dotnet_diagnostic.CA1716.severity = none
# CA1720: Identifier contains type name
dotnet_diagnostic.CA1720.severity = warning
diff --git a/src/FrostFS.SDK.Client/CllientKey.cs b/src/FrostFS.SDK.Client/CllientKey.cs
index cdafb3f..da02b02 100644
--- a/src/FrostFS.SDK.Client/CllientKey.cs
+++ b/src/FrostFS.SDK.Client/CllientKey.cs
@@ -11,4 +11,8 @@ public class ClientKey(ECDsa key)
internal ECDsa ECDsaKey { get; } = key;
internal ByteString PublicKeyProto { get; } = ByteString.CopyFrom(key.PublicKey());
+
+ internal string PublicKey { get; } = key.PublicKey().ToString();
+
+ internal FrostFsOwner Owner { get; } = new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
}
diff --git a/src/FrostFS.SDK.Client/FrostFS.SDK.Client.csproj b/src/FrostFS.SDK.Client/FrostFS.SDK.Client.csproj
index e175d13..7f4df50 100644
--- a/src/FrostFS.SDK.Client/FrostFS.SDK.Client.csproj
+++ b/src/FrostFS.SDK.Client/FrostFS.SDK.Client.csproj
@@ -14,6 +14,10 @@
true
+
+
+ true
+
diff --git a/src/FrostFS.SDK.Client/FrostFSClient.cs b/src/FrostFS.SDK.Client/FrostFSClient.cs
index 4112a5b..e73ba49 100644
--- a/src/FrostFS.SDK.Client/FrostFSClient.cs
+++ b/src/FrostFS.SDK.Client/FrostFSClient.cs
@@ -4,12 +4,7 @@ using System.Net.Http;
using System.Threading.Tasks;
using Frostfs.V2.Ape;
-using Frostfs.V2.Apemanager;
-using FrostFS.Accounting;
-using FrostFS.Container;
-using FrostFS.Netmap;
-using FrostFS.Object;
using FrostFS.SDK.Client.Interfaces;
using FrostFS.SDK.Client.Services;
using FrostFS.SDK.Cryptography;
@@ -21,32 +16,40 @@ using Grpc.Net.Client;
using Microsoft.Extensions.Options;
+using static Frostfs.V2.Apemanager.APEManagerService;
+using static FrostFS.Accounting.AccountingService;
+using static FrostFS.Container.ContainerService;
+using static FrostFS.Netmap.NetmapService;
+using static FrostFS.Object.ObjectService;
+using static FrostFS.Session.SessionService;
+
namespace FrostFS.SDK.Client;
public class FrostFSClient : IFrostFSClient
{
private bool isDisposed;
- internal ContainerService.ContainerServiceClient? ContainerServiceClient { get; set; }
+ internal ContainerServiceClient? ContainerServiceClient { get; set; }
+ internal ContainerServiceProvider? ContainerServiceProvider { get; set; }
- internal NetmapService.NetmapServiceClient? NetmapServiceClient { get; set; }
+ internal NetmapServiceClient? NetmapServiceClient { get; set; }
+ internal NetmapServiceProvider? NetmapServiceProvider { get; set; }
- internal APEManagerService.APEManagerServiceClient? ApeManagerServiceClient { get; set; }
+ internal APEManagerServiceClient? ApeManagerServiceClient { get; set; }
+ internal ApeManagerServiceProvider? ApeManagerServiceProvider { get; set; }
- internal SessionService.SessionServiceClient? SessionServiceClient { get; set; }
+ internal SessionServiceClient? SessionServiceClient { get; set; }
+ internal SessionServiceProvider? SessionServiceProvider { get; set; }
- internal ObjectService.ObjectServiceClient? ObjectServiceClient { get; set; }
+ internal ObjectServiceClient? ObjectServiceClient { get; set; }
+ internal ObjectServiceProvider? ObjectServiceProvider { get; set; }
- internal AccountingService.AccountingServiceClient? AccountingServiceClient { get; set; }
+ internal AccountingServiceClient? AccountingServiceClient { get; set; }
+ internal AccountingServiceProvider? AccountingServiceProvider { get; set; }
internal ClientContext ClientCtx { get; set; }
- public static IFrostFSClient GetInstance(IOptions clientOptions, GrpcChannelOptions? channelOptions = null)
- {
- return new FrostFSClient(clientOptions, channelOptions);
- }
-
- public static IFrostFSClient GetSingleOwnerInstance(IOptions clientOptions, GrpcChannelOptions? channelOptions = null)
+ public static IFrostFSClient GetSingleOwnerInstance(IOptions clientOptions, GrpcChannelOptions? channelOptions = null)
{
return new FrostFSClient(clientOptions, channelOptions);
}
@@ -62,28 +65,28 @@ public class FrostFSClient : IFrostFSClient
/// Object.ObjectService.ObjectServiceClient implementation
///
public static IFrostFSClient GetTestInstance(
- IOptions clientOptions,
+ IOptions settings,
GrpcChannelOptions? channelOptions,
- NetmapService.NetmapServiceClient netmapService,
- SessionService.SessionServiceClient sessionService,
- ContainerService.ContainerServiceClient containerService,
- ObjectService.ObjectServiceClient objectService)
+ NetmapServiceClient netmapService,
+ SessionServiceClient sessionService,
+ ContainerServiceClient containerService,
+ ObjectServiceClient objectService)
{
- if (clientOptions is null)
+ if (settings is null)
{
- throw new ArgumentNullException(nameof(clientOptions));
+ throw new ArgumentNullException(nameof(settings));
}
- return new FrostFSClient(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
+ return new FrostFSClient(settings, channelOptions, containerService, netmapService, sessionService, objectService);
}
private FrostFSClient(
- IOptions settings,
+ IOptions settings,
GrpcChannelOptions? channelOptions,
- ContainerService.ContainerServiceClient containerService,
- NetmapService.NetmapServiceClient netmapService,
- SessionService.SessionServiceClient sessionService,
- ObjectService.ObjectServiceClient objectService)
+ ContainerServiceClient containerService,
+ NetmapServiceClient netmapService,
+ SessionServiceClient sessionService,
+ ObjectServiceClient objectService)
{
if (settings is null)
{
@@ -91,14 +94,18 @@ public class FrostFSClient : IFrostFSClient
}
var ecdsaKey = settings.Value.Key.LoadWif();
- FrostFsOwner.FromKey(ecdsaKey);
ClientCtx = new ClientContext(
client: this,
- key: ecdsaKey,
+ key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
- version: new FrostFsVersion(2, 13));
+ version: new FrostFsVersion(2, 13))
+ {
+ SessionCache = new SessionCache(0),
+ Callback = settings.Value.Callback,
+ Interceptors = settings.Value.Interceptors
+ };
ContainerServiceClient = containerService ?? throw new ArgumentNullException(nameof(containerService));
NetmapServiceClient = netmapService ?? throw new ArgumentNullException(nameof(netmapService));
@@ -106,28 +113,9 @@ public class FrostFSClient : IFrostFSClient
ObjectServiceClient = objectService ?? throw new ArgumentNullException(nameof(objectService));
}
- private FrostFSClient(IOptions options, GrpcChannelOptions? channelOptions)
+ private FrostFSClient(IOptions settings, GrpcChannelOptions? channelOptions)
{
- var clientSettings = (options?.Value) ?? throw new ArgumentNullException(nameof(options), "Options value must be initialized");
-
- clientSettings.Validate();
-
- var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
-
- ClientCtx = new ClientContext(
- this,
- key: null,
- owner: null,
- channel: channel,
- version: new FrostFsVersion(2, 13));
-
- // TODO: define timeout logic
- // CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
- }
-
- private FrostFSClient(IOptions options, GrpcChannelOptions? channelOptions)
- {
- var clientSettings = (options?.Value) ?? throw new ArgumentNullException(nameof(options), "Options value must be initialized");
+ var clientSettings = (settings?.Value) ?? throw new ArgumentNullException(nameof(settings), "Options value must be initialized");
clientSettings.Validate();
@@ -137,10 +125,15 @@ public class FrostFSClient : IFrostFSClient
ClientCtx = new ClientContext(
this,
- key: ecdsaKey,
+ key: new ClientKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: channel,
- version: new FrostFsVersion(2, 13));
+ version: new FrostFsVersion(2, 13))
+ {
+ SessionCache = new SessionCache(0),
+ Callback = settings.Value.Callback,
+ Interceptors = settings.Value.Interceptors
+ };
// TODO: define timeout logic
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
@@ -150,12 +143,14 @@ public class FrostFSClient : IFrostFSClient
{
ClientCtx = new ClientContext(
client: this,
- key: prm.Key,
+ key: new ClientKey(prm.Key),
owner: FrostFsOwner.FromKey(prm.Key!),
channel: InitGrpcChannel(prm.Address, null), //prm.GrpcChannelOptions),
version: new FrostFsVersion(2, 13))
{
- SessionCache = cache
+ SessionCache = cache,
+ Interceptors = prm.Interceptors,
+ Callback = prm.Callback
};
}
@@ -175,14 +170,14 @@ public class FrostFSClient : IFrostFSClient
}
#region ApeManagerImplementation
- public Task AddChainAsync(PrmApeChainAdd args)
+ public Task> AddChainAsync(PrmApeChainAdd args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
- var service = GetApeManagerService(args);
+ var service = GetApeManagerService();
return service.AddChainAsync(args);
}
@@ -193,7 +188,7 @@ public class FrostFSClient : IFrostFSClient
throw new ArgumentNullException(nameof(args));
}
- var service = GetApeManagerService(args);
+ var service = GetApeManagerService();
return service.RemoveChainAsync(args);
}
@@ -202,7 +197,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetApeManagerService(args);
+ var service = GetApeManagerService();
return service.ListChainAsync(args);
}
#endregion
@@ -213,14 +208,14 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetContainerService(args);
+ var service = GetContainerService();
return service.GetContainerAsync(args);
}
public IAsyncEnumerable ListContainersAsync(PrmContainerGetAll? args = null)
{
args ??= new PrmContainerGetAll();
- var service = GetContainerService(args);
+ var service = GetContainerService();
return service.ListContainersAsync(args);
}
@@ -229,7 +224,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetContainerService(args);
+ var service = GetContainerService();
return service.CreateContainerAsync(args);
}
@@ -238,7 +233,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetContainerService(args);
+ var service = GetContainerService();
return service.DeleteContainerAsync(args);
}
#endregion
@@ -247,21 +242,21 @@ public class FrostFSClient : IFrostFSClient
public Task GetNetmapSnapshotAsync(PrmNetmapSnapshot? args)
{
args ??= new PrmNetmapSnapshot();
- var service = GetNetmapService(args);
+ var service = GetNetmapService();
return service.GetNetmapSnapshotAsync(args);
}
public Task GetNodeInfoAsync(PrmNodeInfo? args)
{
args ??= new PrmNodeInfo();
- var service = GetNetmapService(args);
+ var service = GetNetmapService();
return service.GetLocalNodeInfoAsync(args);
}
public Task GetNetworkSettingsAsync(PrmNetworkSettings? args)
{
args ??= new PrmNetworkSettings();
- var service = GetNetmapService(args);
+ var service = GetNetmapService();
return service.GetNetworkSettingsAsync(args.Context!);
}
#endregion
@@ -272,7 +267,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.GetObjectHeadAsync(args);
}
@@ -281,7 +276,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.GetObjectAsync(args);
}
@@ -290,7 +285,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.GetRangeAsync(args);
}
@@ -299,17 +294,16 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.GetRangeHashAsync(args);
}
-
public Task PutObjectAsync(PrmObjectPut args)
{
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.PutObjectAsync(args);
}
@@ -318,7 +312,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.PutSingleObjectAsync(args);
}
@@ -329,7 +323,7 @@ public class FrostFSClient : IFrostFSClient
throw new ArgumentNullException(nameof(args));
}
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.PatchObjectAsync(args);
}
@@ -338,7 +332,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.DeleteObjectAsync(args);
}
@@ -347,7 +341,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetObjectService(args);
+ var service = GetObjectService();
return service.SearchObjectsAsync(args);
}
#endregion
@@ -358,10 +352,9 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var session = await CreateSessionInternalAsync(args).ConfigureAwait(false);
+ var token = await CreateSessionInternalAsync(args).ConfigureAwait(false);
- var token = session.Serialize();
- return new FrostFsSessionToken(token, session.Body.Id.ToUuid());
+ return new FrostFsSessionToken(token);
}
internal Task CreateSessionInternalAsync(PrmSessionCreate args)
@@ -369,7 +362,7 @@ public class FrostFSClient : IFrostFSClient
if (args is null)
throw new ArgumentNullException(nameof(args));
- var service = GetSessionService(args);
+ var service = GetSessionService();
return service.CreateSessionAsync(args);
}
#endregion
@@ -379,18 +372,18 @@ public class FrostFSClient : IFrostFSClient
{
args ??= new PrmBalance();
- var service = GetAccouningService(args);
+ var service = GetAccouningService();
return await service.GetBallance(args).ConfigureAwait(false);
}
#endregion
#region ToolsImplementation
- public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, CallContext ctx)
+ public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header)
{
if (header == null)
throw new ArgumentNullException(nameof(header));
- return ObjectTools.CalculateObjectId(header, ctx);
+ return ObjectTools.CalculateObjectId(header, this.ClientCtx);
}
#endregion
@@ -398,59 +391,34 @@ public class FrostFSClient : IFrostFSClient
{
var args = new PrmNodeInfo(ctx);
- if (ctx?.Version == null)
- throw new ArgumentNullException(nameof(ctx), "Version must be initialized");
-
- var service = GetNetmapService(args);
+ var service = GetNetmapService();
var localNodeInfo = await service.GetLocalNodeInfoAsync(args).ConfigureAwait(false);
- if (!localNodeInfo.Version.IsSupported(ctx.Version))
+ if (!localNodeInfo.Version.IsSupported(ClientCtx.Version))
{
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
throw new FrostFsException(msg);
}
}
- private CallInvoker? SetupClientContext(IContext ctx)
+ private CallInvoker? CreateInvoker()
{
if (isDisposed)
throw new FrostFsInvalidObjectException("Client is disposed.");
- if (ctx.Context!.Key == null)
- {
- if (ClientCtx.Key == null)
- {
- throw new ArgumentNullException(nameof(ctx), "Key is not initialized.");
- }
-
- ctx.Context.Key = ClientCtx.Key.ECDsaKey;
- }
-
- if (ctx.Context.OwnerId == null)
- {
- ctx.Context.OwnerId = ClientCtx.Owner ?? FrostFsOwner.FromKey(ctx.Context.Key);
- }
-
- if (ctx.Context.Version == null)
- {
- if (ClientCtx.Version == null)
- {
- throw new ArgumentNullException(nameof(ctx), "Version is not initialized.");
- }
-
- ctx.Context.Version = ClientCtx.Version;
- }
-
CallInvoker? callInvoker = null;
- foreach (var interceptor in ctx.Context.Interceptors)
- callInvoker = AddInvoker(callInvoker, interceptor);
+ if (ClientCtx.Interceptors != null)
+ {
+ foreach (var interceptor in ClientCtx.Interceptors)
+ callInvoker = AddInvoker(callInvoker, interceptor);
+ }
- if (ctx.Context.Callback != null)
- callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ctx.Context.Callback));
+ if (ClientCtx.Callback != null)
+ callInvoker = AddInvoker(callInvoker, new MetricsInterceptor(ClientCtx.Callback));
- if (ctx.Context.PoolErrorHandler != null)
- callInvoker = AddInvoker(callInvoker, new ErrorInterceptor(ctx.Context.PoolErrorHandler));
+ if (ClientCtx.PoolErrorHandler != null)
+ callInvoker = AddInvoker(callInvoker, new ErrorInterceptor(ClientCtx.PoolErrorHandler));
return callInvoker;
@@ -465,75 +433,109 @@ public class FrostFSClient : IFrostFSClient
}
}
- private NetmapServiceProvider GetNetmapService(IContext ctx)
+ private NetmapServiceProvider GetNetmapService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = NetmapServiceClient ?? (callInvoker != null
- ? new NetmapService.NetmapServiceClient(callInvoker)
- : new NetmapService.NetmapServiceClient(ClientCtx.Channel));
+ if (NetmapServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
- return new NetmapServiceProvider(client, ClientCtx);
+ NetmapServiceClient = NetmapServiceClient ?? (
+ invoker != null
+ ? new NetmapServiceClient(invoker)
+ : new NetmapServiceClient(ClientCtx.Channel));
+
+ NetmapServiceProvider = new NetmapServiceProvider(NetmapServiceClient, ClientCtx);
+ }
+
+ return NetmapServiceProvider;
}
- private SessionServiceProvider GetSessionService(IContext ctx)
+ private SessionServiceProvider GetSessionService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = SessionServiceClient ?? (callInvoker != null
- ? new SessionService.SessionServiceClient(callInvoker)
- : new SessionService.SessionServiceClient(ClientCtx.Channel));
+ if (SessionServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
+
+ SessionServiceClient = SessionServiceClient ?? (
+ invoker != null
+ ? new SessionServiceClient(invoker)
+ : new SessionServiceClient(ClientCtx.Channel));
+
+ SessionServiceProvider = new SessionServiceProvider(SessionServiceClient, ClientCtx);
+ }
+
+ return SessionServiceProvider;
- return new SessionServiceProvider(client, ClientCtx);
}
- private ApeManagerServiceProvider GetApeManagerService(IContext ctx)
+ private ApeManagerServiceProvider GetApeManagerService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = ApeManagerServiceClient ?? (callInvoker != null
- ? new APEManagerService.APEManagerServiceClient(callInvoker)
- : new APEManagerService.APEManagerServiceClient(ClientCtx.Channel));
+ if (ApeManagerServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
- return new ApeManagerServiceProvider(client, ClientCtx);
+ ApeManagerServiceClient = ApeManagerServiceClient ?? (
+ invoker != null
+ ? new APEManagerServiceClient(invoker)
+ : new APEManagerServiceClient(ClientCtx.Channel));
+
+ ApeManagerServiceProvider = new ApeManagerServiceProvider(ApeManagerServiceClient, ClientCtx);
+ }
+
+ return ApeManagerServiceProvider;
}
- private AccountingServiceProvider GetAccouningService(IContext ctx)
+ private AccountingServiceProvider GetAccouningService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = AccountingServiceClient ?? (callInvoker != null
- ? new AccountingService.AccountingServiceClient(callInvoker)
- : new AccountingService.AccountingServiceClient(ClientCtx.Channel));
+ if (this.AccountingServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
- return new AccountingServiceProvider(client, ClientCtx);
+ AccountingServiceClient = AccountingServiceClient ?? (
+ invoker != null
+ ? new AccountingServiceClient(invoker)
+ : new AccountingServiceClient(ClientCtx.Channel));
+
+ AccountingServiceProvider = new AccountingServiceProvider(AccountingServiceClient, ClientCtx);
+ }
+
+ return AccountingServiceProvider;
}
- private ContainerServiceProvider GetContainerService(IContext ctx)
+ private ContainerServiceProvider GetContainerService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = ContainerServiceClient ?? (callInvoker != null
- ? new ContainerService.ContainerServiceClient(callInvoker)
- : new ContainerService.ContainerServiceClient(ClientCtx.Channel));
+ if (this.ContainerServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
- return new ContainerServiceProvider(client, ClientCtx);
+ ContainerServiceClient = ContainerServiceClient ?? (
+ invoker != null
+ ? new ContainerServiceClient(invoker)
+ : new ContainerServiceClient(ClientCtx.Channel));
+
+ ContainerServiceProvider = new ContainerServiceProvider(ContainerServiceClient, ClientCtx);
+ }
+
+ return ContainerServiceProvider;
}
- private ObjectServiceProvider GetObjectService(IContext ctx)
+ private ObjectServiceProvider GetObjectService()
{
- var callInvoker = SetupClientContext(ctx);
- var client = ObjectServiceClient ?? (callInvoker != null
- ? new ObjectService.ObjectServiceClient(callInvoker)
- : new ObjectService.ObjectServiceClient(ClientCtx.Channel));
+ if (this.ObjectServiceProvider == null)
+ {
+ var invoker = CreateInvoker();
- return new ObjectServiceProvider(client, ClientCtx);
+ ObjectServiceClient = ObjectServiceClient ?? (
+ invoker != null
+ ? new ObjectServiceClient(invoker)
+ : new ObjectServiceClient(ClientCtx.Channel));
+
+ ObjectServiceProvider = new ObjectServiceProvider(ObjectServiceClient, ClientCtx);
+ }
+
+ return ObjectServiceProvider;
}
- private AccountingServiceProvider GetAccountService(IContext ctx)
- {
- var callInvoker = SetupClientContext(ctx);
- var client = AccountingServiceClient ?? (callInvoker != null
- ? new AccountingService.AccountingServiceClient(callInvoker)
- : new AccountingService.AccountingServiceClient(ClientCtx.Channel));
-
- return new AccountingServiceProvider(client, ClientCtx);
- }
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
{
@@ -559,7 +561,7 @@ public class FrostFSClient : IFrostFSClient
{
var prm = new PrmBalance(ctx);
- var service = GetAccouningService(prm);
+ var service = GetAccouningService();
_ = await service.GetBallance(prm).ConfigureAwait(false);
return null;
diff --git a/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs b/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs
index 456962f..8520528 100644
--- a/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs
+++ b/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs
@@ -21,7 +21,7 @@ public interface IFrostFSClient : IDisposable
#endregion
#region ApeManager
- Task AddChainAsync(PrmApeChainAdd args);
+ Task> AddChainAsync(PrmApeChainAdd args);
Task RemoveChainAsync(PrmApeChainRemove args);
@@ -63,7 +63,7 @@ public interface IFrostFSClient : IDisposable
#endregion
#region Tools
- FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, CallContext ctx);
+ FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header);
#endregion
public Task Dial(CallContext ctx);
diff --git a/src/FrostFS.SDK.Client/Mappers/ContainerId.cs b/src/FrostFS.SDK.Client/Mappers/ContainerId.cs
index fe8632f..df27320 100644
--- a/src/FrostFS.SDK.Client/Mappers/ContainerId.cs
+++ b/src/FrostFS.SDK.Client/Mappers/ContainerId.cs
@@ -43,6 +43,6 @@ public static class ContainerIdMapper
throw new ArgumentNullException(nameof(message));
}
- return new FrostFsContainerId(Base58.Encode(message.Value.ToByteArray()));
+ return new FrostFsContainerId(Base58.Encode(message.Value.Span));
}
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Client/Mappers/Netmap/NodeInfo.cs b/src/FrostFS.SDK.Client/Mappers/Netmap/NodeInfo.cs
index 747468b..d7340eb 100644
--- a/src/FrostFS.SDK.Client/Mappers/Netmap/NodeInfo.cs
+++ b/src/FrostFS.SDK.Client/Mappers/Netmap/NodeInfo.cs
@@ -39,7 +39,7 @@ public static class NodeInfoMapper
state: state,
addresses: [.. nodeInfo.Addresses],
attributes: nodeInfo.Attributes.ToDictionary(n => n.Key, n => n.Value),
- publicKey: nodeInfo.PublicKey.ToByteArray()
+ publicKey: nodeInfo.PublicKey.Memory
);
}
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Client/Mappers/Object/Object.cs b/src/FrostFS.SDK.Client/Mappers/Object/Object.cs
index b9d1520..5f85fc5 100644
--- a/src/FrostFS.SDK.Client/Mappers/Object/Object.cs
+++ b/src/FrostFS.SDK.Client/Mappers/Object/Object.cs
@@ -6,7 +6,7 @@ internal static class ObjectMapper
{
return new FrostFsObject(obj.Header.ToModel())
{
- ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
+ ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.Span)
};
}
}
diff --git a/src/FrostFS.SDK.Client/Mappers/Object/ObjectHeaderMapper.cs b/src/FrostFS.SDK.Client/Mappers/Object/ObjectHeaderMapper.cs
index 1ee29a6..317b31c 100644
--- a/src/FrostFS.SDK.Client/Mappers/Object/ObjectHeaderMapper.cs
+++ b/src/FrostFS.SDK.Client/Mappers/Object/ObjectHeaderMapper.cs
@@ -40,7 +40,7 @@ public static class ObjectHeaderMapper
}
var model = new FrostFsObjectHeader(
- new FrostFsContainerId(Base58.Encode(header.ContainerId.Value.ToByteArray())),
+ new FrostFsContainerId(Base58.Encode(header.ContainerId.Value.Span)),
objTypeName,
header.Attributes.Select(attribute => attribute.ToModel()).ToArray(),
split,
diff --git a/src/FrostFS.SDK.Client/Mappers/Object/ObjectId.cs b/src/FrostFS.SDK.Client/Mappers/Object/ObjectId.cs
index 373edfb..343e3de 100644
--- a/src/FrostFS.SDK.Client/Mappers/Object/ObjectId.cs
+++ b/src/FrostFS.SDK.Client/Mappers/Object/ObjectId.cs
@@ -28,6 +28,6 @@ public static class ObjectIdMapper
throw new ArgumentNullException(nameof(objectId));
}
- return FrostFsObjectId.FromHash(objectId.Value.ToByteArray());
+ return FrostFsObjectId.FromHash(objectId.Value.Span);
}
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Client/Mappers/OwnerId.cs b/src/FrostFS.SDK.Client/Mappers/OwnerId.cs
index 297178a..6739a0b 100644
--- a/src/FrostFS.SDK.Client/Mappers/OwnerId.cs
+++ b/src/FrostFS.SDK.Client/Mappers/OwnerId.cs
@@ -44,7 +44,7 @@ public static class OwnerIdMapper
if (!Caches.Owners.TryGetValue(message, out FrostFsOwner? model))
{
- model = new FrostFsOwner(Base58.Encode(message.Value.ToByteArray()));
+ model = new FrostFsOwner(Base58.Encode(message.Value.Span));
Caches.Owners.Set(message, model, _oneHourExpiration);
}
diff --git a/src/FrostFS.SDK.Client/Models/Client/ClientSettings.cs b/src/FrostFS.SDK.Client/Models/Client/ClientSettings.cs
index 6ebec1f..4aa00f9 100644
--- a/src/FrostFS.SDK.Client/Models/Client/ClientSettings.cs
+++ b/src/FrostFS.SDK.Client/Models/Client/ClientSettings.cs
@@ -3,6 +3,8 @@ using System.Collections.ObjectModel;
using System.Globalization;
using System.Text;
+using Grpc.Core.Interceptors;
+
namespace FrostFS.SDK;
public class ClientSettings
@@ -11,60 +13,25 @@ public class ClientSettings
public string Host { get; set; } = string.Empty;
- public virtual void Validate()
- {
- var errors = CheckFields();
- if (errors != null)
- ThrowSettingsException(errors);
- }
-
- protected Collection? CheckFields()
- {
- if (string.IsNullOrWhiteSpace(Host))
- {
- var error = string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Host));
- return new Collection([error]);
- }
-
- return null;
- }
-
- protected static void ThrowSettingsException(Collection errors)
- {
- if (errors is null)
- {
- throw new ArgumentNullException(nameof(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)
- ThrowSettingsException(errors);
- }
+ public Action? Callback { get; set; }
- protected new Collection? CheckFields()
+ public Collection Interceptors { get; } = [];
+
+ public void Validate()
{
- Collection? errors = base.CheckFields();
+ StringBuilder? errors = null;
+
+ if (string.IsNullOrWhiteSpace(Host))
+ (errors = new StringBuilder(128)).AppendLine(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Host)));
if (string.IsNullOrWhiteSpace(Key))
- (errors ??= []).Add(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Key)));
+ (errors ??= new StringBuilder(128)).AppendLine(string.Format(CultureInfo.InvariantCulture, errorTemplate, nameof(Key)));
- return errors;
+ if (errors != null)
+ {
+ throw new ArgumentException(errors.ToString());
+ }
}
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerId.cs b/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerId.cs
index f0b3fdf..9f081cd 100644
--- a/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerId.cs
+++ b/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerId.cs
@@ -27,7 +27,7 @@ public class FrostFsContainerId
if (containerID != null)
{
- this.modelId = Base58.Encode(containerID.Value.ToByteArray());
+ this.modelId = Base58.Encode(containerID.Value.Span);
return this.modelId;
}
diff --git a/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerInfo.cs b/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerInfo.cs
index 6223a7f..af4ffdc 100644
--- a/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerInfo.cs
+++ b/src/FrostFS.SDK.Client/Models/Containers/FrostFsContainerInfo.cs
@@ -96,7 +96,7 @@ public class FrostFsContainerInfo
PlacementPolicy = PlacementPolicy.Value.GetPolicy(),
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
OwnerId = Owner?.OwnerID,
- Version = Version?.Version
+ Version = Version?.VersionID
};
var attribs = GetGrpsAttributes();
diff --git a/src/FrostFS.SDK.Client/Models/Netmap/FrostFsVersion.cs b/src/FrostFS.SDK.Client/Models/Netmap/FrostFsVersion.cs
index 6fd0afc..81e642d 100644
--- a/src/FrostFS.SDK.Client/Models/Netmap/FrostFsVersion.cs
+++ b/src/FrostFS.SDK.Client/Models/Netmap/FrostFsVersion.cs
@@ -10,7 +10,7 @@ public class FrostFsVersion(int major, int minor)
public int Major { get; set; } = major;
public int Minor { get; set; } = minor;
- internal Version Version
+ internal Version VersionID
{
get
{
diff --git a/src/FrostFS.SDK.Client/Models/Object/FrostFsObjectId.cs b/src/FrostFS.SDK.Client/Models/Object/FrostFsObjectId.cs
index 49fde5a..57300a3 100644
--- a/src/FrostFS.SDK.Client/Models/Object/FrostFsObjectId.cs
+++ b/src/FrostFS.SDK.Client/Models/Object/FrostFsObjectId.cs
@@ -8,13 +8,8 @@ public class FrostFsObjectId(string id)
{
public string Value { get; } = id;
- public static FrostFsObjectId FromHash(byte[] hash)
+ public static FrostFsObjectId FromHash(ReadOnlySpan hash)
{
- if (hash is null)
- {
- throw new ArgumentNullException(nameof(hash));
- }
-
if (hash.Length != Constants.Sha256HashLength)
throw new FormatException("ObjectID must be a sha256 hash.");
diff --git a/src/FrostFS.SDK.Client/Models/Object/FrostFsOwner.cs b/src/FrostFS.SDK.Client/Models/Object/FrostFsOwner.cs
index 1bd6754..228edf2 100644
--- a/src/FrostFS.SDK.Client/Models/Object/FrostFsOwner.cs
+++ b/src/FrostFS.SDK.Client/Models/Object/FrostFsOwner.cs
@@ -4,6 +4,7 @@ using FrostFS.Refs;
using FrostFS.SDK.Client.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
+
namespace FrostFS.SDK;
public class FrostFsOwner(string id)
diff --git a/src/FrostFS.SDK.Client/Models/Session/FrostFsSessionToken.cs b/src/FrostFS.SDK.Client/Models/Session/FrostFsSessionToken.cs
index 672754d..54f0615 100644
--- a/src/FrostFS.SDK.Client/Models/Session/FrostFsSessionToken.cs
+++ b/src/FrostFS.SDK.Client/Models/Session/FrostFsSessionToken.cs
@@ -1,9 +1,117 @@
using System;
+using FrostFS.Refs;
+
+using FrostFS.SDK.Client;
+using FrostFS.SDK.Cryptography;
+using FrostFS.Session;
+
+using Google.Protobuf;
+
namespace FrostFS.SDK;
-public class FrostFsSessionToken(byte[] token, Guid id)
+public class FrostFsSessionToken
{
- public Guid Id { get; private set; } = id;
- public byte[] Token { get; private set; } = token;
+ private Guid _id;
+ private ReadOnlyMemory _sessionKey;
+ private readonly SessionToken.Types.Body _body;
+
+ private FrostFsSessionToken()
+ {
+ ProtoId = ByteString.Empty;
+ ProtoSessionKey = ByteString.Empty;
+ _body = new SessionToken.Types.Body();
+ }
+
+ internal FrostFsSessionToken(SessionToken token)
+ {
+ ProtoId = token.Body.Id;
+ ProtoSessionKey = token.Body.SessionKey;
+
+ _body = token.Body;
+ }
+
+ public Guid Id
+ {
+ get
+ {
+ if (_id == Guid.Empty)
+ _id = ProtoId.ToUuid();
+
+ return _id;
+ }
+ }
+
+ public ReadOnlyMemory SessionKey
+ {
+ get
+ {
+ if (_sessionKey.IsEmpty)
+ _sessionKey = ProtoSessionKey.Memory;
+
+ return _sessionKey;
+ }
+ }
+
+ internal ByteString ProtoId { get; }
+
+ internal ByteString ProtoSessionKey { get; }
+
+ public SessionToken CreateContainerToken(ContainerID? containerId, ContainerSessionContext.Types.Verb verb, ClientKey key)
+ {
+ if (key is null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ SessionToken sessionToken = new() { Body = _body.Clone() };
+
+ sessionToken.Body.Container = new() { Verb = verb };
+
+ if (containerId != null)
+ sessionToken.Body.Container.ContainerId = containerId;
+ else
+ sessionToken.Body.Container.Wildcard = true;
+
+ sessionToken.Body.SessionKey = key.PublicKeyProto;
+
+ sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
+
+ return sessionToken;
+ }
+
+ public SessionToken CreateObjectTokenContext(Address address, ObjectSessionContext.Types.Verb verb, ClientKey key)
+ {
+ if (address is null)
+ {
+ throw new ArgumentNullException(nameof(address));
+ }
+
+ if (key is null)
+ {
+ throw new ArgumentNullException(nameof(key));
+ }
+
+ SessionToken sessionToken = new()
+ {
+ Body = _body.Clone()
+ };
+
+ ObjectSessionContext.Types.Target target = new() { Container = address.ContainerId };
+
+ if (address.ObjectId != null)
+ target.Objects.Add(address.ObjectId);
+
+ sessionToken.Body.Object = new()
+ {
+ Target = target,
+ Verb = verb
+ };
+
+ sessionToken.Body.SessionKey = key.PublicKeyProto;
+
+ sessionToken.Signature = key.ECDsaKey.SignMessagePart(sessionToken.Body);
+
+ return sessionToken;
+ }
}
diff --git a/src/FrostFS.SDK.Client/Parameters/CallContext.cs b/src/FrostFS.SDK.Client/Parameters/CallContext.cs
index 323a990..05e061c 100644
--- a/src/FrostFS.SDK.Client/Parameters/CallContext.cs
+++ b/src/FrostFS.SDK.Client/Parameters/CallContext.cs
@@ -1,27 +1,16 @@
using System;
-using System.Collections.ObjectModel;
-using System.Security.Cryptography;
using System.Threading;
-using FrostFS.SDK.Cryptography;
-
-using Google.Protobuf;
-
-using Grpc.Core.Interceptors;
-
namespace FrostFS.SDK.Client;
public class CallContext()
{
- private ByteString? publicKeyCache;
- internal Action? PoolErrorHandler { get; set; }
+ // internal Action? PoolErrorHandler { get; set; }
- public ECDsa? Key { get; set; }
+ // public FrostFsOwner? OwnerId { get; set; }
- public FrostFsOwner? OwnerId { get; set; }
-
- public FrostFsVersion? Version { get; set; }
+ // public FrostFsVersion? Version { get; set; }
public CancellationToken CancellationToken { get; set; }
@@ -29,17 +18,7 @@ public class CallContext()
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
- public Action? Callback { get; set; }
+ // public Action? Callback { get; set; }
- public Collection Interceptors { get; } = [];
-
- public ByteString? GetPublicKeyCache()
- {
- if (publicKeyCache == null && Key != null)
- {
- publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
- }
-
- return publicKeyCache;
- }
+ // public Collection Interceptors { get; } = [];
}
diff --git a/src/FrostFS.SDK.Client/Pool/ClientWrapper.cs b/src/FrostFS.SDK.Client/Pool/ClientWrapper.cs
index 7e50337..de984d6 100644
--- a/src/FrostFS.SDK.Client/Pool/ClientWrapper.cs
+++ b/src/FrostFS.SDK.Client/Pool/ClientWrapper.cs
@@ -9,10 +9,8 @@ namespace FrostFS.SDK.Client;
public class ClientWrapper : ClientStatusMonitor
{
private readonly object _lock = new();
-
private SessionCache sessionCache;
-
internal ClientWrapper(WrapperPrm wrapperPrm, Pool pool) : base(wrapperPrm.Logger, wrapperPrm.Address)
{
WrapperPrm = wrapperPrm;
@@ -140,6 +138,7 @@ public class ClientWrapper : ClientStatusMonitor
catch (FrostFsException)
{
SetUnhealthy();
+
return wasHealthy;
}
diff --git a/src/FrostFS.SDK.Client/Pool/InitParameters.cs b/src/FrostFS.SDK.Client/Pool/InitParameters.cs
index 480820e..3f4d14e 100644
--- a/src/FrostFS.SDK.Client/Pool/InitParameters.cs
+++ b/src/FrostFS.SDK.Client/Pool/InitParameters.cs
@@ -1,6 +1,8 @@
using System;
+using System.Collections.ObjectModel;
using System.Security.Cryptography;
+using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
@@ -33,4 +35,8 @@ public class InitParameters
public ulong GracefulCloseOnSwitchTimeout { get; set; }
public ILogger? Logger { get; set; }
+
+ public Action? Callback { get; set; }
+
+ public Collection Interceptors { get; } = [];
}
diff --git a/src/FrostFS.SDK.Client/Pool/Pool.cs b/src/FrostFS.SDK.Client/Pool/Pool.cs
index 105978d..acb60b9 100644
--- a/src/FrostFS.SDK.Client/Pool/Pool.cs
+++ b/src/FrostFS.SDK.Client/Pool/Pool.cs
@@ -35,18 +35,17 @@ public partial class Pool : IFrostFSClient
private InnerPool[]? InnerPools { get; set; }
- private ECDsa Key { get; set; }
-
- private string PublicKey { get; }
+ private ClientKey Key { get; set; }
private OwnerID? _ownerId;
+
private FrostFsOwner? _owner;
private FrostFsOwner Owner
{
get
{
- _owner ??= new FrostFsOwner(Key.PublicKey().PublicKeyToAddress());
+ _owner ??= new FrostFsOwner(Key.ECDsaKey.PublicKey().PublicKeyToAddress());
return _owner;
}
}
@@ -57,7 +56,7 @@ public partial class Pool : IFrostFSClient
{
if (_ownerId == null)
{
- _owner = new FrostFsOwner(Key.PublicKey().PublicKeyToAddress());
+ _owner = Key.Owner;
_ownerId = _owner.ToMessage();
}
return _ownerId;
@@ -101,8 +100,7 @@ public partial class Pool : IFrostFSClient
FillDefaultInitParams(options, this);
- Key = options.Key;
- PublicKey = $"{Key.PublicKey()}";
+ Key = new ClientKey(options.Key);
SessionCache = cache;
logger = options.Logger;
@@ -115,16 +113,9 @@ public partial class Pool : IFrostFSClient
options.SessionExpirationDuration);
ClientBuilder = options.ClientBuilder!;
- }
- private void SetupContext(CallContext ctx)
- {
- if (ctx == null)
- {
- throw new ArgumentNullException(nameof(ctx));
- }
+ // ClientContext.PoolErrorHandler = client.HandleError;
- ctx.Key ??= Key;
}
// Dial establishes a connection to the servers from the FrostFS network.
@@ -137,8 +128,6 @@ public partial class Pool : IFrostFSClient
// See also InitParameters.SetClientRebalanceInterval.
public async Task Dial(CallContext ctx)
{
- SetupContext(ctx);
-
var inner = new InnerPool[RebalanceParams.NodesParams.Length];
bool atLeastOneHealthy = false;
@@ -158,11 +147,11 @@ public partial class Pool : IFrostFSClient
await client.Dial(ctx).ConfigureAwait(false);
dialed = true;
- var token = await InitSessionForDuration(ctx, client, RebalanceParams.SessionExpirationDuration, Key, false)
+ var token = await InitSessionForDuration(ctx, client, RebalanceParams.SessionExpirationDuration, Key.ECDsaKey, false)
.ConfigureAwait(false);
- var key = FormCacheKey(nodeParams.Addresses[j], Key.PrivateKey().ToString());
- _ = SessionCache.Cache[key] = token;
+ var key = FormCacheKey(nodeParams.Addresses[j], Key.PublicKey);
+ SessionCache.SetValue(key, token);
atLeastOneHealthy = true;
}
@@ -291,12 +280,14 @@ public partial class Pool : IFrostFSClient
var wrapperPrm = new WrapperPrm
{
Address = address,
- Key = parameters.Key,
+ Key = parameters.Key!,
Logger = parameters.Logger,
DialTimeout = parameters.NodeDialTimeout,
StreamTimeout = parameters.NodeStreamTimeout,
ErrorThreshold = parameters.ErrorThreshold,
- GracefulCloseOnSwitchTimeout = parameters.GracefulCloseOnSwitchTimeout
+ GracefulCloseOnSwitchTimeout = parameters.GracefulCloseOnSwitchTimeout,
+ Callback = parameters.Callback,
+ Interceptors = parameters.Interceptors
};
return new ClientWrapper(wrapperPrm, pool);
@@ -318,7 +309,7 @@ public partial class Pool : IFrostFSClient
throw new FrostFsException("Cannot find alive client");
}
- private static async Task InitSessionForDuration(CallContext ctx, ClientWrapper cw, ulong duration, ECDsa key, bool clientCut)
+ private static async Task InitSessionForDuration(CallContext ctx, ClientWrapper cw, ulong duration, ECDsa key, bool clientCut)
{
var client = cw.Client;
var networkInfo = await client!.GetNetworkSettingsAsync(new PrmNetworkSettings(ctx)).ConfigureAwait(false);
@@ -521,7 +512,6 @@ public partial class Pool : IFrostFSClient
var client = Connection();
args ??= new();
- args.Context.PoolErrorHandler = client.HandleError;
return await client.Client!.GetNetmapSnapshotAsync(args).ConfigureAwait(false);
}
@@ -529,278 +519,126 @@ public partial class Pool : IFrostFSClient
public async Task GetNodeInfoAsync(PrmNodeInfo? args = null)
{
var client = Connection();
-
- args ??= new();
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetNodeInfoAsync(args).ConfigureAwait(false);
}
public async Task GetNetworkSettingsAsync(PrmNetworkSettings? args = null)
{
var client = Connection();
-
- args ??= new();
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetNetworkSettingsAsync(args).ConfigureAwait(false);
}
public async Task CreateSessionAsync(PrmSessionCreate args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.CreateSessionAsync(args).ConfigureAwait(false);
}
- public async Task AddChainAsync(PrmApeChainAdd args)
+ public async Task> AddChainAsync(PrmApeChainAdd args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.AddChainAsync(args).ConfigureAwait(false);
}
public async Task RemoveChainAsync(PrmApeChainRemove args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
await client.Client!.RemoveChainAsync(args).ConfigureAwait(false);
}
public async Task ListChainAsync(PrmApeChainList args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.ListChainAsync(args).ConfigureAwait(false);
}
public async Task GetContainerAsync(PrmContainerGet args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetContainerAsync(args).ConfigureAwait(false);
}
public IAsyncEnumerable ListContainersAsync(PrmContainerGetAll? args = null)
{
var client = Connection();
-
- args ??= new();
- args.Context.PoolErrorHandler = client.HandleError;
-
return client.Client!.ListContainersAsync(args);
}
public async Task CreateContainerAsync(PrmContainerCreate args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.CreateContainerAsync(args).ConfigureAwait(false);
}
public async Task DeleteContainerAsync(PrmContainerDelete args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
await client.Client!.DeleteContainerAsync(args).ConfigureAwait(false);
}
public async Task GetObjectHeadAsync(PrmObjectHeadGet args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetObjectHeadAsync(args).ConfigureAwait(false);
}
public async Task GetObjectAsync(PrmObjectGet args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetObjectAsync(args).ConfigureAwait(false);
}
public async Task PutObjectAsync(PrmObjectPut args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.PutObjectAsync(args).ConfigureAwait(false);
}
public async Task PutSingleObjectAsync(PrmSingleObjectPut args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.PutSingleObjectAsync(args).ConfigureAwait(false);
}
public async Task PatchObjectAsync(PrmObjectPatch args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.PatchObjectAsync(args).ConfigureAwait(false);
}
public async Task GetRangeAsync(PrmRangeGet args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetRangeAsync(args).ConfigureAwait(false);
}
public async Task[]> GetRangeHashAsync(PrmRangeHashGet args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetRangeHashAsync(args).ConfigureAwait(false);
}
public async Task PatchAsync(PrmObjectPatch args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.PatchObjectAsync(args).ConfigureAwait(false);
}
public async Task DeleteObjectAsync(PrmObjectDelete args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
await client.Client!.DeleteObjectAsync(args).ConfigureAwait(false);
}
public IAsyncEnumerable SearchObjectsAsync(PrmObjectSearch args)
{
- if (args is null)
- {
- throw new ArgumentNullException(nameof(args));
- }
-
var client = Connection();
-
- args.Context.PoolErrorHandler = client.HandleError;
-
return client.Client!.SearchObjectsAsync(args);
}
public async Task GetBalanceAsync(PrmBalance? args)
{
var client = Connection();
-
- args ??= new();
- args.Context.PoolErrorHandler = client.HandleError;
-
return await client.Client!.GetBalanceAsync(args).ConfigureAwait(false);
}
@@ -824,7 +662,7 @@ public partial class Pool : IFrostFSClient
GC.SuppressFinalize(this);
}
- public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, CallContext ctx)
+ public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header)
{
throw new NotImplementedException();
}
diff --git a/src/FrostFS.SDK.Client/Pool/SessionCache.cs b/src/FrostFS.SDK.Client/Pool/SessionCache.cs
index 829b1c9..fae3de1 100644
--- a/src/FrostFS.SDK.Client/Pool/SessionCache.cs
+++ b/src/FrostFS.SDK.Client/Pool/SessionCache.cs
@@ -1,23 +1,49 @@
using System;
-using System.Collections;
+using System.Collections.Concurrent;
namespace FrostFS.SDK.Client;
-internal struct SessionCache(ulong sessionExpirationDuration)
+internal sealed class SessionCache(ulong sessionExpirationDuration)
{
- internal Hashtable Cache { get; } = [];
+ private ConcurrentDictionary _cache { get; } = [];
internal ulong CurrentEpoch { get; set; }
internal ulong TokenDuration { get; set; } = sessionExpirationDuration;
+ internal bool Contains(string key)
+ {
+ return _cache.ContainsKey(key);
+ }
+
+ internal bool TryGetValue(string? key, out FrostFsSessionToken? value)
+ {
+ if (key == null)
+ {
+ value = null;
+ return false;
+ }
+
+ var ok = _cache.TryGetValue(key, out value);
+
+ return ok && value != null;
+ }
+
+ internal void SetValue(string? key, FrostFsSessionToken value)
+ {
+ if (key != null)
+ {
+ _cache[key] = value;
+ }
+ }
+
internal void DeleteByPrefix(string prefix)
{
- foreach (var key in Cache.Keys)
+ foreach (var key in _cache.Keys)
{
- if (((string)key).StartsWith(prefix, StringComparison.Ordinal))
+ if (key.StartsWith(prefix, StringComparison.Ordinal))
{
- Cache.Remove(key);
+ _cache.TryRemove(key, out var _);
}
}
}
diff --git a/src/FrostFS.SDK.Client/Pool/WrapperPrm.cs b/src/FrostFS.SDK.Client/Pool/WrapperPrm.cs
index 3c23505..b68b6ee 100644
--- a/src/FrostFS.SDK.Client/Pool/WrapperPrm.cs
+++ b/src/FrostFS.SDK.Client/Pool/WrapperPrm.cs
@@ -1,13 +1,14 @@
using System;
+using System.Collections.ObjectModel;
using System.Security.Cryptography;
+using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Logging;
namespace FrostFS.SDK.Client;
-// wrapperPrm is params to create clientWrapper.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Performance", "CA1815:Override equals and operator equals on value types", Justification = "")]
public struct WrapperPrm
{
@@ -15,7 +16,7 @@ public struct WrapperPrm
internal string Address { get; set; }
- internal ECDsa? Key { get; set; }
+ internal ECDsa Key { get; set; }
internal ulong DialTimeout { get; set; }
@@ -30,5 +31,9 @@ public struct WrapperPrm
internal GrpcChannelOptions GrpcChannelOptions { get; set; }
internal ulong GracefulCloseOnSwitchTimeout { get; set; }
+
+ internal Action? Callback { get; set; }
+
+ internal Collection? Interceptors { get; set; }
}
diff --git a/src/FrostFS.SDK.Client/Services/AccountingServiceProvider.cs b/src/FrostFS.SDK.Client/Services/AccountingServiceProvider.cs
index ba8ba2a..bdb8e61 100644
--- a/src/FrostFS.SDK.Client/Services/AccountingServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/AccountingServiceProvider.cs
@@ -24,12 +24,12 @@ internal sealed class AccountingServiceProvider : ContextAccessor
{
Body = new()
{
- OwnerId = ctx.OwnerId!.OwnerID
+ OwnerId = ClientContext.Owner.OwnerID
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key!);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await _accountingServiceClient!.BalanceAsync(request, null, ctx.Deadline, ctx.CancellationToken);
diff --git a/src/FrostFS.SDK.Client/Services/ApeManagerServiceProvider.cs b/src/FrostFS.SDK.Client/Services/ApeManagerServiceProvider.cs
index 840223d..1c22cdc 100644
--- a/src/FrostFS.SDK.Client/Services/ApeManagerServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/ApeManagerServiceProvider.cs
@@ -16,13 +16,9 @@ internal sealed class ApeManagerServiceProvider : ContextAccessor
_apeManagerServiceClient = apeManagerServiceClient;
}
- internal async Task AddChainAsync(PrmApeChainAdd args)
+ internal async Task> AddChainAsync(PrmApeChainAdd args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
AddChainRequest request = new()
{
@@ -34,22 +30,18 @@ internal sealed class ApeManagerServiceProvider : ContextAccessor
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await _apeManagerServiceClient!.AddChainAsync(request, null, ctx.Deadline, ctx.CancellationToken);
Verifier.CheckResponse(response);
- return response.Body.ChainId.ToByteArray();
+ return response.Body.ChainId.Memory;
}
internal async Task RemoveChainAsync(PrmApeChainRemove args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
RemoveChainRequest request = new()
{
@@ -61,7 +53,7 @@ internal sealed class ApeManagerServiceProvider : ContextAccessor
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await _apeManagerServiceClient!.RemoveChainAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -71,10 +63,6 @@ internal sealed class ApeManagerServiceProvider : ContextAccessor
internal async Task ListChainAsync(PrmApeChainList args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
ListChainsRequest request = new()
{
@@ -85,7 +73,7 @@ internal sealed class ApeManagerServiceProvider : ContextAccessor
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await _apeManagerServiceClient!.ListChainsAsync(request, null, ctx.Deadline, ctx.CancellationToken);
diff --git a/src/FrostFS.SDK.Client/Services/ContainerServiceProvider.cs b/src/FrostFS.SDK.Client/Services/ContainerServiceProvider.cs
index 3a0379e..fcdc0e5 100644
--- a/src/FrostFS.SDK.Client/Services/ContainerServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/ContainerServiceProvider.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
+using System.Security.Cryptography;
using System.Threading.Tasks;
using FrostFS.Container;
@@ -12,26 +13,34 @@ using FrostFS.Session;
namespace FrostFS.SDK.Client;
-internal sealed class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientContext clientCtx) : ContextAccessor(clientCtx), ISessionProvider
+internal sealed class ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientContext clientCtx) : ContextAccessor(clientCtx)
{
private SessionProvider? sessions;
- public async ValueTask GetOrCreateSession(ISessionToken args, CallContext ctx)
+ public async ValueTask GetDefaultSession(ISessionToken args, CallContext ctx)
{
sessions ??= new(ClientContext);
- if (ClientContext.SessionCache.Cache != null &&
- ClientContext.SessionCache.Cache.ContainsKey(ClientContext.SessionCacheKey))
+ if (!ClientContext.SessionCache!.TryGetValue(ClientContext.SessionCacheKey, out var token))
{
- return (SessionToken)ClientContext.SessionCache.Cache[ClientContext.SessionCacheKey];
+ var protoToken = await sessions.GetDefaultSession(args, ctx).ConfigureAwait(false);
+
+ token = new FrostFsSessionToken(protoToken);
+
+ ClientContext.SessionCache.SetValue(ClientContext.SessionCacheKey, token);
}
- return await sessions.GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ if (token == null)
+ {
+ throw new FrostFsException("Cannot create session");
+ }
+
+ return token;
}
internal async Task GetContainerAsync(PrmContainerGet args)
{
- GetRequest request = GetContainerRequest(args.Container.ContainerID, args.XHeaders, args.Context);
+ GetRequest request = GetContainerRequest(args.Container.ContainerID, args.XHeaders, ClientContext.Key.ECDsaKey);
var response = await service.GetAsync(request, null, args.Context.Deadline, args.Context.CancellationToken);
@@ -43,24 +52,17 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
internal async IAsyncEnumerable ListContainersAsync(PrmContainerGetAll args)
{
var ctx = args.Context!;
- ctx.OwnerId ??= ClientContext.Owner;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
- if (ctx.OwnerId == null)
- throw new ArgumentException(nameof(ctx.OwnerId));
var request = new ListRequest
{
Body = new()
{
- OwnerId = ctx.OwnerId.ToMessage()
+ OwnerId = ClientContext.Owner.OwnerID
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await service.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -68,7 +70,7 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
foreach (var cid in response.Body.ContainerIds)
{
- yield return new FrostFsContainerId(Base58.Encode(cid.Value.ToByteArray()));
+ yield return new FrostFsContainerId(Base58.Encode(cid.Value.Span));
}
}
@@ -78,36 +80,28 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
var grpcContainer = args.Container.GetContainer();
- grpcContainer.OwnerId ??= ctx.OwnerId?.ToMessage();
- grpcContainer.Version ??= ctx.Version?.ToMessage();
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
- if (grpcContainer.OwnerId == null)
- throw new ArgumentException(nameof(grpcContainer.OwnerId));
- if (grpcContainer.Version == null)
- throw new ArgumentException(nameof(grpcContainer.Version));
+ grpcContainer.OwnerId ??= ClientContext.Owner.OwnerID;
+ grpcContainer.Version ??= ClientContext.Version.VersionID;
var request = new PutRequest
{
Body = new PutRequest.Types.Body
{
Container = grpcContainer,
- Signature = ctx.Key.SignRFC6979(grpcContainer)
+ Signature = ClientContext.Key.ECDsaKey.SignRFC6979(grpcContainer)
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = (args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false)) ?? throw new FrostFsException("Cannot create session token");
- sessionToken.CreateContainerTokenContext(
+ var protoToken = sessionToken.CreateContainerToken(
null,
ContainerSessionContext.Types.Verb.Put,
- ctx.Key,
- ctx.GetPublicKeyCache()!);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await service.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -121,29 +115,26 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
internal async Task DeleteContainerAsync(PrmContainerDelete args)
{
var ctx = args.Context!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var request = new DeleteRequest
{
Body = new DeleteRequest.Types.Body
{
ContainerId = args.ContainerId.ToMessage(),
- Signature = ctx.Key.SignRFC6979(args.ContainerId.ToMessage().Value)
+ Signature = ClientContext.Key.ECDsaKey.SignRFC6979(args.ContainerId.ToMessage().Value)
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateContainerTokenContext(
+ var protoToken = sessionToken.CreateContainerToken(
request.Body.ContainerId,
ContainerSessionContext.Types.Verb.Delete,
- ctx.Key,
- ctx.GetPublicKeyCache()!);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await service.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -155,11 +146,8 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
Verifier.CheckResponse(response);
}
- private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, CallContext ctx)
+ private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, ECDsa key)
{
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(ctx), "Key is null");
-
var request = new GetRequest
{
Body = new GetRequest.Types.Body
@@ -169,7 +157,7 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
};
request.AddMetaHeader(xHeaders);
- request.Sign(ctx.Key);
+ request.Sign(key);
return request;
}
@@ -182,7 +170,7 @@ internal sealed class ContainerServiceProvider(ContainerService.ContainerService
private async Task WaitForContainer(WaitExpects expect, ContainerID id, PrmWait? waitParams, CallContext ctx)
{
- var request = GetContainerRequest(id, null, ctx);
+ var request = GetContainerRequest(id, null, ClientContext.Key.ECDsaKey);
async Task action()
{
diff --git a/src/FrostFS.SDK.Client/Services/NetmapServiceProvider.cs b/src/FrostFS.SDK.Client/Services/NetmapServiceProvider.cs
index 18649d8..570bd24 100644
--- a/src/FrostFS.SDK.Client/Services/NetmapServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/NetmapServiceProvider.cs
@@ -1,6 +1,4 @@
using System;
-using System.Linq;
-using System.Text;
using System.Threading.Tasks;
using FrostFS.Netmap;
@@ -47,10 +45,6 @@ internal sealed class NetmapServiceProvider : ContextAccessor
internal async Task GetLocalNodeInfoAsync(PrmNodeInfo args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var request = new LocalNodeInfoRequest
{
@@ -58,7 +52,7 @@ internal sealed class NetmapServiceProvider : ContextAccessor
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -69,15 +63,10 @@ internal sealed class NetmapServiceProvider : ContextAccessor
internal async Task GetNetworkInfoAsync(CallContext ctx)
{
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(ctx), "Key is null");
-
var request = new NetworkInfoRequest();
request.AddMetaHeader(null);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken)
.ConfigureAwait(false);
@@ -90,15 +79,11 @@ internal sealed class NetmapServiceProvider : ContextAccessor
internal async Task GetNetmapSnapshotAsync(PrmNetmapSnapshot args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var request = new NetmapSnapshotRequest();
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -107,12 +92,16 @@ internal sealed class NetmapServiceProvider : ContextAccessor
return response.ToModel();
}
- private static bool GetBoolValue(byte[] bytes)
+ private static bool GetBoolValue(ReadOnlySpan bytes)
{
- return bytes.Any(b => b != 0);
+ for (int i = bytes.Length - 1; i >= 0; i--)
+ if (bytes[i] != 0)
+ return true;
+
+ return false;
}
- private static ulong GetLongValue(byte[] bytes)
+ private static ulong GetLongValue(ReadOnlySpan bytes)
{
ulong val = 0;
for (var i = bytes.Length - 1; i >= 0; i--)
@@ -123,24 +112,50 @@ internal sealed class NetmapServiceProvider : ContextAccessor
private static void SetNetworksParam(Parameter param, NetworkSettings settings)
{
- var key = Encoding.UTF8.GetString(param.Key.ToByteArray());
+ var key = param.Key.ToStringUtf8();
- var valueBytes = param.Value.ToByteArray();
+ var valueBytes = param.Value.Span;
switch (key)
{
- case "AuditFee": settings.AuditFee = GetLongValue(valueBytes); break;
- case "BasicIncomeRate": settings.BasicIncomeRate = GetLongValue(valueBytes); break;
- case "ContainerFee": settings.ContainerFee = GetLongValue(valueBytes); break;
- case "ContainerAliasFee": settings.ContainerAliasFee = GetLongValue(valueBytes); break;
- case "EpochDuration": settings.EpochDuration = GetLongValue(valueBytes); break;
- case "InnerRingCandidateFee": settings.InnerRingCandidateFee = GetLongValue(valueBytes); break;
- case "MaxECDataCount": settings.MaxECDataCount = GetLongValue(valueBytes); break;
- case "MaxECParityCount": settings.MaxECParityCount = GetLongValue(valueBytes); break;
- case "MaxObjectSize": settings.MaxObjectSize = GetLongValue(valueBytes); break;
- case "WithdrawFee": settings.WithdrawFee = GetLongValue(valueBytes); break;
- case "HomomorphicHashingDisabled": settings.HomomorphicHashingDisabled = GetBoolValue(valueBytes); break;
- case "MaintenanceModeAllowed": settings.MaintenanceModeAllowed = GetBoolValue(valueBytes); break;
- default: settings.UnnamedSettings.Add(key, valueBytes); break;
+ case "AuditFee":
+ settings.AuditFee = GetLongValue(valueBytes);
+ break;
+ case "BasicIncomeRate":
+ settings.BasicIncomeRate = GetLongValue(valueBytes);
+ break;
+ case "ContainerFee":
+ settings.ContainerFee = GetLongValue(valueBytes);
+ break;
+ case "ContainerAliasFee":
+ settings.ContainerAliasFee = GetLongValue(valueBytes);
+ break;
+ case "EpochDuration":
+ settings.EpochDuration = GetLongValue(valueBytes);
+ break;
+ case "InnerRingCandidateFee":
+ settings.InnerRingCandidateFee = GetLongValue(valueBytes);
+ break;
+ case "MaxECDataCount":
+ settings.MaxECDataCount = GetLongValue(valueBytes);
+ break;
+ case "MaxECParityCount":
+ settings.MaxECParityCount = GetLongValue(valueBytes);
+ break;
+ case "MaxObjectSize":
+ settings.MaxObjectSize = GetLongValue(valueBytes);
+ break;
+ case "WithdrawFee":
+ settings.WithdrawFee = GetLongValue(valueBytes);
+ break;
+ case "HomomorphicHashingDisabled":
+ settings.HomomorphicHashingDisabled = GetBoolValue(valueBytes);
+ break;
+ case "MaintenanceModeAllowed":
+ settings.MaintenanceModeAllowed = GetBoolValue(valueBytes);
+ break;
+ default:
+ settings.UnnamedSettings.Add(key, valueBytes.ToArray());
+ break;
}
}
}
diff --git a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs
index 7737c62..d3c4347 100644
--- a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs
@@ -17,31 +17,35 @@ using Google.Protobuf;
namespace FrostFS.SDK.Client;
internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient client, ClientContext clientCtx)
- : ContextAccessor(clientCtx), ISessionProvider
+ : ContextAccessor(clientCtx)
{
private SessionProvider? sessions;
private readonly ObjectService.ObjectServiceClient client = client;
- public async ValueTask GetOrCreateSession(ISessionToken args, CallContext ctx)
+ public async ValueTask GetDefaultSession(ISessionToken args, CallContext ctx)
{
sessions ??= new(ClientContext);
- if (ClientContext.SessionCache.Cache != null &&
- ClientContext.SessionCache.Cache.ContainsKey(ClientContext.SessionCacheKey))
+ if (!ClientContext.SessionCache!.TryGetValue(ClientContext.SessionCacheKey, out var token))
{
- return (SessionToken)ClientContext.SessionCache.Cache[ClientContext.SessionCacheKey];
+ var protoToken = await sessions.GetDefaultSession(args, ctx).ConfigureAwait(false);
+
+ token = new FrostFsSessionToken(protoToken);
+
+ ClientContext.SessionCache.SetValue(ClientContext.SessionCacheKey, token);
}
- return await sessions.GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ if (token == null)
+ {
+ throw new FrostFsException("Cannot create session");
+ }
+
+ return token;
}
internal async Task GetObjectHeadAsync(PrmObjectHeadGet args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var request = new HeadRequest
{
@@ -55,16 +59,16 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Head,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await client!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken).ConfigureAwait(false);
@@ -77,11 +81,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
var request = new GetRequest
{
Body = new GetRequest.Types.Body
@@ -94,16 +93,16 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Get,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
return await GetObject(request, ctx).ConfigureAwait(false);
}
@@ -112,11 +111,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
var request = new GetRangeRequest
{
Body = new GetRangeRequest.Types.Body
@@ -135,16 +129,16 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Range,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var call = client.GetRange(request, null, ctx.Deadline, ctx.CancellationToken);
return new RangeReader(call);
@@ -154,11 +148,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
var request = new GetRangeHashRequest
{
Body = new GetRangeHashRequest.Types.Body
@@ -182,16 +171,16 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
});
}
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Rangehash,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await client.GetRangeHashAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -206,10 +195,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
internal async Task DeleteObjectAsync(PrmObjectDelete args)
{
var ctx = args.Context!;
- ctx.Key ??= ClientContext.Key?.ECDsaKey;
-
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var request = new DeleteRequest
{
@@ -223,15 +208,15 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Delete,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(ctx.Key);
+ request.AddMetaHeader(args.XHeaders, protoToken);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await client.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -242,9 +227,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
var request = new SearchRequest
{
Body = new SearchRequest.Types.Body
@@ -256,22 +238,30 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
request.Body.Filters.AddRange(args.Filters.Select(f => f.ToMessage()));
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
new Address { ContainerId = request.Body.ContainerId },
ObjectSessionContext.Types.Verb.Search,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
- var objectsIds = SearchObjects(request, ctx);
+ using var stream = GetSearchReader(request, ctx);
- await foreach (var oid in objectsIds)
+ while (true)
{
- yield return FrostFsObjectId.FromHash(oid.Value.ToByteArray());
+ var ids = await stream.Read(ctx.CancellationToken).ConfigureAwait(false);
+
+ if (ids == null)
+ yield break;
+
+ foreach (var oid in ids)
+ {
+ yield return FrostFsObjectId.FromHash(oid.Value.Span);
+ }
}
}
@@ -296,6 +286,8 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
args.FullLength = args.Header.PayloadLength;
else if (args.Payload.CanSeek)
args.FullLength = (ulong)args.Payload.Length;
+ else
+ throw new ArgumentException("The stream does not have a length and payload length is not defined");
var response = await PutStreamObject(args).ConfigureAwait(false);
@@ -307,39 +299,34 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
- var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
+ var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ClientContext);
var request = new PutSingleRequest
{
Body = new() { Object = grpcObject }
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId },
ObjectSessionContext.Types.Verb.Put,
- ctx.Key);
+ ClientContext.Key);
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
var response = await client.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken).ConfigureAwait(false);
Verifier.CheckResponse(response);
- return FrostFsObjectId.FromHash(grpcObject.ObjectId.Value.ToByteArray());
+ return FrostFsObjectId.FromHash(grpcObject.ObjectId.Value.Span);
}
internal async Task PatchObjectAsync(PrmObjectPatch args)
{
var ctx = args.Context!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var chunkSize = args.MaxPayloadPatchChunkLength;
Stream payload = args.Payload ?? throw new ArgumentNullException(nameof(args), "Stream parameter is null");
@@ -350,7 +337,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
try
{
// common
- chunkBuffer = ClientContext.GetArrayPool(Constants.ObjectChunkSize).Rent(chunkSize);
+ chunkBuffer = ArrayPool.Shared.Rent(chunkSize);
var address = new Address
{
@@ -358,13 +345,12 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
ContainerId = args.Address.ContainerId
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false);
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
address,
ObjectSessionContext.Types.Verb.Patch,
- ctx.Key
- );
+ ClientContext.Key);
var request = new PatchRequest()
{
@@ -403,9 +389,9 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
currentPos += (ulong)bytesCount;
- request.AddMetaHeader(args.XHeaders, sessionToken);
+ request.AddMetaHeader(args.XHeaders, protoToken);
- request.Sign(ctx.Key);
+ request.Sign(ClientContext.Key.ECDsaKey);
await call.RequestStream.WriteAsync(request).ConfigureAwait(false);
@@ -433,20 +419,17 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var ctx = args.Context!;
- var tokenRaw = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
- var token = new FrostFsSessionToken(tokenRaw.Serialize(), tokenRaw.Body.Id.ToUuid());
-
- args.SessionToken = token;
+ args.SessionToken ??= await GetDefaultSession(args, ctx).ConfigureAwait(false);
var payloadStream = args.Payload!;
var header = args.Header!;
- var fullLength = header.PayloadLength;
-
- if (payloadStream.CanSeek && fullLength == 0)
- fullLength = (ulong)payloadStream.Length;
-
- args.FullLength = fullLength;
+ if (header.PayloadLength > 0)
+ args.FullLength = header.PayloadLength;
+ else if (payloadStream.CanSeek)
+ args.FullLength = (ulong)payloadStream.Length;
+ else
+ throw new ArgumentException("The stream does not have a length and payload length is not defined");
if (args.MaxObjectSizeCache == 0)
{
@@ -456,12 +439,12 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
args.MaxObjectSizeCache = (int)networkSettings.MaxObjectSize;
}
- var restBytes = fullLength - args.CurrentStreamPosition;
+ var restBytes = args.FullLength - args.CurrentStreamPosition;
var objectSize = restBytes > 0 ? (int)Math.Min((ulong)args.MaxObjectSizeCache, restBytes) : args.MaxObjectSizeCache;
//define collection capacity
var restPart = (restBytes % (ulong)objectSize) > 0 ? 1 : 0;
- var objectsCount = fullLength > 0 ? (int)(restBytes / (ulong)objectSize) + restPart : 0;
+ var objectsCount = args.FullLength > 0 ? (int)(restBytes / (ulong)objectSize) + restPart : 0;
List sentObjectIds = new(objectsCount);
@@ -491,7 +474,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var largeObjectHeader = new FrostFsObjectHeader(header.ContainerId, FrostFsObjectType.Regular, [.. attributes])
{
- PayloadLength = fullLength,
+ PayloadLength = args.FullLength,
};
args.Header.Split!.ParentHeader = largeObjectHeader;
@@ -526,8 +509,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
private async Task PutStreamObject(PrmObjectPut args)
{
var ctx = args.Context!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
var payload = args.Payload!;
@@ -542,21 +523,26 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
try
{
+ // 0 means no limit from client, so server side cut is performed
+ var objectLimitSize = args.ClientCut ? args.MaxObjectSizeCache : 0;
+
if (args.CustomBuffer != null)
{
+ if (args.CustomBuffer.Length < chunkSize)
+ {
+ throw new ArgumentException($"Buffer size is too small. At least {chunkSize} required");
+ }
+
chunkBuffer = args.CustomBuffer;
}
else
{
- chunkBuffer = ClientContext.GetArrayPool(Constants.ObjectChunkSize).Rent(chunkSize);
+ chunkBuffer = ArrayPool.Shared.Rent(chunkSize);
isRentBuffer = true;
}
var sentBytes = 0;
- // 0 means no limit from client, so server side cut is performed
- var objectLimitSize = args.ClientCut ? args.MaxObjectSizeCache : 0;
-
using var stream = await GetUploadStream(args, ctx).ConfigureAwait(false);
while (objectLimitSize == 0 || sentBytes < objectLimitSize)
@@ -581,7 +567,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- chunkRequest.Sign(ctx.Key);
+ chunkRequest.Sign(ClientContext.Key.ECDsaKey);
await stream.Write(chunkRequest).ConfigureAwait(false);
}
@@ -589,7 +575,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
var response = await stream.Close().ConfigureAwait(false);
Verifier.CheckResponse(response);
- return new PutObjectResult(FrostFsObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray()), sentBytes);
+ return new PutObjectResult(FrostFsObjectId.FromHash(response.Body.ObjectId.Value.Span), sentBytes);
}
finally
{
@@ -604,17 +590,14 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
{
var header = args.Header!;
- if (ctx.Key == null)
- throw new ArgumentNullException(nameof(args), "Key is null");
-
- header.OwnerId ??= ctx.OwnerId;
- header.Version ??= ctx.Version;
+ header.OwnerId ??= ClientContext.Owner;
+ header.Version ??= ClientContext.Version;
var grpcHeader = header.GetHeader();
if (header.Split != null)
{
- ObjectTools.SetSplitValues(grpcHeader, header.Split, ctx);
+ ObjectTools.SetSplitValues(grpcHeader, header.Split, ClientContext);
}
var oid = new ObjectID { Value = grpcHeader.Sha256() };
@@ -630,17 +613,16 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
}
};
- var sessionToken = await GetOrCreateSession(args, ctx).ConfigureAwait(false);
+ var sessionToken = (args.SessionToken ?? await GetDefaultSession(args, ctx).ConfigureAwait(false));
- sessionToken.CreateObjectTokenContext(
+ var protoToken = sessionToken.CreateObjectTokenContext(
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
ObjectSessionContext.Types.Verb.Put,
- ctx.Key
- );
+ ClientContext.Key);
- initRequest.AddMetaHeader(args.XHeaders, sessionToken);
+ initRequest.AddMetaHeader(args.XHeaders, protoToken);
- initRequest.Sign(ctx.Key);
+ initRequest.Sign(ClientContext.Key.ECDsaKey);
return await PutObjectInit(initRequest, ctx).ConfigureAwait(false);
}
@@ -681,24 +663,6 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl
return new ObjectReader(call);
}
- private async IAsyncEnumerable SearchObjects(SearchRequest request, CallContext ctx)
- {
- using var stream = GetSearchReader(request, ctx);
-
- while (true)
- {
- var ids = await stream.Read(ctx.CancellationToken).ConfigureAwait(false);
-
- if (ids == null)
- break;
-
- foreach (var oid in ids)
- {
- yield return oid;
- }
- }
- }
-
private SearchReader GetSearchReader(SearchRequest initRequest, CallContext ctx)
{
if (initRequest is null)
diff --git a/src/FrostFS.SDK.Client/Services/SessionServiceProvider.cs b/src/FrostFS.SDK.Client/Services/SessionServiceProvider.cs
index e9b5963..859d836 100644
--- a/src/FrostFS.SDK.Client/Services/SessionServiceProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/SessionServiceProvider.cs
@@ -1,7 +1,5 @@
using System.Threading.Tasks;
-using FrostFS.SDK.Client;
-using FrostFS.SDK.Client.Mappers.GRPC;
using FrostFS.Session;
namespace FrostFS.SDK.Client;
@@ -20,19 +18,17 @@ internal sealed class SessionServiceProvider : ContextAccessor
{
var ctx = args.Context!;
- ctx.OwnerId ??= ClientContext.Owner;
-
var request = new CreateRequest
{
Body = new CreateRequest.Types.Body
{
- OwnerId = ctx.OwnerId!.ToMessage(),
+ OwnerId = ClientContext.Owner.OwnerID,
Expiration = args.Expiration
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(ctx.Key!);
+ request.Sign(ClientContext.Key.ECDsaKey);
return await CreateSession(request, args.Context!).ConfigureAwait(false);
}
diff --git a/src/FrostFS.SDK.Client/Services/Shared/SessionProvider.cs b/src/FrostFS.SDK.Client/Services/Shared/SessionProvider.cs
index a8d80ac..e8ff793 100644
--- a/src/FrostFS.SDK.Client/Services/Shared/SessionProvider.cs
+++ b/src/FrostFS.SDK.Client/Services/Shared/SessionProvider.cs
@@ -9,14 +9,15 @@ internal interface ISessionProvider
internal sealed class SessionProvider(ClientContext envCtx)
{
- public async ValueTask GetOrCreateSession(ISessionToken args, CallContext ctx)
+ public async Task CreateSession(ISessionToken args, CallContext ctx)
{
- if (args.SessionToken is null)
- {
- return await envCtx.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue, ctx))
- .ConfigureAwait(false);
- }
+ var token = await GetDefaultSession(args, ctx).ConfigureAwait(false);
- return new Session.SessionToken().Deserialize(args.SessionToken.Token);
+ return new FrostFsSessionToken(token);
+ }
+
+ internal async Task GetDefaultSession(ISessionToken args, CallContext ctx)
+ {
+ return await envCtx.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue, ctx)).ConfigureAwait(false);
}
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Client/Tools/ClientContext.cs b/src/FrostFS.SDK.Client/Tools/ClientContext.cs
index 5f7c72e..133ad3f 100644
--- a/src/FrostFS.SDK.Client/Tools/ClientContext.cs
+++ b/src/FrostFS.SDK.Client/Tools/ClientContext.cs
@@ -1,19 +1,16 @@
using System;
-using System.Buffers;
-using System.Security.Cryptography;
-
-using FrostFS.SDK.Cryptography;
+using System.Collections.ObjectModel;
+using Grpc.Core.Interceptors;
using Grpc.Net.Client;
namespace FrostFS.SDK.Client;
-public class ClientContext(FrostFSClient client, ECDsa? key, FrostFsOwner? owner, GrpcChannel channel, FrostFsVersion version) : IDisposable
+public class ClientContext(FrostFSClient client, ClientKey key, FrostFsOwner owner, GrpcChannel channel, FrostFsVersion version) : IDisposable
{
- private ArrayPool? _arrayPool;
private string? sessionKey;
- internal FrostFsOwner? Owner { get; } = owner;
+ internal FrostFsOwner Owner { get; } = owner;
internal string? Address { get; } = channel.Target;
@@ -25,9 +22,16 @@ public class ClientContext(FrostFSClient client, ECDsa? key, FrostFsOwner? owner
internal FrostFSClient Client { get; } = client;
- internal ClientKey? Key { get; } = key != null ? new ClientKey(key) : null;
+ internal ClientKey Key { get; } = key;
+
+ internal SessionCache? SessionCache { get; set; }
+
+ internal Action? Callback { get; set; }
+
+ internal Collection? Interceptors { get; set; }
+
+ internal Action? PoolErrorHandler { get; set; }
- internal SessionCache SessionCache { get; set; }
internal string? SessionCacheKey
{
@@ -35,23 +39,13 @@ public class ClientContext(FrostFSClient client, ECDsa? key, FrostFsOwner? owner
{
if (sessionKey == null && Key != null && Address != null)
{
- sessionKey = Pool.FormCacheKey(Address, Key.ECDsaKey.PrivateKey().ToString());
+ sessionKey = Pool.FormCacheKey(Address, Key.PublicKey);
}
return sessionKey;
}
}
- ///
- /// Custom pool is used for predefined sizes of buffers like grpc chunk
- ///
- internal ArrayPool GetArrayPool(int size)
- {
- _arrayPool ??= ArrayPool.Create(size, 256);
-
- return _arrayPool;
- }
-
public void Dispose()
{
Dispose(true);
diff --git a/src/FrostFS.SDK.Client/Tools/ObjectTools.cs b/src/FrostFS.SDK.Client/Tools/ObjectTools.cs
index f20cacd..eeb06c0 100644
--- a/src/FrostFS.SDK.Client/Tools/ObjectTools.cs
+++ b/src/FrostFS.SDK.Client/Tools/ObjectTools.cs
@@ -11,7 +11,7 @@ namespace FrostFS.SDK.Client;
internal static class ObjectTools
{
- internal static FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, CallContext ctx)
+ internal static FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, ClientContext ctx)
{
var grpcHeader = CreateHeader(header, [], ctx);
@@ -21,9 +21,9 @@ internal static class ObjectTools
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
}
- internal static Object.Object CreateObject(FrostFsObject @object, CallContext ctx)
+ internal static Object.Object CreateObject(FrostFsObject @object, ClientContext ctx)
{
- @object.Header.OwnerId ??= ctx.OwnerId;
+ @object.Header.OwnerId ??= ctx.Owner;
@object.Header.Version ??= ctx.Version;
var grpcHeader = @object.Header.GetHeader();
@@ -46,14 +46,14 @@ internal static class ObjectTools
obj.Signature = new Signature
{
- Key = ctx.GetPublicKeyCache(),
- Sign = ByteString.CopyFrom(ctx.Key!.SignData(obj.ObjectId.ToByteArray())),
+ Key = ctx.Key.PublicKeyProto,
+ Sign = ctx.Key.ECDsaKey.SignData(obj.ObjectId.ToByteArray()),
};
return obj;
}
- internal static void SetSplitValues(Header grpcHeader, FrostFsSplit split, CallContext ctx)
+ internal static void SetSplitValues(Header grpcHeader, FrostFsSplit split, ClientContext ctx)
{
if (split == null)
return;
@@ -77,17 +77,17 @@ internal static class ObjectTools
grpcHeader.Split.ParentHeader = grpcParentHeader;
grpcHeader.Split.ParentSignature = new Signature
{
- Key = ctx.GetPublicKeyCache(),
- Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
+ Key = ctx.Key.PublicKeyProto,
+ Sign = ctx.Key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray()),
};
}
grpcHeader.Split.Previous = split.Previous?.ToMessage();
}
- internal static Header CreateHeader(FrostFsObjectHeader header, byte[]? payload, CallContext ctx)
+ internal static Header CreateHeader(FrostFsObjectHeader header, byte[]? payload, ClientContext ctx)
{
- header.OwnerId ??= ctx.OwnerId;
+ header.OwnerId ??= ctx.Owner;
header.Version ??= ctx.Version;
var grpcHeader = header.GetHeader();
diff --git a/src/FrostFS.SDK.Client/Tools/RequestConstructor.cs b/src/FrostFS.SDK.Client/Tools/RequestConstructor.cs
index 65d9e35..64aecc6 100644
--- a/src/FrostFS.SDK.Client/Tools/RequestConstructor.cs
+++ b/src/FrostFS.SDK.Client/Tools/RequestConstructor.cs
@@ -1,11 +1,8 @@
using System;
using System.Collections.Specialized;
using System.Linq;
-using System.Security.Cryptography;
-using FrostFS.Refs;
using FrostFS.SDK.Client.Mappers.GRPC;
-using FrostFS.SDK.Cryptography;
using FrostFS.SDK.Proto.Interfaces;
using FrostFS.Session;
@@ -33,59 +30,4 @@ public static class RequestConstructor
xHeaders.Cast().SelectMany(key => xHeaders.GetValues(key),
(k, v) => new XHeader { Key = k, Value = v }));
}
-
- public static void CreateObjectTokenContext(this SessionToken sessionToken,
- Address address,
- ObjectSessionContext.Types.Verb verb,
- ECDsa key)
- {
- if (sessionToken is null)
- {
- throw new ArgumentNullException(nameof(sessionToken));
- }
-
- if (address is null)
- {
- throw new ArgumentNullException(nameof(address));
- }
-
- if (sessionToken.Body.Object?.Target != null)
- return;
-
- ObjectSessionContext.Types.Target target = new() { Container = address.ContainerId };
-
- if (address.ObjectId != null)
- target.Objects.Add(address.ObjectId);
-
- sessionToken.Body.Object = new()
- {
- Target = target,
- Verb = verb
- };
-
- sessionToken.Body.SessionKey = Google.Protobuf.ByteString.CopyFrom(key.PublicKey());
-
- sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
- }
-
- internal static void CreateContainerTokenContext(this SessionToken sessionToken,
- ContainerID? containerId,
- ContainerSessionContext.Types.Verb verb,
- ECDsa key,
- Google.Protobuf.ByteString publicKey)
- {
- 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.Body.SessionKey = publicKey;
-
- sessionToken.Signature = key.SignMessagePart(sessionToken.Body);
- }
}
diff --git a/src/FrostFS.SDK.Client/Tools/RequestSigner.cs b/src/FrostFS.SDK.Client/Tools/RequestSigner.cs
index a45c569..f747b3f 100644
--- a/src/FrostFS.SDK.Client/Tools/RequestSigner.cs
+++ b/src/FrostFS.SDK.Client/Tools/RequestSigner.cs
@@ -14,24 +14,21 @@ using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
+using Signature = FrostFS.Refs.Signature;
+
namespace FrostFS.SDK.Client;
public static class RequestSigner
{
internal const int RFC6979SignatureSize = 64;
- internal static byte[] SignRFC6979(this ECDsa key, byte[] data)
+ internal static ByteString SignRFC6979(this ECDsa key, byte[] data)
{
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
- if (data is null)
- {
- throw new ArgumentNullException(nameof(data));
- }
-
var digest = new Sha256Digest();
var secp256R1 = SecNamedCurves.GetByName("secp256r1");
var ecParameters = new ECDomainParameters(secp256R1.Curve, secp256R1.G, secp256R1.N);
@@ -44,24 +41,27 @@ public static class RequestSigner
signer.Init(true, privateKey);
var rs = signer.GenerateSignature(hash);
- var signature = new byte[RFC6979SignatureSize];
+
+ Span signature = stackalloc byte[RFC6979SignatureSize];
+
var rbytes = rs[0].ToByteArrayUnsigned();
var sbytes = rs[1].ToByteArrayUnsigned();
var index = RFC6979SignatureSize / 2 - rbytes.Length;
- rbytes.CopyTo(signature, index);
+ rbytes.AsSpan().CopyTo(signature[index..]);
index = RFC6979SignatureSize - sbytes.Length;
- sbytes.CopyTo(signature, index);
+ sbytes.AsSpan().CopyTo(signature[index..]);
- return signature;
+ return ByteString.CopyFrom(signature);
}
+
internal static SignatureRFC6979 SignRFC6979(this ECDsa key, IMessage message)
{
return new SignatureRFC6979
{
Key = ByteString.CopyFrom(key.PublicKey()),
- Sign = ByteString.CopyFrom(key.SignRFC6979(message.ToByteArray())),
+ Sign = key.SignRFC6979(message.ToByteArray()),
};
}
@@ -70,23 +70,26 @@ public static class RequestSigner
return new SignatureRFC6979
{
Key = ByteString.CopyFrom(key.PublicKey()),
- Sign = ByteString.CopyFrom(key.SignRFC6979(data.ToByteArray())),
+ Sign = key.SignRFC6979(data.ToByteArray()),
};
}
- public static byte[] SignData(this ECDsa key, byte[] data)
+ public static ByteString SignData(this ECDsa key, byte[] data)
{
if (key is null)
{
throw new ArgumentNullException(nameof(key));
}
- var hash = new byte[65];
- hash[0] = 0x04;
+ Span result = stackalloc byte[65];
+ result[0] = 0x04;
- key.SignHash(data.Sha512()).CopyTo(hash, 1);
+ //var hash = new byte[65];
+ //hash[0] = 0x04;
- return hash;
+ key.SignHash(data.Sha512()).AsSpan().CopyTo(result[1..]);
+
+ return ByteString.CopyFrom(result);
}
internal static Signature SignMessagePart(this ECDsa key, IMessage? data)
@@ -95,7 +98,7 @@ public static class RequestSigner
var sig = new Signature
{
Key = ByteString.CopyFrom(key.PublicKey()),
- Sign = ByteString.CopyFrom(key.SignData(data2Sign)),
+ Sign = key.SignData(data2Sign),
};
return sig;
diff --git a/src/FrostFS.SDK.Client/Tools/SearchReader.cs b/src/FrostFS.SDK.Client/Tools/SearchReader.cs
index c2e7607..ba9b1d1 100644
--- a/src/FrostFS.SDK.Client/Tools/SearchReader.cs
+++ b/src/FrostFS.SDK.Client/Tools/SearchReader.cs
@@ -1,21 +1,21 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FrostFS.Object;
using FrostFS.Refs;
+using Google.Protobuf.Collections;
+
using Grpc.Core;
namespace FrostFS.SDK.Client;
internal sealed class SearchReader(AsyncServerStreamingCall call) : IDisposable
{
- public AsyncServerStreamingCall Call { get; private set; } = call;
+ internal AsyncServerStreamingCall Call { get; private set; } = call;
- public async Task?> Read(CancellationToken cancellationToken)
+ internal async Task?> Read(CancellationToken cancellationToken)
{
if (!await Call.ResponseStream.MoveNext(cancellationToken).ConfigureAwait(false))
return null;
@@ -24,7 +24,7 @@ internal sealed class SearchReader(AsyncServerStreamingCall call
Verifier.CheckResponse(response);
- return response.Body?.IdList.ToList();
+ return response.Body?.IdList;
}
public void Dispose()
diff --git a/src/FrostFS.SDK.Client/Tools/Verifier.cs b/src/FrostFS.SDK.Client/Tools/Verifier.cs
index bc8dd31..ce215ba 100644
--- a/src/FrostFS.SDK.Client/Tools/Verifier.cs
+++ b/src/FrostFS.SDK.Client/Tools/Verifier.cs
@@ -88,6 +88,7 @@ public static class Verifier
return key.VerifyData(data2Verify, sig.Sign.ToByteArray());
}
+
internal static bool VerifyMatryoskaLevel(IMessage body, IMetaHeader meta, IVerificationHeader verification)
{
if (!verification.MetaSignature.VerifyMessagePart(meta))
diff --git a/src/FrostFS.SDK.Cryptography/FrostFS.SDK.Cryptography.csproj b/src/FrostFS.SDK.Cryptography/FrostFS.SDK.Cryptography.csproj
index 148ae78..604fe7c 100644
--- a/src/FrostFS.SDK.Cryptography/FrostFS.SDK.Cryptography.csproj
+++ b/src/FrostFS.SDK.Cryptography/FrostFS.SDK.Cryptography.csproj
@@ -7,12 +7,12 @@
- true
+ true
-
+
- true
-
+ true
+
diff --git a/src/FrostFS.SDK.Cryptography/UUID.cs b/src/FrostFS.SDK.Cryptography/UUID.cs
index c92a874..94fba3f 100644
--- a/src/FrostFS.SDK.Cryptography/UUID.cs
+++ b/src/FrostFS.SDK.Cryptography/UUID.cs
@@ -11,9 +11,7 @@ public static class UUIDExtension
if (id == null)
throw new ArgumentNullException(nameof(id));
- var bytes = id.ToByteArray();
-
- var orderedBytes = GetGuidBytesDirectOrder(bytes);
+ var orderedBytes = GetGuidBytesDirectOrder(id.Span);
return new Guid(orderedBytes);
}
@@ -32,7 +30,7 @@ public static class UUIDExtension
return orderedBytes;
}
- private static byte[] GetGuidBytesDirectOrder(byte[] source)
+ private static byte[] GetGuidBytesDirectOrder(ReadOnlySpan source)
{
if (source.Length != 16)
throw new ArgumentException("Wrong uuid binary format");
diff --git a/src/FrostFS.SDK.Protos/FrostFS.SDK.Protos.csproj b/src/FrostFS.SDK.Protos/FrostFS.SDK.Protos.csproj
index 0bf48d5..8f69fe0 100644
--- a/src/FrostFS.SDK.Protos/FrostFS.SDK.Protos.csproj
+++ b/src/FrostFS.SDK.Protos/FrostFS.SDK.Protos.csproj
@@ -7,11 +7,11 @@
- true
+ true
-
+
- true
+ true
diff --git a/src/FrostFS.SDK.Tests/ContainerTestsBase.cs b/src/FrostFS.SDK.Tests/ContainerTestsBase.cs
index 55f548d..3a0d396 100644
--- a/src/FrostFS.SDK.Tests/ContainerTestsBase.cs
+++ b/src/FrostFS.SDK.Tests/ContainerTestsBase.cs
@@ -8,12 +8,12 @@ public abstract class ContainerTestsBase
{
internal readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- protected IOptions Settings { get; set; }
+ protected IOptions Settings { get; set; }
protected ContainerMocker Mocker { get; set; }
protected ContainerTestsBase()
{
- Settings = Options.Create(new SingleOwnerClientSettings
+ Settings = Options.Create(new ClientSettings
{
Key = key,
Host = "http://localhost:8080"
diff --git a/src/FrostFS.SDK.Tests/FrostFS.SDK.Tests.csproj b/src/FrostFS.SDK.Tests/FrostFS.SDK.Tests.csproj
index d5cb78f..30c0564 100644
--- a/src/FrostFS.SDK.Tests/FrostFS.SDK.Tests.csproj
+++ b/src/FrostFS.SDK.Tests/FrostFS.SDK.Tests.csproj
@@ -1,4 +1,4 @@
-
+
net8.0
@@ -10,15 +10,15 @@
- true
+ true
-
+
- true
+ true
-
+
-
+
@@ -38,7 +38,7 @@
-
+
PreserveNewest
diff --git a/src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs b/src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs
index d1366c7..bd9d858 100644
--- a/src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs
+++ b/src/FrostFS.SDK.Tests/Mocks/AsyncStreamRangeReaderMock.cs
@@ -1,9 +1,4 @@
-using System.Security.Cryptography;
-
using FrostFS.Object;
-using FrostFS.SDK.Client;
-using FrostFS.SDK.Client.Mappers.GRPC;
-using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Google.Protobuf;
diff --git a/src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs b/src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs
index c09df83..9e9a18d 100644
--- a/src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs
+++ b/src/FrostFS.SDK.Tests/Mocks/AsyncStreamReaderMock.cs
@@ -43,7 +43,7 @@ public class AsyncStreamReaderMock(string key, FrostFsObjectHeader objectHeader)
Signature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
- Sign = ByteString.CopyFrom(Key.SignData(header.ToByteArray())),
+ Sign = Key.SignData(header.ToByteArray()),
}
}
},
diff --git a/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs b/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs
index ca1c670..8d4230c 100644
--- a/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs
+++ b/src/FrostFS.SDK.Tests/Mocks/ContainerServiceMocks/ContainerServiceBase.cs
@@ -46,19 +46,19 @@ public abstract class ServiceBase(string key)
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
- Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
+ Sign = Key.SignData(response.MetaHeader.ToByteArray())
},
BodySignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
- Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
+ Sign = Key.SignData(response.GetBody().ToByteArray())
},
OriginSignature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
- Sign = ByteString.CopyFrom(Key.SignData([]))
+ Sign = Key.SignData([])
}
};
diff --git a/src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs b/src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs
index 4b2b5c1..4f07e41 100644
--- a/src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs
+++ b/src/FrostFS.SDK.Tests/Mocks/ObjectMock.cs
@@ -5,7 +5,6 @@ using FrostFS.Object;
using FrostFS.SDK.Client;
using FrostFS.SDK.Client.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
-using FrostFS.Session;
using Google.Protobuf;
@@ -41,7 +40,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
public GetRangeHashRequest? GetRangeHashRequest { get; set; }
- public Collection RangeHashResponses { get; } = [];
+ public Collection RangeHashResponses { get; } = [];
public override Mock GetMock()
{
@@ -94,7 +93,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
headResponse.Body.Header.Signature = new Refs.Signature
{
Key = ByteString.CopyFrom(Key.PublicKey()),
- Sign = ByteString.CopyFrom(Key.SignData(headResponse.Body.Header.ToByteArray())),
+ Sign = Key.SignData(headResponse.Body.Header.ToByteArray()),
};
headResponse.VerifyHeader = GetResponseVerificationHeader(headResponse);
@@ -259,7 +258,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
response.Body.HashList.Add(hash);
}
}
-
+
response.VerifyHeader = GetResponseVerificationHeader(response);
return new AsyncUnaryCall(
@@ -281,7 +280,7 @@ public class ObjectMocker(string key) : ObjectServiceBase(key)
{
Body = new PatchResponse.Types.Body
{
- ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom(SHA256.HashData([1,2,3])) },
+ ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom(SHA256.HashData([1, 2, 3])) },
},
MetaHeader = ResponseMetaHeader
};
diff --git a/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs b/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs
index 88ed60d..ebea821 100644
--- a/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs
+++ b/src/FrostFS.SDK.Tests/Mocks/SessionMock.cs
@@ -31,7 +31,7 @@ public class SessionMocker(string key) : ServiceBase(key)
if (SessionKey == null)
{
- SessionKey = new byte[32];
+ SessionKey = new byte[33];
rand.NextBytes(SessionKey);
}
diff --git a/src/FrostFS.SDK.Tests/NetworkTest.cs b/src/FrostFS.SDK.Tests/NetworkTest.cs
index 2123460..9e83bb0 100644
--- a/src/FrostFS.SDK.Tests/NetworkTest.cs
+++ b/src/FrostFS.SDK.Tests/NetworkTest.cs
@@ -32,16 +32,13 @@ public class NetworkTest : NetworkTestsBase
new PrmNetworkSettings(new CallContext
{
CancellationToken = Mocker.CancellationTokenSource.Token,
- Timeout = TimeSpan.FromSeconds(20),
- OwnerId = OwnerId,
- Key = ECDsaKey,
- Version = Version
+ Timeout = TimeSpan.FromSeconds(20)
})
: new PrmNetworkSettings();
var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20);
- var result = await GetClient().GetNetworkSettingsAsync(param);
+ var result = await GetClient(DefaultSettings).GetNetworkSettingsAsync(param);
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
@@ -113,17 +110,14 @@ public class NetworkTest : NetworkTestsBase
Mocker.NetmapSnapshotResponse = new NetmapSnapshotResponse { Body = body };
- PrmNetmapSnapshot param;
+ PrmNetmapSnapshot param = new();
if (useContext)
{
var ctx = new CallContext
{
CancellationToken = Mocker.CancellationTokenSource.Token,
- Timeout = TimeSpan.FromSeconds(20),
- OwnerId = OwnerId,
- Key = ECDsaKey,
- Version = Version
+ Timeout = TimeSpan.FromSeconds(20)
};
param = new(ctx);
@@ -137,7 +131,7 @@ public class NetworkTest : NetworkTestsBase
var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20);
- var result = await GetClient().GetNetmapSnapshotAsync(param);
+ var result = await GetClient(DefaultSettings).GetNetmapSnapshotAsync(param);
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
@@ -219,10 +213,7 @@ public class NetworkTest : NetworkTestsBase
var ctx = new CallContext
{
CancellationToken = Mocker.CancellationTokenSource.Token,
- Timeout = TimeSpan.FromSeconds(20),
- OwnerId = OwnerId,
- Key = ECDsaKey,
- Version = Version
+ Timeout = TimeSpan.FromSeconds(20)
};
param = new(ctx);
@@ -236,7 +227,7 @@ public class NetworkTest : NetworkTestsBase
var validTimeoutFrom = DateTime.UtcNow.AddSeconds(20);
- var result = await GetClient().GetNodeInfoAsync(param);
+ var result = await GetClient(DefaultSettings).GetNodeInfoAsync(param);
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
diff --git a/src/FrostFS.SDK.Tests/NetworkTestsBase.cs b/src/FrostFS.SDK.Tests/NetworkTestsBase.cs
index 8090ecd..0cabab5 100644
--- a/src/FrostFS.SDK.Tests/NetworkTestsBase.cs
+++ b/src/FrostFS.SDK.Tests/NetworkTestsBase.cs
@@ -1,8 +1,6 @@
using System.Diagnostics.CodeAnalysis;
-using System.Security.Cryptography;
using FrostFS.SDK.Client.Interfaces;
-using FrostFS.SDK.Cryptography;
using Microsoft.Extensions.Options;
@@ -13,32 +11,27 @@ public abstract class NetworkTestsBase
{
internal readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- protected IOptions Settings { get; set; }
+ // protected FrostFsVersion Version { get; set; } = new FrostFsVersion(2, 13);
- protected FrostFsVersion Version { get; set; } = new FrostFsVersion(2, 13);
-
- protected ECDsa ECDsaKey { get; set; }
- protected FrostFsOwner OwnerId { get; set; }
protected NetworkMocker Mocker { get; set; }
+ protected ClientSettings DefaultSettings { get; }
+
protected NetworkTestsBase()
{
- Settings = Options.Create(new SingleOwnerClientSettings
+ DefaultSettings = new ClientSettings
{
Key = key,
- Host = "http://localhost:8080"
- });
-
- ECDsaKey = key.LoadWif();
- OwnerId = FrostFsOwner.FromKey(ECDsaKey);
+ Host = "http://localhost:8080",
+ };
Mocker = new NetworkMocker(this.key);
}
- protected IFrostFSClient GetClient()
+ protected IFrostFSClient GetClient(ClientSettings settings)
{
return Client.FrostFSClient.GetTestInstance(
- Settings,
+ Options.Create(settings),
null,
Mocker.GetMock().Object,
new SessionMocker(this.key).GetMock().Object,
diff --git a/src/FrostFS.SDK.Tests/ObjectTest.cs b/src/FrostFS.SDK.Tests/ObjectTest.cs
index dabbbc8..5914605 100644
--- a/src/FrostFS.SDK.Tests/ObjectTest.cs
+++ b/src/FrostFS.SDK.Tests/ObjectTest.cs
@@ -6,12 +6,9 @@ using System.Text;
using FrostFS.Refs;
using FrostFS.SDK.Client;
using FrostFS.SDK.Client.Mappers.GRPC;
-using FrostFS.SDK.Cryptography;
using Google.Protobuf;
-using static FrostFS.Object.ECInfo.Types;
-
namespace FrostFS.SDK.Tests;
[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")]
@@ -23,18 +20,9 @@ public class ObjectTest : ObjectTestsBase
{
var client = GetClient();
- var ecdsaKey = key.LoadWif();
+ var objectId = client.CalculateObjectId(Mocker.ObjectHeader!);
- var ctx = new CallContext
- {
- Key = ecdsaKey,
- OwnerId = FrostFsOwner.FromKey(ecdsaKey),
- Version = new FrostFsVersion(2, 13)
- };
-
- var objectId = client.CalculateObjectId(Mocker.ObjectHeader!, ctx);
-
- var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId, ctx));
+ var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId));
Assert.NotNull(result);
@@ -90,7 +78,7 @@ public class ObjectTest : ObjectTestsBase
NetworkMocker.Parameters.Add("MaxObjectSize", [0x0, 0xa]);
var blockSize = 2560;
- byte[] bytes = File.ReadAllBytes(@".\..\..\..\TestData\cat.jpg");
+ byte[] bytes = File.ReadAllBytes(@".\..\..\..\cat.jpg");
var fileLength = bytes.Length;
var param = new PrmObjectPut
@@ -295,7 +283,7 @@ public class ObjectTest : ObjectTestsBase
Assert.Equal(SHA256.HashData(hash), SHA256.HashData(result.First().ToArray()));
}
-
+
[Fact]
public async void PatchTest()
{
@@ -337,9 +325,9 @@ public class ObjectTest : ObjectTestsBase
Assert.Equal(address.ContainerId, body.Address.ContainerId);
Assert.Equal(address.ObjectId, body.Address.ObjectId);
-
+
Assert.Equal(32, body.Patch.Chunk.Length);
-
+
Assert.Equal(SHA256.HashData(patch), SHA256.HashData(body.Patch.Chunk.ToArray()));
}
}
diff --git a/src/FrostFS.SDK.Tests/ObjectTestsBase.cs b/src/FrostFS.SDK.Tests/ObjectTestsBase.cs
index ba68e6f..21289e4 100644
--- a/src/FrostFS.SDK.Tests/ObjectTestsBase.cs
+++ b/src/FrostFS.SDK.Tests/ObjectTestsBase.cs
@@ -10,7 +10,7 @@ public abstract class ObjectTestsBase
{
protected static readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- protected IOptions Settings { get; set; }
+ protected IOptions Settings { get; set; }
protected FrostFsContainerId ContainerId { get; set; }
protected NetworkMocker NetworkMocker { get; set; } = new NetworkMocker(key);
@@ -22,7 +22,7 @@ public abstract class ObjectTestsBase
{
var ecdsaKey = key.LoadWif();
- Settings = Options.Create(new SingleOwnerClientSettings
+ Settings = Options.Create(new ClientSettings
{
Key = key,
Host = "http://localhost:8080"
diff --git a/src/FrostFS.SDK.Tests/PoolSmokeTests.cs b/src/FrostFS.SDK.Tests/PoolSmokeTests.cs
index efc4802..0a6f2b3 100644
--- a/src/FrostFS.SDK.Tests/PoolSmokeTests.cs
+++ b/src/FrostFS.SDK.Tests/PoolSmokeTests.cs
@@ -6,8 +6,6 @@ using FrostFS.SDK.Cryptography;
using Microsoft.Extensions.Options;
-using static FrostFS.Session.SessionToken.Types.Body;
-
namespace FrostFS.SDK.SmokeTests;
[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")]
@@ -78,6 +76,8 @@ public class PoolSmokeTests : SmokeTestsBase
[Fact]
public async void NodeInfoStatisticsTwoNodesTest()
{
+ var callbackText = string.Empty;
+
var options = new InitParameters
{
Key = keyString.LoadWif(),
@@ -87,16 +87,14 @@ public class PoolSmokeTests : SmokeTestsBase
],
ClientBuilder = null,
GracefulCloseOnSwitchTimeout = 30_000_000,
- Logger = null
+ Logger = null,
+ Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"
};
using var pool = new Pool(options);
- var callbackText = string.Empty;
-
var ctx = new CallContext
{
- Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"
};
var error = await pool.Dial(ctx).ConfigureAwait(true);
@@ -118,14 +116,12 @@ public class PoolSmokeTests : SmokeTestsBase
{
var options = GetDefaultParams();
+ var callbackText = string.Empty;
+ options.Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
+
using var pool = new Pool(options);
- var callbackText = string.Empty;
-
- var ctx = new CallContext
- {
- Callback = (cs) => callbackText = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds"
- };
+ var ctx = new CallContext();
var error = await pool.Dial(ctx).ConfigureAwait(true);
@@ -154,18 +150,11 @@ public class PoolSmokeTests : SmokeTestsBase
var token = await pool.CreateSessionAsync(prm).ConfigureAwait(true);
- var session = new Session.SessionToken().Deserialize(token.Token);
-
var ownerHash = Base58.Decode(OwnerId!.Value);
- Assert.NotNull(session);
- Assert.Null(session.Body.Container);
- Assert.Null(session.Body.Object);
- Assert.Equal(16, session.Body.Id.Length);
- Assert.Equal(100ul, session.Body.Lifetime.Exp);
- Assert.Equal(ownerHash, session.Body.OwnerId.Value);
- Assert.Equal(33, session.Body.SessionKey.Length);
- Assert.Equal(ContextOneofCase.None, session.Body.ContextCase);
+ Assert.NotNull(token);
+ Assert.NotEqual(Guid.Empty, token.Id);
+ Assert.Equal(33, token.SessionKey.Length);
}
[Fact]
@@ -314,8 +303,16 @@ public class PoolSmokeTests : SmokeTestsBase
[InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioTest(int objectSize)
{
+ bool callbackInvoked = false;
+
var options = GetDefaultParams();
+ options.Callback = new((CallStatistics cs) =>
+ {
+ callbackInvoked = true;
+ Assert.True(cs.ElapsedMicroSeconds > 0);
+ });
+
using var pool = new Pool(options);
var error = await pool.Dial(new CallContext()).ConfigureAwait(true);
@@ -324,16 +321,7 @@ public class PoolSmokeTests : SmokeTestsBase
await Cleanup(pool);
- bool callbackInvoked = false;
- var ctx = new CallContext
- {
- // Timeout = TimeSpan.FromSeconds(20),
- Callback = new((CallStatistics cs) =>
- {
- callbackInvoked = true;
- Assert.True(cs.ElapsedMicroSeconds > 0);
- })
- };
+ var ctx = new CallContext { };
var createContainerParam = new PrmContainerCreate(
new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]), ctx);
@@ -346,12 +334,7 @@ public class PoolSmokeTests : SmokeTestsBase
var bytes = GetRandomBytes(objectSize);
- var ctx1 = new CallContext
- {
- Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
- };
-
- var param = new PrmObjectPut(ctx1)
+ var param = new PrmObjectPut()
{
Header = new FrostFsObjectHeader(
containerId: createdContainer,
@@ -410,6 +393,7 @@ public class PoolSmokeTests : SmokeTestsBase
var options = GetDefaultParams();
using var pool = new Pool(options);
+ options.Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0));
var error = await pool.Dial(new CallContext()).ConfigureAwait(true);
@@ -421,8 +405,7 @@ public class PoolSmokeTests : SmokeTestsBase
var ctx = new CallContext
{
- Timeout = TimeSpan.FromSeconds(20),
- Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
+ Timeout = TimeSpan.FromSeconds(20)
};
var createContainerParam = new PrmContainerCreate(
@@ -435,7 +418,7 @@ public class PoolSmokeTests : SmokeTestsBase
var bytes = GetRandomBytes(objectSize);
- var param = new PrmObjectPut(new CallContext { Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0)) })
+ var param = new PrmObjectPut(new CallContext())
{
Header = new FrostFsObjectHeader(
containerId: container,
@@ -517,7 +500,7 @@ public class PoolSmokeTests : SmokeTestsBase
Timeout = TimeSpan.FromSeconds(10),
};
- ctx.Interceptors.Add(new CallbackInterceptor());
+ // ctx.Interceptors.Add(new CallbackInterceptor());
var container = await pool.GetContainerAsync(new PrmContainerGet(containerId, ctx));
@@ -585,9 +568,9 @@ public class PoolSmokeTests : SmokeTestsBase
return bytes;
}
- private static IOptions GetSingleOwnerOptions(string key, string url)
+ private static IOptions GetSingleOwnerOptions(string key, string url)
{
- return Options.Create(new SingleOwnerClientSettings
+ return Options.Create(new ClientSettings
{
Key = key,
Host = url
diff --git a/src/FrostFS.SDK.Tests/SessionTests.cs b/src/FrostFS.SDK.Tests/SessionTests.cs
index 4cf03ba..9e79b29 100644
--- a/src/FrostFS.SDK.Tests/SessionTests.cs
+++ b/src/FrostFS.SDK.Tests/SessionTests.cs
@@ -2,6 +2,7 @@ using System.Diagnostics.CodeAnalysis;
using FrostFS.SDK.Client;
using FrostFS.SDK.Client.Mappers.GRPC;
+using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK.Tests;
@@ -21,10 +22,7 @@ public class SessionTest : SessionTestsBase
var ctx = new CallContext
{
CancellationToken = Mocker.CancellationTokenSource.Token,
- Timeout = TimeSpan.FromSeconds(20),
- OwnerId = OwnerId,
- Key = ECDsaKey,
- Version = Mocker.Version
+ Timeout = TimeSpan.FromSeconds(20)
};
param = new PrmSessionCreate(exp, ctx);
@@ -43,18 +41,16 @@ public class SessionTest : SessionTestsBase
var validTimeoutTo = DateTime.UtcNow.AddSeconds(20);
Assert.NotNull(result);
- Assert.NotNull(result.Token);
+ Assert.NotEqual(Guid.Empty, result.Id);
- var session = new Session.SessionToken().Deserialize(result.Token);
+ Assert.Equal(Mocker.SessionId, result.Id.ToBytes());
+ Assert.Equal(Mocker.SessionKey, result.SessionKey.ToArray());
- Assert.Equal(Mocker.SessionId, session.Body.Id);
- Assert.Equal(Mocker.SessionKey, session.Body.SessionKey);
-
- Assert.Equal(OwnerId.ToMessage(), session.Body.OwnerId);
- Assert.Equal(exp, session.Body.Lifetime.Exp);
- Assert.Equal(exp, session.Body.Lifetime.Iat);
- Assert.Equal(exp, session.Body.Lifetime.Nbf);
- Assert.Null(session.Body.Container);
+ //Assert.Equal(OwnerId.ToMessage(), result.Token.Body.OwnerId);
+ //Assert.Equal(exp, result.Token.Body.Lifetime.Exp);
+ //Assert.Equal(exp, result.Token.Body.Lifetime.Iat);
+ //Assert.Equal(exp, result.Token.Body.Lifetime.Nbf);
+ //Assert.Null(result.Token.Body.Container);
Assert.NotNull(Mocker.CreateSessionRequest);
diff --git a/src/FrostFS.SDK.Tests/SessionTestsBase.cs b/src/FrostFS.SDK.Tests/SessionTestsBase.cs
index 93bc140..bd958fc 100644
--- a/src/FrostFS.SDK.Tests/SessionTestsBase.cs
+++ b/src/FrostFS.SDK.Tests/SessionTestsBase.cs
@@ -11,7 +11,7 @@ public abstract class SessionTestsBase
{
internal readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- protected IOptions Settings { get; set; }
+ protected IOptions Settings { get; set; }
protected ECDsa ECDsaKey { get; set; }
protected FrostFsOwner OwnerId { get; set; }
@@ -19,7 +19,7 @@ public abstract class SessionTestsBase
protected SessionTestsBase()
{
- Settings = Options.Create(new SingleOwnerClientSettings
+ Settings = Options.Create(new ClientSettings
{
Key = key,
Host = "http://localhost:8080"
diff --git a/src/FrostFS.SDK.Tests/SmokeClientTests.cs b/src/FrostFS.SDK.Tests/SmokeClientTests.cs
index ba822c7..aaf1869 100644
--- a/src/FrostFS.SDK.Tests/SmokeClientTests.cs
+++ b/src/FrostFS.SDK.Tests/SmokeClientTests.cs
@@ -1,4 +1,4 @@
-using System.Diagnostics.CodeAnalysis;
+using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using FrostFS.SDK.Client;
@@ -7,8 +7,6 @@ using FrostFS.SDK.Cryptography;
using Microsoft.Extensions.Options;
-using static FrostFS.Session.SessionToken.Types.Body;
-
namespace FrostFS.SDK.SmokeTests;
[SuppressMessage("Reliability", "CA2007:Consider calling ConfigureAwait on the awaited task", Justification = "Default Value is correct for tests")]
@@ -17,29 +15,23 @@ public class SmokeClientTests : SmokeTestsBase
{
private static readonly PrmWait lightWait = new(100, 1);
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async void AccountTest(bool isSingleOnwerClient)
+ [Fact]
+ public async void AccountTest()
{
- using var client = isSingleOnwerClient
- ? FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url))
- : FrostFSClient.GetInstance(GetOptions(this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
- PrmBalance? prm = isSingleOnwerClient ? default : new(Ctx);
+ var result = await client.GetBalanceAsync();
- var result = await client.GetBalanceAsync(prm);
+ Assert.NotNull(result);
+ Assert.True(result.Value == 0);
}
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async void NetworkMapTest(bool isSingleOnwerClient)
+ [Fact]
+ public async void NetworkMapTest()
{
- using var client = isSingleOnwerClient ? FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url)) : FrostFSClient.GetInstance(GetOptions(this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
- PrmNetmapSnapshot? prm = isSingleOnwerClient ? default : new(Ctx);
- var result = await client.GetNetmapSnapshotAsync(prm);
+ var result = await client.GetNetmapSnapshotAsync();
Assert.True(result.Epoch > 0);
Assert.Single(result.NodeInfoCollection);
@@ -54,18 +46,12 @@ public class SmokeClientTests : SmokeTestsBase
}
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async void NodeInfoTest(bool isSingleOnwerClient)
+ [Fact]
+ public async void NodeInfoTest()
{
- using var client = isSingleOnwerClient
- ? FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url))
- : FrostFSClient.GetInstance(GetOptions(this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
- PrmNodeInfo? prm = isSingleOnwerClient ? default : new(Ctx);
-
- var result = await client.GetNodeInfoAsync(prm);
+ var result = await client.GetNodeInfoAsync();
Assert.Equal(2, result.Version.Major);
Assert.Equal(13, result.Version.Minor);
@@ -78,45 +64,38 @@ public class SmokeClientTests : SmokeTestsBase
[Fact]
public async void NodeInfoStatisticsTest()
{
- var ctx = new CallContext
- {
- Callback = (cs) => Console.WriteLine($"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds")
- };
+ var options = GetClientOptions(this.keyString, this.url);
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ var callbackContent = string.Empty;
+ options.Value.Callback = (cs) => callbackContent = $"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds";
+
+ using var client = FrostFSClient.GetSingleOwnerInstance(options);
var result = await client.GetNodeInfoAsync();
+
+ Assert.NotEmpty(callbackContent);
}
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public async void GetSessionTest(bool isSingleOnwerClient)
+ [Fact]
+ public async void GetSessionTest()
{
- using var client = isSingleOnwerClient ? FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url)) : FrostFSClient.GetInstance(GetOptions(this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
- PrmSessionCreate? prm = isSingleOnwerClient ? new PrmSessionCreate(100) : new PrmSessionCreate(100, Ctx);
+ PrmSessionCreate? prm = new(100);
var token = await client.CreateSessionAsync(prm);
- var session = new Session.SessionToken().Deserialize(token.Token);
-
var ownerHash = Base58.Decode(OwnerId!.Value);
- Assert.NotNull(session);
- Assert.Null(session.Body.Container);
- Assert.Null(session.Body.Object);
- Assert.Equal(16, session.Body.Id.Length);
- Assert.Equal(100ul, session.Body.Lifetime.Exp);
- Assert.Equal(ownerHash, session.Body.OwnerId.Value);
- Assert.Equal(33, session.Body.SessionKey.Length);
- Assert.Equal(ContextOneofCase.None, session.Body.ContextCase);
+ Assert.NotNull(token);
+ Assert.NotEqual(Guid.Empty, token.Id);
+ Assert.Equal(33, token.SessionKey.Length);
}
[Fact]
public async void CreateObjectWithSessionToken()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -164,7 +143,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact]
public async void FilterTest()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -248,89 +227,87 @@ public class SmokeClientTests : SmokeTestsBase
[InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioTest(int objectSize)
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ bool callbackInvoked = false;
- await Cleanup(client);
+ var options = GetClientOptions(this.keyString, this.url);
- bool callbackInvoked = false;
- var ctx = new CallContext
- {
- // Timeout = TimeSpan.FromSeconds(20),
- Callback = new((CallStatistics cs) =>
- {
- callbackInvoked = true;
- Assert.True(cs.ElapsedMicroSeconds > 0);
- })
- };
+ options.Value.Callback = new((CallStatistics cs) =>
+ {
+ callbackInvoked = true;
+ Assert.True(cs.ElapsedMicroSeconds > 0);
+ });
- var createContainerParam = new PrmContainerCreate(
- new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]), ctx);
+ using var client = FrostFSClient.GetSingleOwnerInstance(options);
- var createdContainer = await client.CreateContainerAsync(createContainerParam);
+ await Cleanup(client);
- var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer, ctx));
- Assert.NotNull(container);
- Assert.True(callbackInvoked);
+ var ctx = new CallContext { Timeout = TimeSpan.FromSeconds(20) };
- var bytes = GetRandomBytes(objectSize);
+ var createContainerParam = new PrmContainerCreate(
+ new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1)), [new("testKey", "testValue")]), ctx);
- var param = new PrmObjectPut(new CallContext
- {
- Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
- })
- {
- Header = new FrostFsObjectHeader(
- containerId: createdContainer,
- type: FrostFsObjectType.Regular,
- [new FrostFsAttributePair("fileName", "test")]),
- Payload = new MemoryStream(bytes),
- ClientCut = false
- };
+ var createdContainer = await client.CreateContainerAsync(createContainerParam);
- var objectId = await client.PutObjectAsync(param);
+ var container = await client.GetContainerAsync(new PrmContainerGet(createdContainer));
+ Assert.NotNull(container);
+ Assert.True(callbackInvoked);
- var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
+ var bytes = GetRandomBytes(objectSize);
- bool hasObject = false;
- await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer) { Filters = [filter] }))
- {
- hasObject = true;
+ var param = new PrmObjectPut
+ {
+ Header = new FrostFsObjectHeader(
+ containerId: createdContainer,
+ type: FrostFsObjectType.Regular,
+ [new FrostFsAttributePair("fileName", "test")]),
+ Payload = new MemoryStream(bytes),
+ ClientCut = false
+ };
- var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(createdContainer, objectId));
- Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
- Assert.NotNull(objHeader.Attributes);
- Assert.Single(objHeader.Attributes);
- Assert.Equal("fileName", objHeader.Attributes.First().Key);
- Assert.Equal("test", objHeader.Attributes.First().Value);
- }
+ var objectId = await client.PutObjectAsync(param);
- Assert.True(hasObject);
+ var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test");
- var @object = await client.GetObjectAsync(new PrmObjectGet(createdContainer, objectId));
+ bool hasObject = false;
+ await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(createdContainer) { Filters = [filter] }))
+ {
+ hasObject = true;
- var downloadedBytes = new byte[@object.Header.PayloadLength];
- MemoryStream ms = new(downloadedBytes);
+ var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(createdContainer, objectId));
+ Assert.Equal((ulong)bytes.Length, objHeader.PayloadLength);
+ Assert.NotNull(objHeader.Attributes);
+ Assert.Single(objHeader.Attributes);
+ Assert.Equal("fileName", objHeader.Attributes.First().Key);
+ Assert.Equal("test", objHeader.Attributes.First().Value);
+ }
- ReadOnlyMemory? chunk = null;
- while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
- {
- ms.Write(chunk.Value.Span);
- }
+ Assert.True(hasObject);
- Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
+ var @object = await client.GetObjectAsync(new PrmObjectGet(createdContainer, objectId));
- await Cleanup(client);
+ var downloadedBytes = new byte[@object.Header.PayloadLength];
+ MemoryStream ms = new(downloadedBytes);
- await foreach (var _ in client.ListContainersAsync())
- {
- Assert.Fail("Containers exist");
- }
+ ReadOnlyMemory? chunk = null;
+ while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
+ {
+ ms.Write(chunk.Value.Span);
+ }
+
+ Assert.Equal(SHA256.HashData(bytes), SHA256.HashData(downloadedBytes));
+
+ await Cleanup(client);
+
+ await foreach (var _ in client.ListContainersAsync())
+ {
+ Assert.Fail("Containers exist");
+ }
}
[Fact]
public async void PatchTest()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -388,7 +365,7 @@ public class SmokeClientTests : SmokeTestsBase
ms.Write(chunk.Value.Span);
}
- for(int i = 0; i < (int)range.Offset; i++)
+ for (int i = 0; i < (int)range.Offset; i++)
Assert.Equal(downloadedBytes[i], bytes[i]);
var rangeEnd = range.Offset + range.Length;
@@ -410,7 +387,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact]
public async void RangeTest()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -465,7 +442,7 @@ public class SmokeClientTests : SmokeTestsBase
[Fact]
public async void RangeHashTest()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -494,15 +471,15 @@ public class SmokeClientTests : SmokeTestsBase
var objectId = await client.PutObjectAsync(param);
- var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [ new FrostFsRange(100, 64)], bytes);
+ var rangeParam = new PrmRangeHashGet(createdContainer, objectId, [new FrostFsRange(100, 64)], bytes);
var hashes = await client.GetRangeHashAsync(rangeParam);
foreach (var hash in hashes)
{
- var x = hash.Slice(0, 32).ToArray();
+ var x = hash[..32].ToArray();
}
-
+
await Cleanup(client);
await foreach (var _ in client.ListContainersAsync())
@@ -517,8 +494,8 @@ public class SmokeClientTests : SmokeTestsBase
[InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioWithSessionTest(int objectSize)
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
-
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
+ //Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue));
await Cleanup(client);
@@ -526,7 +503,7 @@ public class SmokeClientTests : SmokeTestsBase
var ctx = new CallContext
{
Timeout = TimeSpan.FromSeconds(20),
- Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
+
};
var createContainerParam = new PrmContainerCreate(
@@ -539,10 +516,7 @@ public class SmokeClientTests : SmokeTestsBase
var bytes = GetRandomBytes(objectSize);
- var param = new PrmObjectPut(new CallContext
- {
- Callback = new((CallStatistics cs) => Assert.True(cs.ElapsedMicroSeconds > 0))
- })
+ var param = new PrmObjectPut
{
Header = new FrostFsObjectHeader(
containerId: container,
@@ -602,7 +576,11 @@ public class SmokeClientTests : SmokeTestsBase
[InlineData(200)]
public async void ClientCutScenarioTest(int objectSize)
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
+
+ var options = GetClientOptions(this.keyString, this.url);
+ options.Value.Interceptors.Add(new CallbackInterceptor());
+
+ using var client = FrostFSClient.GetSingleOwnerInstance(GetClientOptions(this.keyString, this.url));
await Cleanup(client);
@@ -613,12 +591,7 @@ public class SmokeClientTests : SmokeTestsBase
var containerId = await client.CreateContainerAsync(createContainerParam);
- var ctx = new CallContext
- {
- Timeout = TimeSpan.FromSeconds(10)
- };
-
- ctx.Interceptors.Add(new CallbackInterceptor());
+ var ctx = new CallContext { Timeout = TimeSpan.FromSeconds(10) };
var container = await client.GetContainerAsync(new PrmContainerGet(containerId, ctx));
@@ -692,23 +665,21 @@ public class SmokeClientTests : SmokeTestsBase
[Fact]
public async void NodeInfoCallbackAndInterceptorTest()
{
- using var client = FrostFSClient.GetSingleOwnerInstance(GetSingleOwnerOptions(this.keyString, this.url));
-
bool callbackInvoked = false;
bool intercepterInvoked = false;
- var ctx = new CallContext
+ var options = GetClientOptions(this.keyString, this.url);
+ options.Value.Callback = (CallStatistics cs) =>
{
- Callback = new((CallStatistics cs) =>
- {
- callbackInvoked = true;
- Assert.True(cs.ElapsedMicroSeconds > 0);
- })
+ callbackInvoked = true;
+ Assert.True(cs.ElapsedMicroSeconds > 0);
};
- ctx.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true));
+ options.Value.Interceptors.Add(new CallbackInterceptor(s => intercepterInvoked = true));
- var result = await client.GetNodeInfoAsync(new PrmNodeInfo(ctx));
+ using var client = FrostFSClient.GetSingleOwnerInstance(options);
+
+ var result = await client.GetNodeInfoAsync(new PrmNodeInfo());
Assert.True(callbackInvoked);
Assert.True(intercepterInvoked);
@@ -729,22 +700,15 @@ public class SmokeClientTests : SmokeTestsBase
return bytes;
}
- private static IOptions GetSingleOwnerOptions(string key, string url)
+ private static IOptions GetClientOptions(string key, string url)
{
- return Options.Create(new SingleOwnerClientSettings
+ return Options.Create(new ClientSettings
{
Key = key,
Host = url
});
}
- private static IOptions GetOptions(string url)
- {
- return Options.Create(new ClientSettings
- {
- Host = url
- });
- }
static async Task Cleanup(IFrostFSClient client)
{
diff --git a/src/FrostFS.SDK.Tests/SmokeTestsBase.cs b/src/FrostFS.SDK.Tests/SmokeTestsBase.cs
index 5d67029..b96997c 100644
--- a/src/FrostFS.SDK.Tests/SmokeTestsBase.cs
+++ b/src/FrostFS.SDK.Tests/SmokeTestsBase.cs
@@ -7,8 +7,6 @@ namespace FrostFS.SDK.SmokeTests;
public abstract class SmokeTestsBase
{
- // internal readonly string keyString = "KzPXA6669m2pf18XmUdoR8MnP1pi1PMmefiFujStVFnv7WR5SRmK";
-
internal readonly string keyString = "KzPXA6669m2pf18XmUdoR8MnP1pi1PMmefiFujStVFnv7WR5SRmK";
internal readonly string url = "http://172.23.32.4:8080";
@@ -26,7 +24,5 @@ public abstract class SmokeTestsBase
Key = keyString.LoadWif();
OwnerId = FrostFsOwner.FromKey(Key);
Version = new FrostFsVersion(2, 13);
-
- Ctx = new CallContext { Key = Key, OwnerId = OwnerId, Version = Version };
}
}
diff --git a/src/FrostFS.SDK.Tests/TestData/cat.jpg b/src/FrostFS.SDK.Tests/cat.jpg
similarity index 100%
rename from src/FrostFS.SDK.Tests/TestData/cat.jpg
rename to src/FrostFS.SDK.Tests/cat.jpg