From 2a28806ace76a79f42bd5d1805a2fa1da5ca20d4 Mon Sep 17 00:00:00 2001
From: Pavel Gross
Date: Mon, 12 Aug 2024 10:46:59 +0300
Subject: [PATCH] [#21] Client: Allows multinenant client
Using one client for several owners
Signed-off-by: Pavel Gross
---
src/FrostFS.SDK.ClientV2/Client.cs | 73 ++++++++++--
.../Interfaces/IFrostFSClient.cs | 2 +-
.../Parameters}/Context.cs | 28 ++++-
.../Parameters/Credentials.cs | 11 ++
.../Parameters/PrmBase.cs | 14 +++
.../Parameters/PrmContainerCreate.cs | 12 +-
.../Parameters/PrmContainerDelete.cs | 13 +--
.../Parameters/PrmContainerGet.cs | 13 +--
.../Parameters/PrmContainerGetAll.cs | 9 +-
.../Parameters/PrmNetmapSnapshot.cs | 11 +-
.../Parameters/PrmNetworkSettings.cs | 15 +--
.../Parameters/PrmNodeInfo.cs | 15 +--
.../Parameters/PrmObjectDelete.cs | 11 +-
.../Parameters/PrmObjectGet.cs | 14 +--
.../Parameters/PrmObjectHeadGet.cs | 16 +--
.../Parameters/PrmObjectPut.cs | 14 +--
.../Parameters/PrmObjectSearch.cs | 17 +--
.../Parameters/PrmSessionCreate.cs | 14 +--
.../Parameters/PrmSingleObjectPut.cs | 14 +--
.../Services/ContainerServiceProvider.cs | 24 ++--
.../Services/NetmapServiceProvider.cs | 6 +-
.../Services/ObjectServiceProvider.cs | 40 +++----
.../Services/SessionServiceProvider.cs | 5 +-
.../Services/Shared/SessionProvider.cs | 2 +-
.../Tools/ClientEnvironment.cs | 11 +-
src/FrostFS.SDK.ClientV2/Tools/ObjectTools.cs | 33 +++---
.../Client/ClientSettings.cs | 64 ++++++++---
src/FrostFS.SDK.Tests/ContainerTest.cs | 4 +-
src/FrostFS.SDK.Tests/ObjectTest.cs | 19 ++--
src/FrostFS.SDK.Tests/SmokeTests.cs | 106 ++++++++++++------
30 files changed, 349 insertions(+), 281 deletions(-)
rename src/{FrostFS.SDK.ModelsV2/Client => FrostFS.SDK.ClientV2/Parameters}/Context.cs (54%)
create mode 100644 src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs
create mode 100644 src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs
diff --git a/src/FrostFS.SDK.ClientV2/Client.cs b/src/FrostFS.SDK.ClientV2/Client.cs
index faf18024..0142c032 100644
--- a/src/FrostFS.SDK.ClientV2/Client.cs
+++ b/src/FrostFS.SDK.ClientV2/Client.cs
@@ -35,6 +35,11 @@ public class Client : IFrostFSClient
return new Client(clientOptions, channelOptions);
}
+ public static IFrostFSClient GetSingleOwnerInstance(IOptions clientOptions, GrpcChannelOptions? channelOptions = null)
+ {
+ return new Client(clientOptions, channelOptions);
+ }
+
///
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
///
@@ -46,7 +51,7 @@ public class Client : IFrostFSClient
/// Object.ObjectService.ObjectServiceClient implementation
///
public static IFrostFSClient GetTestInstance(
- IOptions clientOptions,
+ IOptions clientOptions,
GrpcChannelOptions? channelOptions,
NetmapService.NetmapServiceClient netmapService,
SessionService.SessionServiceClient sessionService,
@@ -57,18 +62,18 @@ public class Client : IFrostFSClient
}
private Client(
- IOptions settings,
- GrpcChannelOptions? channelOptions,
- ContainerService.ContainerServiceClient containerService,
- NetmapService.NetmapServiceClient netmapService,
- SessionService.SessionServiceClient sessionService,
- ObjectService.ObjectServiceClient objectService)
+ IOptions settings,
+ GrpcChannelOptions? channelOptions,
+ ContainerService.ContainerServiceClient containerService,
+ NetmapService.NetmapServiceClient netmapService,
+ SessionService.SessionServiceClient sessionService,
+ ObjectService.ObjectServiceClient objectService)
{
var ecdsaKey = settings.Value.Key.LoadWif();
OwnerId.FromKey(ecdsaKey);
ClientCtx = new ClientEnvironment(
- this,
+ client: this,
key: ecdsaKey,
owner: OwnerId.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
@@ -86,6 +91,25 @@ public class Client : IFrostFSClient
clientSettings.Validate();
+ var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
+
+ ClientCtx = new ClientEnvironment(
+ this,
+ key: null,
+ owner: null,
+ channel: channel,
+ version: new Version(2, 13));
+
+ // TODO: define timeout logic
+ // CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
+ }
+
+ private Client(IOptions options, GrpcChannelOptions? channelOptions)
+ {
+ var clientSettings = (options?.Value) ?? throw new ArgumentException("Options must be initialized");
+
+ clientSettings.Validate();
+
var ecdsaKey = clientSettings.Key.LoadWif();
var channel = InitGrpcChannel(clientSettings.Host, channelOptions);
@@ -221,22 +245,22 @@ public class Client : IFrostFSClient
#endregion
#region ToolsImplementation
- public ObjectId CalculateObjectId(ObjectHeader header)
+ public ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
{
if (header == null)
throw new ArgumentNullException(nameof(header));
- return ObjectTools.CalculateObjectId(header, ClientCtx);
+ return ObjectTools.CalculateObjectId(header, ctx);
}
#endregion
private async void CheckFrostFsVersionSupport(Context? ctx = default)
{
- var args = new PrmNodeInfo(ctx);
+ var args = new PrmNodeInfo { Context = ctx };
var service = GetNetmapService(args);
var localNodeInfo = await service.GetLocalNodeInfoAsync(args);
- if (!localNodeInfo.Version.IsSupported(ClientCtx.Version))
+ if (!localNodeInfo.Version.IsSupported(args.Context!.Version))
{
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
throw new ApplicationException(msg);
@@ -250,6 +274,31 @@ public class Client : IFrostFSClient
ctx.Context ??= new Context();
+ if (ctx.Context.Key == null)
+ {
+ if (ClientCtx.Key == null)
+ {
+ throw new Exception("Key is not initialized.");
+ }
+
+ ctx.Context.Key = ClientCtx.Key.ECDsaKey;
+ }
+
+ if (ctx.Context.OwnerId == null)
+ {
+ ctx.Context.OwnerId = ClientCtx.Owner ?? OwnerId.FromKey(ctx.Context.Key);
+ }
+
+ if (ctx.Context.Version == null)
+ {
+ if (ClientCtx.Version == null)
+ {
+ throw new Exception("Version is not initialized.");
+ }
+
+ ctx.Context.Version = ClientCtx.Version;
+ }
+
CallInvoker? callInvoker = null;
if (ctx.Context.Interceptors != null && ctx.Context.Interceptors.Count > 0)
{
diff --git a/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs b/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs
index a3a7f812..500a9c2a 100644
--- a/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs
+++ b/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs
@@ -45,6 +45,6 @@ public interface IFrostFSClient : IDisposable
#endregion
#region Tools
- ObjectId CalculateObjectId(ObjectHeader header);
+ ObjectId CalculateObjectId(ObjectHeader header, Context ctx);
#endregion
}
diff --git a/src/FrostFS.SDK.ModelsV2/Client/Context.cs b/src/FrostFS.SDK.ClientV2/Parameters/Context.cs
similarity index 54%
rename from src/FrostFS.SDK.ModelsV2/Client/Context.cs
rename to src/FrostFS.SDK.ClientV2/Parameters/Context.cs
index 4ac90a8c..ca3728a9 100644
--- a/src/FrostFS.SDK.ModelsV2/Client/Context.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/Context.cs
@@ -1,7 +1,10 @@
using System;
using System.Collections.Generic;
+using System.Security.Cryptography;
using System.Threading;
using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.Cryptography;
+using Google.Protobuf;
using Grpc.Core.Interceptors;
namespace FrostFS.SDK.ClientV2;
@@ -10,8 +13,18 @@ public class Context()
{
private List? interceptors;
+ private ByteString publicKeyCache;
+
+ public ECDsa Key { get; set; }
+
+ public OwnerId OwnerId { get; set; }
+
+ public ModelsV2.Version Version { get; set; }
+
public CancellationToken CancellationToken { get; set; } = default;
+
public TimeSpan Timeout { get; set; } = default;
+
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
public Action? Callback { get; set; }
@@ -20,5 +33,18 @@ public class Context()
{
get { return this.interceptors ??= []; }
set { this.interceptors = value; }
- }
+ }
+
+ public ByteString PublicKeyCache
+ {
+ get
+ {
+ if (publicKeyCache == null)
+ {
+ publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
+ }
+
+ return publicKeyCache;
+ }
+ }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs b/src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs
new file mode 100644
index 00000000..a4915c3a
--- /dev/null
+++ b/src/FrostFS.SDK.ClientV2/Parameters/Credentials.cs
@@ -0,0 +1,11 @@
+using FrostFS.SDK.ModelsV2;
+using System.Security.Cryptography;
+
+namespace FrostFS.SDK.ClientV2.Parameters;
+
+public class Credentials(ECDsa key, OwnerId ownerId)
+{
+ public ECDsa Key { get; } = key;
+
+ public OwnerId OwnerId { get; } = ownerId;
+}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs
new file mode 100644
index 00000000..09ca3636
--- /dev/null
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmBase.cs
@@ -0,0 +1,14 @@
+using System.Collections.Specialized;
+
+namespace FrostFS.SDK.ClientV2.Parameters;
+
+public class PrmBase() : IContext
+{
+ ///
+ /// FrostFS request X-Headers
+ ///
+ public NameValueCollection XHeaders { get; set; } = [];
+
+ ///
+ public Context? Context { get; set; }
+}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerCreate.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerCreate.cs
index 4185a419..21e4931a 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerCreate.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerCreate.cs
@@ -1,8 +1,8 @@
-using System.Collections.Specialized;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmContainerCreate(ModelsV2.Container container) : IContext
+public sealed class PrmContainerCreate(ModelsV2.Container container) : PrmBase, ISessionToken
{
public ModelsV2.Container Container { get; set; } = container;
@@ -12,11 +12,7 @@ public sealed class PrmContainerCreate(ModelsV2.Container container) : IContext
/// Rules for polling the result
public PrmWait? WaitParams { get; set; }
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
+ public string SessionKey { get; set; }
- ///
- public Context? Context { get; set; }
+ public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerDelete.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerDelete.cs
index 8455f517..63308aab 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerDelete.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerDelete.cs
@@ -1,9 +1,8 @@
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmContainerDelete(ContainerId containerId, Context? ctx = null) : IContext
+public sealed class PrmContainerDelete(ContainerId containerId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
@@ -12,12 +11,6 @@ public sealed class PrmContainerDelete(ContainerId containerId, Context? ctx = n
///
/// Rules for polling the result
public PrmWait? WaitParams { get; set; }
-
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
- ///
- public Context? Context { get; set; } = ctx;
+ public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGet.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGet.cs
index 2761ba2f..cebdaca8 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGet.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGet.cs
@@ -1,17 +1,8 @@
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmContainerGet(ContainerId containerId, Context? ctx = null) : IContext
+public sealed class PrmContainerGet(ContainerId containerId) : PrmBase
{
public ContainerId ContainerId { get; set; } = containerId;
-
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = ctx;
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGetAll.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGetAll.cs
index 77d954e2..e1556067 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGetAll.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmContainerGetAll.cs
@@ -2,13 +2,6 @@
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmContainerGetAll() : IContext
+public sealed class PrmContainerGetAll() : PrmBase()
{
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmNetmapSnapshot.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmNetmapSnapshot.cs
index 117ab856..e5316ee9 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmNetmapSnapshot.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmNetmapSnapshot.cs
@@ -2,13 +2,6 @@
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmNetmapSnapshot(Context? context = default) : IContext
-{
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = context;
+public sealed class PrmNetmapSnapshot() : PrmBase
+{
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmNetworkSettings.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmNetworkSettings.cs
index 250eb04b..c82db6e1 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmNetworkSettings.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmNetworkSettings.cs
@@ -1,14 +1,5 @@
-using System.Collections.Specialized;
+namespace FrostFS.SDK.ClientV2.Parameters;
-namespace FrostFS.SDK.ClientV2.Parameters;
-
-public sealed class PrmNetworkSettings(Context? context = default) : IContext
-{
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = context;
+public sealed class PrmNetworkSettings() : PrmBase
+{
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmNodeInfo.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmNodeInfo.cs
index 8a293a58..2b3b661c 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmNodeInfo.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmNodeInfo.cs
@@ -1,14 +1,5 @@
-using System.Collections.Specialized;
+namespace FrostFS.SDK.ClientV2.Parameters;
-namespace FrostFS.SDK.ClientV2.Parameters;
-
-public sealed class PrmNodeInfo(Context? context = default) : IContext
-{
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = context;
+public sealed class PrmNodeInfo() : PrmBase
+{
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectDelete.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectDelete.cs
index 100f5589..96df2c11 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectDelete.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectDelete.cs
@@ -3,19 +3,12 @@ using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmObjectDelete(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
+public sealed class PrmObjectDelete(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
+
public ObjectId ObjectId { get; set; } = objectId;
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
-
///
public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectGet.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectGet.cs
index 9c8cb1c9..07e717f8 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectGet.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectGet.cs
@@ -1,21 +1,13 @@
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmObjectGet(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
+public sealed class PrmObjectGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
+
public ObjectId ObjectId { get; set; } = objectId;
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
-
///
public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectHeadGet.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectHeadGet.cs
index 5184fe88..cdc75cb4 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectHeadGet.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectHeadGet.cs
@@ -1,21 +1,13 @@
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmObjectHeadGet(ContainerId containerId, ObjectId objectId) : IContext, ISessionToken
+public sealed class PrmObjectHeadGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
+
public ObjectId ObjectId { get; set; } = objectId;
-
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
-
+
///
public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectPut.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectPut.cs
index fea3bd5f..0fcf91da 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectPut.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectPut.cs
@@ -1,10 +1,10 @@
-using FrostFS.SDK.ModelsV2;
using System.Collections.Specialized;
using System.IO;
+using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmObjectPut : IContext, ISessionToken
+public sealed class PrmObjectPut : PrmBase, ISessionToken
{
///
/// Need to provide values like ContainerId and ObjectType to create and object.
@@ -30,21 +30,13 @@ public sealed class PrmObjectPut : IContext, ISessionToken
/// Overrides default size of the buffer for stream transferring.
///
/// Size of the buffer
- public int BufferMaxSize { get; set; }
+ public int BufferMaxSize { get; set; }
///
/// Allows to define a buffer for chunks to manage by the memory allocation and releasing.
///
public byte[]? CustomBuffer { get; set; }
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
-
///
public SessionToken? SessionToken { get; set; }
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectSearch.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectSearch.cs
index c4e8fc9a..e7c56be0 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectSearch.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmObjectSearch.cs
@@ -1,9 +1,8 @@
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
+using System.Collections.Generic;
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilter[] filters) : IContext, ISessionToken
+public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilter[] filters) : PrmBase, ISessionToken
{
///
/// Defines container for the search
@@ -16,15 +15,7 @@ public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilte
///
/// Collection of filters
public IEnumerable Filters { get; set; } = filters;
-
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; }
-
+
///
public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmSessionCreate.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmSessionCreate.cs
index 22f0c4ed..2afc76f2 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmSessionCreate.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmSessionCreate.cs
@@ -1,16 +1,6 @@
-using System.Collections.Specialized;
+namespace FrostFS.SDK.ClientV2.Parameters;
-namespace FrostFS.SDK.ClientV2.Parameters;
-
-public sealed class PrmSessionCreate(ulong expiration, Context? context = default) : IContext
+public sealed class PrmSessionCreate(ulong expiration) : PrmBase
{
public ulong Expiration { get; set; } = expiration;
-
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = context;
}
diff --git a/src/FrostFS.SDK.ClientV2/Parameters/PrmSingleObjectPut.cs b/src/FrostFS.SDK.ClientV2/Parameters/PrmSingleObjectPut.cs
index 0d1df0f8..fc22bf74 100644
--- a/src/FrostFS.SDK.ClientV2/Parameters/PrmSingleObjectPut.cs
+++ b/src/FrostFS.SDK.ClientV2/Parameters/PrmSingleObjectPut.cs
@@ -1,19 +1,11 @@
-using System.Collections.Specialized;
-using FrostFS.SDK.ModelsV2;
+using FrostFS.SDK.ModelsV2;
+
namespace FrostFS.SDK.ClientV2.Parameters;
-public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject, Context? context = null) : IContext, ISessionToken
+public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject) : PrmBase, ISessionToken
{
public FrostFsObject FrostFsObject { get; set; } = frostFsObject;
- ///
- /// FrostFS request X-Headers
- ///
- public NameValueCollection XHeaders { get; set; } = [];
-
- ///
- public Context? Context { get; set; } = context;
-
///
public SessionToken? SessionToken { get; set; }
}
diff --git a/src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs b/src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs
index 7f412c15..b91fcd12 100644
--- a/src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs
+++ b/src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs
@@ -17,7 +17,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
{
internal async Task GetContainerAsync(PrmContainerGet args)
{
- GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders);
+ GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders, args.Context!);
var response = await service.GetAsync(request, null, args.Context!.Deadline, args.Context.CancellationToken);
@@ -34,12 +34,12 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
{
Body = new ListRequest.Types.Body
{
- OwnerId = Context.Owner.ToMessage()
+ OwnerId = ctx.OwnerId.ToMessage()
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await service.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -55,20 +55,20 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
{
var ctx = args.Context!;
var grpcContainer = args.Container.ToMessage();
- grpcContainer.OwnerId = Context.Owner.ToMessage();
- grpcContainer.Version = Context.Version.ToMessage();
+ grpcContainer.OwnerId = ctx.OwnerId.ToMessage();
+ grpcContainer.Version = ctx.Version.ToMessage();
var request = new PutRequest
{
Body = new PutRequest.Types.Body
{
Container = grpcContainer,
- Signature = Context.Key.ECDsaKey.SignRFC6979(grpcContainer)
+ Signature = ctx.Key.SignRFC6979(grpcContainer)
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await service.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -87,13 +87,13 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
Body = new DeleteRequest.Types.Body
{
ContainerId = args.ContainerId.ToMessage(),
- Signature = Context.Key.ECDsaKey.SignRFC6979(args.ContainerId.ToMessage().Value)
+ Signature = ctx.Key.SignRFC6979(args.ContainerId.ToMessage().Value)
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await service.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -102,7 +102,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
Verifier.CheckResponse(response);
}
- private GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders)
+ private static GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders, Context ctx)
{
var request = new GetRequest
{
@@ -113,7 +113,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
};
request.AddMetaHeader(xHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
return request;
}
@@ -126,7 +126,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
private async Task WaitForContainer(WaitExpects expect, ContainerID id, PrmWait? waitParams, Context ctx)
{
- var request = GetContainerRequest(id, null);
+ var request = GetContainerRequest(id, null, ctx);
async Task action()
{
diff --git a/src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs b/src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs
index e088ba43..60c7e1f5 100644
--- a/src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs
+++ b/src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs
@@ -49,7 +49,7 @@ internal class NetmapServiceProvider : ContextAccessor
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -63,7 +63,7 @@ internal class NetmapServiceProvider : ContextAccessor
var request = new NetworkInfoRequest();
request.AddMetaHeader(null);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -79,7 +79,7 @@ internal class NetmapServiceProvider : ContextAccessor
var request = new NetmapSnapshotRequest();
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
diff --git a/src/FrostFS.SDK.ClientV2/Services/ObjectServiceProvider.cs b/src/FrostFS.SDK.ClientV2/Services/ObjectServiceProvider.cs
index 26ba3e8b..95106b7e 100644
--- a/src/FrostFS.SDK.ClientV2/Services/ObjectServiceProvider.cs
+++ b/src/FrostFS.SDK.ClientV2/Services/ObjectServiceProvider.cs
@@ -46,11 +46,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Head,
- Context.Key.ECDsaKey);
+ ctx.Key);
request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await client!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -80,11 +80,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Get,
- Context.Key.ECDsaKey);
+ ctx.Key);
request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
return await GetObject(request, ctx);
}
@@ -109,10 +109,10 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
request.Body.Address,
ObjectSessionContext.Types.Verb.Delete,
- Context.Key.ECDsaKey);
+ ctx.Key);
request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await client.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -139,11 +139,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
new Address { ContainerId = request.Body.ContainerId },
ObjectSessionContext.Types.Verb.Search,
- Context.Key.ECDsaKey);
+ ctx.Key);
request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var objectsIds = SearchObjects(request, ctx);
@@ -177,7 +177,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
internal async Task PutSingleObjectAsync(PrmSingleObjectPut args)
{
var ctx = args.Context!;
- var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, env);
+ var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
var request = new PutSingleRequest
{
@@ -192,11 +192,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
new Address { ContainerId = grpcObject.Header.ContainerId, ObjectId = grpcObject.ObjectId},
ObjectSessionContext.Types.Verb.Put,
- Context.Key.ECDsaKey);
+ ctx.Key);
request.AddMetaHeader(args.XHeaders, sessionToken);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
var response = await client.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken);
@@ -226,7 +226,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
if (args.MaxObjectSizeCache == 0)
{
- var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings(ctx));
+ var networkSettings = await Context.Client.GetNetworkSettingsAsync(new PrmNetworkSettings() { Context = ctx });
args.MaxObjectSizeCache = (int)networkSettings.MaxObjectSize;
}
@@ -331,7 +331,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
while (objectLimitSize == 0 || sentBytes < objectLimitSize)
{
- // send chanks limited to default or user's settings
+ // send chunks limited to default or user's settings
var bufferSize = objectLimitSize > 0 ?
(int)Math.Min(objectLimitSize - sentBytes, chunkSize)
: chunkSize;
@@ -350,8 +350,8 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
Chunk = ByteString.CopyFrom(chunkBuffer, 0, bytesCount)
}
};
-
- chunkRequest.Sign(Context.Key.ECDsaKey);
+
+ chunkRequest.Sign(ctx.Key);
await stream.Write(chunkRequest);
}
@@ -374,14 +374,14 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
{
var header = args.Header!;
- header.OwnerId = Context.Owner;
- header.Version = Context.Version;
+ header.OwnerId = ctx.OwnerId;
+ header.Version = ctx.Version;
var grpcHeader = header.ToMessage();
if (header.Split != null)
{
- ObjectTools.SetSplitValues(grpcHeader, header.Split, env);
+ ObjectTools.SetSplitValues(grpcHeader, header.Split, ctx);
}
var oid = new ObjectID { Value = grpcHeader.Sha256() };
@@ -402,12 +402,12 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sessionToken.CreateObjectTokenContext(
new Address { ContainerId = grpcHeader.ContainerId, ObjectId = oid },
ObjectSessionContext.Types.Verb.Put,
- Context.Key.ECDsaKey
+ ctx.Key
);
initRequest.AddMetaHeader(args.XHeaders, sessionToken);
- initRequest.Sign(Context.Key.ECDsaKey);
+ initRequest.Sign(ctx.Key);
return await PutObjectInit(initRequest, ctx);
}
diff --git a/src/FrostFS.SDK.ClientV2/Services/SessionServiceProvider.cs b/src/FrostFS.SDK.ClientV2/Services/SessionServiceProvider.cs
index 0bb5499f..104fa4ce 100644
--- a/src/FrostFS.SDK.ClientV2/Services/SessionServiceProvider.cs
+++ b/src/FrostFS.SDK.ClientV2/Services/SessionServiceProvider.cs
@@ -17,17 +17,18 @@ internal class SessionServiceProvider : ContextAccessor
internal async Task CreateSessionAsync(PrmSessionCreate args)
{
+ var ctx = args.Context!;
var request = new CreateRequest
{
Body = new CreateRequest.Types.Body
{
- OwnerId = Context.Owner.ToMessage(),
+ OwnerId = ctx.OwnerId.ToMessage(),
Expiration = args.Expiration
}
};
request.AddMetaHeader(args.XHeaders);
- request.Sign(Context.Key.ECDsaKey);
+ request.Sign(ctx.Key);
return await CreateSession(request, args.Context!);
}
diff --git a/src/FrostFS.SDK.ClientV2/Services/Shared/SessionProvider.cs b/src/FrostFS.SDK.ClientV2/Services/Shared/SessionProvider.cs
index 05e57235..ccfec71a 100644
--- a/src/FrostFS.SDK.ClientV2/Services/Shared/SessionProvider.cs
+++ b/src/FrostFS.SDK.ClientV2/Services/Shared/SessionProvider.cs
@@ -15,7 +15,7 @@ internal class SessionProvider(ClientEnvironment env)
{
if (args.SessionToken is null)
{
- return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue, ctx));
+ return await env.Client.CreateSessionInternalAsync(new PrmSessionCreate(uint.MaxValue) { Context = ctx });
}
return new Session.SessionToken().Deserialize(args.SessionToken.Token);
diff --git a/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs b/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs
index 4f4fa1bd..ec06eab5 100644
--- a/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs
+++ b/src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs
@@ -1,25 +1,26 @@
using FrostFS.SDK.ModelsV2;
-using Google.Protobuf;
using Grpc.Net.Client;
using System;
using System.Security.Cryptography;
using FrostFS.SDK.Cryptography;
-using System.Buffers;
namespace FrostFS.SDK.ClientV2;
-public class ClientEnvironment(Client client, ECDsa key, OwnerId owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
+public class ClientEnvironment(Client client, ECDsa? key, OwnerId? owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
{
private ArrayPool _arrayPool;
- internal OwnerId Owner { get; } = owner;
+ internal OwnerId? Owner { get; } = owner;
+
internal GrpcChannel Channel { get; private set; } = channel;
+
internal ModelsV2.Version Version { get; } = version;
+
internal NetworkSettings? NetworkSettings { get; set; }
internal Client Client { get; } = client;
- internal ClientKey Key { get; } = new ClientKey(key);
+ internal ClientKey? Key { get; } = key != null ? new ClientKey(key) : null;
///
/// Custom pool is used for predefined sizes of buffers like grpc chunk
diff --git a/src/FrostFS.SDK.ClientV2/Tools/ObjectTools.cs b/src/FrostFS.SDK.ClientV2/Tools/ObjectTools.cs
index aad073b6..321724a0 100644
--- a/src/FrostFS.SDK.ClientV2/Tools/ObjectTools.cs
+++ b/src/FrostFS.SDK.ClientV2/Tools/ObjectTools.cs
@@ -7,26 +7,25 @@ using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
-using static FrostFS.Object.Header.Types;
namespace FrostFS.SDK.ClientV2;
internal class ObjectTools
{
- internal static ObjectId CalculateObjectId(ObjectHeader header, ClientEnvironment env)
+ internal static ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
{
- var grpcHeader = CreateHeader(header, [], env);
+ var grpcHeader = CreateHeader(header, [], ctx);
if (header.Split != null)
- SetSplitValues(grpcHeader, header.Split, env);
+ SetSplitValues(grpcHeader, header.Split, ctx);
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
}
- internal static Object.Object CreateObject(FrostFsObject @object, ClientEnvironment env)
+ internal static Object.Object CreateObject(FrostFsObject @object, Context ctx)
{
- @object.Header.OwnerId = env.Owner;
- @object.Header.Version = env.Version;
+ @object.Header.OwnerId = ctx.OwnerId;
+ @object.Header.Version = ctx.Version;
var grpcHeader = @object.Header.ToMessage();
@@ -36,7 +35,7 @@ internal class ObjectTools
var split = @object.Header.Split;
if (split != null)
{
- SetSplitValues(grpcHeader, split, env);
+ SetSplitValues(grpcHeader, split, ctx);
}
var obj = new Object.Object
@@ -48,14 +47,14 @@ internal class ObjectTools
obj.Signature = new Refs.Signature
{
- Key = env.Key.PublicKeyProto,
- Sign = ByteString.CopyFrom(env.Key.ECDsaKey.SignData(obj.ObjectId.ToByteArray())),
+ Key = ctx.PublicKeyCache,
+ Sign = ByteString.CopyFrom(ctx.Key.SignData(obj.ObjectId.ToByteArray())),
};
return obj;
}
- internal static void SetSplitValues(Header grpcHeader, ModelsV2.Split split, ClientEnvironment env)
+ internal static void SetSplitValues(Header grpcHeader, ModelsV2.Split split, Context ctx)
{
grpcHeader.Split = new Header.Types.Split
{
@@ -67,14 +66,14 @@ internal class ObjectTools
if (split.ParentHeader is not null)
{
- var grpcParentHeader = CreateHeader(split.ParentHeader, [], env);
+ var grpcParentHeader = CreateHeader(split.ParentHeader, [], ctx);
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
grpcHeader.Split.ParentHeader = grpcParentHeader;
grpcHeader.Split.ParentSignature = new Refs.Signature
{
- Key = env.Key.PublicKeyProto,
- Sign = ByteString.CopyFrom(env.Key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray())),
+ Key = ctx.PublicKeyCache,
+ Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
};
split.Parent = grpcHeader.Split.Parent.ToModel();
@@ -83,12 +82,12 @@ internal class ObjectTools
grpcHeader.Split.Previous = split.Previous?.ToMessage();
}
- internal static Header CreateHeader(ObjectHeader header, byte[]? payload, ClientEnvironment env)
+ internal static Header CreateHeader(ObjectHeader header, byte[]? payload, Context ctx)
{
var grpcHeader = header.ToMessage();
- grpcHeader.OwnerId = env.Owner.ToMessage();
- grpcHeader.Version = env.Version.ToMessage();
+ grpcHeader.OwnerId = ctx.OwnerId.ToMessage();
+ grpcHeader.Version = ctx.Version.ToMessage();
if (payload != null) // && payload.Length > 0
grpcHeader.PayloadHash = Sha256Checksum(payload);
diff --git a/src/FrostFS.SDK.ModelsV2/Client/ClientSettings.cs b/src/FrostFS.SDK.ModelsV2/Client/ClientSettings.cs
index 4268d531..049d3f74 100644
--- a/src/FrostFS.SDK.ModelsV2/Client/ClientSettings.cs
+++ b/src/FrostFS.SDK.ModelsV2/Client/ClientSettings.cs
@@ -1,28 +1,64 @@
+using Google.Protobuf;
using System;
+using System.Collections.Generic;
using System.Text;
namespace FrostFS.SDK.ModelsV2;
public class ClientSettings
{
- private static readonly string errorTemplate = "{0} is required parameter";
-
- public string Key { get; set; } = string.Empty;
+ protected static readonly string errorTemplate = "{0} is required parameter";
public string Host { get; set; } = string.Empty;
- public void Validate()
+ public virtual void Validate()
{
- StringBuilder? error = null;
-
- if (string.IsNullOrWhiteSpace(Key))
- (error ??= new StringBuilder()).AppendLine(string.Format(errorTemplate, nameof(Key)));
-
- if (string.IsNullOrWhiteSpace(Host))
- (error ??= new StringBuilder()).AppendLine(string.Format(errorTemplate, nameof(Host)));
-
- if (error != null)
- throw new ArgumentException(error.ToString());
+ var errors = CheckFields();
+ if (errors != null)
+ ThrowException(errors);
}
+ protected List? CheckFields()
+ {
+ List? errors = null;
+
+ if (string.IsNullOrWhiteSpace(Host))
+ (errors ??= []).Add(string.Format(errorTemplate, nameof(Host)));
+
+ return errors;
+ }
+
+ protected static void ThrowException(List errors)
+ {
+ StringBuilder messages = new();
+
+ foreach (var error in errors)
+ {
+ messages.AppendLine(error);
+ }
+
+ throw new ArgumentException(messages.ToString());
+ }
+}
+
+public class SingleOwnerClientSettings : ClientSettings
+{
+ public string Key { get; set; } = string.Empty;
+
+ public override void Validate()
+ {
+ var errors = CheckFields();
+ if (errors != null)
+ ThrowException(errors);
+ }
+
+ protected List? CheckFields()
+ {
+ List? errors = base.CheckFields();
+
+ if (string.IsNullOrWhiteSpace(Key))
+ (errors ??= []).Add(string.Format(errorTemplate, nameof(Key)));
+
+ return errors;
+ }
}
\ No newline at end of file
diff --git a/src/FrostFS.SDK.Tests/ContainerTest.cs b/src/FrostFS.SDK.Tests/ContainerTest.cs
index 74f80e37..0af0e705 100644
--- a/src/FrostFS.SDK.Tests/ContainerTest.cs
+++ b/src/FrostFS.SDK.Tests/ContainerTest.cs
@@ -16,12 +16,12 @@ public abstract class ContainerTestsBase
{
protected 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 ClientSettings
+ Settings = Options.Create(new SingleOwnerClientSettings
{
Key = key,
Host = "http://localhost:8080"
diff --git a/src/FrostFS.SDK.Tests/ObjectTest.cs b/src/FrostFS.SDK.Tests/ObjectTest.cs
index 6fb3f0a2..30ec8f07 100644
--- a/src/FrostFS.SDK.Tests/ObjectTest.cs
+++ b/src/FrostFS.SDK.Tests/ObjectTest.cs
@@ -19,7 +19,7 @@ public abstract class ObjectTestsBase
{
protected static readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- protected IOptions Settings { get; set; }
+ protected IOptions Settings { get; set; }
protected ContainerId ContainerId { get; set; }
protected NetworkMocker NetworkMocker { get; set; } = new NetworkMocker(key);
@@ -31,7 +31,7 @@ public abstract class ObjectTestsBase
{
var ecdsaKey = key.LoadWif();
- Settings = Options.Create(new ClientSettings
+ Settings = Options.Create(new SingleOwnerClientSettings
{
Key = key,
Host = "http://localhost:8080"
@@ -71,14 +71,17 @@ public class ObjectTest : ObjectTestsBase
public async void GetObjectTest()
{
var client = GetClient();
- var objectId = client.CalculateObjectId(Mocker.ObjectHeader!);
- var context = new Context
- {
- Timeout = TimeSpan.FromSeconds(2)
- };
+ var ecdsaKey = key.LoadWif();
- var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = context });
+ var ctx = new Context {
+ Key = ecdsaKey,
+ OwnerId = OwnerId.FromKey(ecdsaKey),
+ Version = new ModelsV2.Version(2, 13) };
+
+ var objectId = client.CalculateObjectId(Mocker.ObjectHeader!, ctx);
+
+ var result = await client.GetObjectAsync(new PrmObjectGet(ContainerId, objectId) { Context = ctx });
Assert.NotNull(result);
diff --git a/src/FrostFS.SDK.Tests/SmokeTests.cs b/src/FrostFS.SDK.Tests/SmokeTests.cs
index 8b89531e..aff3298b 100644
--- a/src/FrostFS.SDK.Tests/SmokeTests.cs
+++ b/src/FrostFS.SDK.Tests/SmokeTests.cs
@@ -13,21 +13,46 @@ using System.Diagnostics;
using static FrostFS.Session.SessionToken.Types.Body;
using FrostFS.SDK.ClientV2.Parameters;
+using FrostFS.SDK.Tests;
namespace FrostFS.SDK.SmokeTests;
-public class SmokeTests
+public abstract class SmokeTestsBase
+{
+ protected readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
+ protected readonly string url = "http://172.23.32.4:8080";
+
+ protected ECDsa Key { get; }
+
+ protected OwnerId OwnerId { get; }
+
+ protected ModelsV2.Version Version { get; }
+
+ protected Context Ctx { get; }
+
+ protected SmokeTestsBase()
+ {
+ Key = key.LoadWif();
+ OwnerId = OwnerId.FromKey(Key);
+ Version = new ModelsV2.Version(2, 13);
+
+ Ctx = new Context { Key = Key, OwnerId = OwnerId, Version = Version };
+ }
+}
+
+public class SmokeTests : SmokeTestsBase
{
private static readonly PrmWait lightWait = new (100, 1);
- private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
- private readonly string url = "http://172.23.32.4:8080";
-
- [Fact]
- public async void NetworkMapTest()
- {
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
- var result = await client.GetNetmapSnapshotAsync();
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async void NetworkMapTest(bool isSingleOnwerClient)
+ {
+ using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
+
+ PrmNetmapSnapshot? prm = isSingleOnwerClient ? default : new () { Context = Ctx };
+ var result = await client.GetNetmapSnapshotAsync(prm);
Assert.True(result.Epoch > 0);
Assert.Single(result.NodeInfoCollection);
@@ -41,12 +66,17 @@ public class SmokeTests
Assert.Equal(9, item.Attributes.Count);
}
- [Fact]
- public async void NodeInfoTest()
- {
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
- var result = await client.GetNodeInfoAsync();
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async void NodeInfoTest(bool isSingleOnwerClient)
+ {
+ using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
+
+ PrmNodeInfo? prm = isSingleOnwerClient ? default : new() { Context = Ctx };
+
+ var result = await client.GetNodeInfoAsync(prm);
Assert.Equal(2, result.Version.Major);
Assert.Equal(13, result.Version.Minor);
@@ -64,25 +94,25 @@ public class SmokeTests
Callback = (cs) => Console.WriteLine($"{cs.MethodName} took {cs.ElapsedMicroSeconds} microseconds")
};
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
var result = await client.GetNodeInfoAsync();
}
- [Fact]
- public async void GetSessionTest()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async void GetSessionTest(bool isSingleOnwerClient)
{
- var ecdsaKey = this.key.LoadWif();
+ using var client = isSingleOnwerClient ? Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url)) : Client.GetInstance(GetOptions(this.url));
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ PrmSessionCreate? prm = isSingleOnwerClient ? new PrmSessionCreate(100) : new PrmSessionCreate(100) { Context = Ctx };
- var token = await client.CreateSessionAsync(new PrmSessionCreate(100));
+ var token = await client.CreateSessionAsync(prm);
var session = new Session.SessionToken().Deserialize(token.Token);
- var owner = OwnerId.FromKey(ecdsaKey);
-
- var ownerHash = Base58.Decode(owner.Value);
+ var ownerHash = Base58.Decode(OwnerId.Value);
Assert.NotNull(session);
Assert.Null(session.Body.Container);
@@ -97,7 +127,7 @@ public class SmokeTests
[Fact]
public async void CreateObjectWithSessionToken()
{
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
await Cleanup(client);
@@ -144,7 +174,7 @@ public class SmokeTests
[Fact]
public async void FilterTest()
{
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
await Cleanup(client);
@@ -230,7 +260,7 @@ public class SmokeTests
[InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioTest(int objectSize)
{
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
await Cleanup(client);
@@ -253,7 +283,7 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam);
- var container = await client.GetContainerAsync(new PrmContainerGet(containerId,ctx));
+ var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
Assert.NotNull(container);
Assert.True(callbackInvoked);
@@ -318,7 +348,7 @@ public class SmokeTests
[InlineData(6 * 1024 * 1024 + 100)]
public async void SimpleScenarioWithSessionTest(int objectSize)
{
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
var token = await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue));
@@ -338,7 +368,7 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam);
- var container = await client.GetContainerAsync(new PrmContainerGet(containerId,ctx));
+ var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
Assert.NotNull(container);
var bytes = GetRandomBytes(objectSize);
@@ -406,7 +436,7 @@ public class SmokeTests
[InlineData(200)]
public async void ClientCutScenarioTest(int objectSize)
{
- using var client = Client.GetInstance(GetOptions(this.key, this.url));
+ using var client = Client.GetSingleOwnerInstance(GetSingleOwnerOptions(this.key, this.url));
await Cleanup(client);
@@ -417,13 +447,13 @@ public class SmokeTests
var containerId = await client.CreateContainerAsync(createContainerParam);
- var context = new Context
+ var ctx = new Context
{
Timeout = TimeSpan.FromSeconds(10),
Interceptors = new([new MetricsInterceptor()])
};
- var container = await client.GetContainerAsync(new PrmContainerGet(containerId, context));
+ var container = await client.GetContainerAsync(new PrmContainerGet(containerId) { Context = ctx });
Assert.NotNull(container);
@@ -499,11 +529,19 @@ public class SmokeTests
return bytes;
}
- private static IOptions GetOptions(string key, string url)
+ private static IOptions GetSingleOwnerOptions(string key, string url)
+ {
+ return Options.Create(new SingleOwnerClientSettings
+ {
+ Key = key,
+ Host = url
+ });
+ }
+
+ private static IOptions GetOptions(string url)
{
return Options.Create(new ClientSettings
{
- Key = key,
Host = url
});
}