[#10] Netmap snapshot, options, metrics #11
84 changed files with 2238 additions and 933 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -18,6 +18,7 @@ vendor/
|
|||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
.vs
|
||||
|
||||
# coverage
|
||||
coverage.txt
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
#
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion =
|
||||
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ClientV2", "src\FrostFS.SDK.ClientV2\FrostFS.SDK.ClientV2.csproj", "{50D8F61F-C302-4AC9-8D8A-AB0B8C0988C3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Cryptography", "src\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj", "{3D804F4A-B0B2-47A5-B006-BE447BE64B50}"
|
||||
|
@ -10,6 +10,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ModelsV2", "src
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ProtosV2", "src\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj", "{5012EF96-9C9E-4E77-BC78-B4111EE54107}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -32,8 +34,9 @@ Global
|
|||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{8FDA7E0D-9C75-4874-988E-6592CD28F76C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
@ -1,93 +1,223 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FrostFS.Container;
|
||||
using FrostFS.Container;
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.ClientV2.Interfaces;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using FrostFS.Session;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using static FrostFS.Netmap.NetworkConfig.Types;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Version = FrostFS.SDK.ModelsV2.Version;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public partial class Client: IFrostFSClient
|
||||
public class Client : IFrostFSClient
|
||||
{
|
||||
private GrpcChannel? _channel;
|
||||
private readonly ECDsa _key;
|
||||
public readonly OwnerId OwnerId;
|
||||
public readonly Version Version = new(2, 13);
|
||||
private bool isDisposed;
|
||||
|
||||
private readonly Dictionary<string, ulong> NetworkSettings = [];
|
||||
internal ClientEnvironment ClientCtx { get; set; }
|
||||
|
||||
private ContainerService.ContainerServiceClient? _containerServiceClient;
|
||||
private NetmapService.NetmapServiceClient? _netmapServiceClient;
|
||||
private ObjectService.ObjectServiceClient? _objectServiceClient;
|
||||
private SessionService.SessionServiceClient? _sessionServiceClient;
|
||||
|
||||
public static IFrostFSClient GetInstance(string key, string host)
|
||||
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions channelOptions)
|
||||
{
|
||||
return new Client(key, host);
|
||||
return new Client(clientOptions, channelOptions);
|
||||
}
|
||||
|
||||
private Client(string key, string host)
|
||||
/// <summary>
|
||||
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
|
||||
/// </summary>
|
||||
/// <param name="clientOptions">Global setting for client</param>
|
||||
/// <param name="channelOptions">Setting for gRPC cjannel</param>
|
||||
/// <param name="containerService">ContainerService.ContainerServiceClient implementation</param>
|
||||
/// <param name="netmapService">Netmap.NetmapService.NetmapServiceClient implementation</param>
|
||||
/// <param name="sessionService">Session.SessionService.SessionServiceClient implementation</param>
|
||||
/// <param name="objectService">Object.ObjectService.ObjectServiceClient implementation</param>
|
||||
/// <returns></returns>
|
||||
public static IFrostFSClient GetTestInstance(
|
||||
IOptions<ClientSettings> clientOptions,
|
||||
GrpcChannelOptions? channelOptions,
|
||||
NetmapService.NetmapServiceClient netmapService,
|
||||
SessionService.SessionServiceClient sessionService,
|
||||
ContainerService.ContainerServiceClient containerService,
|
||||
ObjectService.ObjectServiceClient objectService)
|
||||
{
|
||||
// TODO: Развязать клиент и реализацию GRPC
|
||||
_key = key.LoadWif();
|
||||
OwnerId = OwnerId.FromKey(_key);
|
||||
InitGrpcChannel(host);
|
||||
InitContainerClient();
|
||||
InitNetmapClient();
|
||||
InitObjectClient();
|
||||
InitSessionClient();
|
||||
return new Client(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
|
||||
}
|
||||
dstepanov-yadro marked this conversation as resolved
Outdated
|
||||
|
||||
private Client(
|
||||
IOptions<ClientSettings> 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(
|
||||
key: ecdsaKey,
|
||||
owner: OwnerId.FromKey(ecdsaKey),
|
||||
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
|
||||
version: new Version(2, 13));
|
||||
|
||||
ClientCtx.ContainerService = new ContainerServiceProvider(containerService, ClientCtx);
|
||||
ClientCtx.NetmapService = new NetmapServiceProvider(netmapService, ClientCtx);
|
||||
ClientCtx.SessionService = new SessionServiceProvider(sessionService, ClientCtx);
|
||||
ClientCtx.ObjectService = new ObjectServiceProvider(objectService, ClientCtx);
|
||||
}
|
||||
|
||||
private Client(IOptions<ClientSettings> 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);
|
||||
|
||||
ClientCtx = new ClientEnvironment(
|
||||
key: ecdsaKey,
|
||||
owner: OwnerId.FromKey(ecdsaKey),
|
||||
channel: channel,
|
||||
version: new Version(2, 13));
|
||||
|
||||
ClientCtx.ContainerService = new ContainerServiceProvider(new ContainerService.ContainerServiceClient(channel), ClientCtx);
|
||||
ClientCtx.NetmapService = new NetmapServiceProvider(new NetmapService.NetmapServiceClient(channel), ClientCtx);
|
||||
ClientCtx.SessionService = new SessionServiceProvider(new SessionService.SessionServiceClient(channel), ClientCtx);
|
||||
ClientCtx.ObjectService = new ObjectServiceProvider(new ObjectService.ObjectServiceClient(channel), ClientCtx);
|
||||
|
||||
CheckFrostFsVersionSupport();
|
||||
|
||||
InitNetworkInfoAsync();
|
||||
}
|
||||
|
||||
private async void InitNetworkInfoAsync()
|
||||
public void Dispose()
|
||||
{
|
||||
var info = await GetNetworkInfoAsync();
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
foreach (var param in info.Body.NetworkInfo.NetworkConfig.Parameters)
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && !isDisposed)
|
||||
{
|
||||
SetNetworksParam(param);
|
||||
ClientCtx.Dispose();
|
||||
isDisposed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetNetworksParam(Parameter param)
|
||||
{
|
||||
var key = Encoding.UTF8.GetString(param.Key.ToByteArray());
|
||||
public GrpcChannel Channel => ClientCtx.Channel;
|
||||
|
||||
var encodedValue = param.Value.ToByteArray();
|
||||
|
||||
ulong val = 0;
|
||||
for (var i = encodedValue.Length - 1; i >= 0; i--)
|
||||
{
|
||||
val = (val << 8) + encodedValue[i];
|
||||
}
|
||||
|
||||
NetworkSettings.Add(key, val);
|
||||
}
|
||||
|
||||
private async void CheckFrostFsVersionSupport()
|
||||
public Task<ModelsV2.Container> GetContainerAsync(ContainerId containerId, Context? ctx = null)
|
||||
{
|
||||
var localNodeInfo = await GetLocalNodeInfoAsync();
|
||||
if (!localNodeInfo.Version.IsSupported(Version))
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ContainerService!.GetContainerAsync(containerId, ctx!);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<ContainerId> ListContainersAsync(Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ContainerService!.ListContainersAsync(ctx!);
|
||||
}
|
||||
|
||||
public Task<ContainerId> CreateContainerAsync(ModelsV2.Container container, Context? ctx = null)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ContainerService!.CreateContainerAsync(container, ctx!);
|
||||
}
|
||||
|
||||
public Task DeleteContainerAsync(ContainerId containerId, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ContainerService!.DeleteContainerAsync(containerId, ctx!);
|
||||
}
|
||||
|
||||
public Task<NetmapSnapshot> GetNetmapSnapshotAsync(Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.NetmapService!.GetNetmapSnapshotAsync(ctx!);
|
||||
}
|
||||
|
||||
public Task<ModelsV2.Netmap.NodeInfo> GetNodeInfoAsync(Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.NetmapService!.GetLocalNodeInfoAsync(ctx!);
|
||||
}
|
||||
|
||||
public Task<ObjectHeader> GetObjectHeadAsync(ContainerId containerId, ObjectId objectId, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.GetObjectHeadAsync(containerId, objectId, ctx!);
|
||||
}
|
||||
|
||||
public Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.GetObjectAsync(containerId, objectId, ctx!);
|
||||
}
|
||||
|
||||
public Task<ObjectId> PutObjectAsync(PutObjectParameters putObjectParameters, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.PutObjectAsync(putObjectParameters, ctx!);
|
||||
}
|
||||
|
||||
public Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object obj, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.PutSingleObjectAsync(obj, ctx!);
|
||||
}
|
||||
|
||||
public Task DeleteObjectAsync(ContainerId containerId, ObjectId objectId, Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.DeleteObjectAsync(containerId, objectId, ctx!);
|
||||
}
|
||||
|
||||
public IAsyncEnumerable<ObjectId> SearchObjectsAsync(
|
||||
ContainerId containerId,
|
||||
IEnumerable<ObjectFilter> filters,
|
||||
Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
return ClientCtx.ObjectService!.SearchObjectsAsync(containerId, filters, ctx!);
|
||||
}
|
||||
|
||||
public ObjectId CalculateObjectId(ObjectHeader header)
|
||||
{
|
||||
return ClientCtx.ObjectService!.CalculateObjectId(header);
|
||||
}
|
||||
|
||||
private async void CheckFrostFsVersionSupport(Context? ctx = default)
|
||||
{
|
||||
ValidateEnvironment(ref ctx);
|
||||
var localNodeInfo = await ClientCtx.NetmapService!.GetLocalNodeInfoAsync(ctx!);
|
||||
|
||||
if (!localNodeInfo.Version.IsSupported(ClientCtx.Version))
|
||||
{
|
||||
var msg = $"FrostFS {localNodeInfo.Version} is not supported.";
|
||||
Console.WriteLine(msg);
|
||||
throw new ApplicationException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private void InitGrpcChannel(string host)
|
||||
|
||||
private void ValidateEnvironment(ref Context? ctx)
|
||||
{
|
||||
if (isDisposed)
|
||||
throw new Exception("Client is disposed.");
|
||||
|
||||
if (ClientCtx == null || !ClientCtx.Initialized)
|
||||
throw new Exception("Client is not initialized.");
|
||||
|
||||
ctx ??= new Context();
|
||||
}
|
||||
|
||||
private static GrpcChannel InitGrpcChannel(string host, GrpcChannelOptions? channelOptions)
|
||||
{
|
||||
Uri uri;
|
||||
try
|
||||
|
@ -97,49 +227,25 @@ public partial class Client: IFrostFSClient
|
|||
catch (UriFormatException e)
|
||||
{
|
||||
var msg = $"Host '{host}' has invalid format. Error: {e.Message}";
|
||||
Console.WriteLine(msg);
|
||||
throw new ArgumentException(msg);
|
||||
}
|
||||
|
||||
ChannelCredentials grpcCredentials;
|
||||
switch (uri.Scheme)
|
||||
ChannelCredentials grpcCredentials = uri.Scheme switch
|
||||
{
|
||||
case "https":
|
||||
grpcCredentials = ChannelCredentials.SecureSsl;
|
||||
break;
|
||||
case "http":
|
||||
grpcCredentials = ChannelCredentials.Insecure;
|
||||
break;
|
||||
default:
|
||||
var msg = $"Host '{host}' has invalid URI scheme: '{uri.Scheme}'.";
|
||||
Console.WriteLine(msg);
|
||||
throw new ArgumentException(msg);
|
||||
"https" => ChannelCredentials.SecureSsl,
|
||||
"http" => ChannelCredentials.Insecure,
|
||||
_ => throw new ArgumentException($"Host '{host}' has invalid URI scheme: '{uri.Scheme}'.")
|
||||
};
|
||||
|
||||
if (channelOptions != null)
|
||||
{
|
||||
return GrpcChannel.ForAddress(uri, channelOptions);
|
||||
}
|
||||
|
||||
_channel = GrpcChannel.ForAddress(uri, new GrpcChannelOptions
|
||||
{
|
||||
Credentials = grpcCredentials,
|
||||
HttpHandler = new System.Net.Http.HttpClientHandler()
|
||||
});
|
||||
}
|
||||
|
||||
private void InitContainerClient()
|
||||
{
|
||||
_containerServiceClient = new ContainerService.ContainerServiceClient(_channel);
|
||||
}
|
||||
|
||||
private void InitNetmapClient()
|
||||
{
|
||||
_netmapServiceClient = new NetmapService.NetmapServiceClient(_channel);
|
||||
}
|
||||
|
||||
private void InitObjectClient()
|
||||
{
|
||||
_objectServiceClient = new ObjectService.ObjectServiceClient(_channel);
|
||||
}
|
||||
|
||||
private void InitSessionClient()
|
||||
{
|
||||
_sessionServiceClient = new SessionService.SessionServiceClient(_channel);
|
||||
|
||||
return GrpcChannel.ForAddress(uri, new GrpcChannelOptions
|
||||
{
|
||||
Credentials = grpcCredentials,
|
||||
HttpHandler = new HttpClientHandler()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,14 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
|
||||
<PackageReference Include="Moq.AutoMock" Version="3.5.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
dstepanov-yadro marked this conversation as resolved
Outdated
dstepanov-yadro
commented
Why cross-platform SDK have Windows dependency? Why cross-platform SDK have Windows dependency?
PavelGrossSpb
commented
Right. These are some artefacts from my research. Wrong references have been removed. Right. These are some artefacts from my research. Wrong references have been removed.
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,34 +1,41 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using Grpc.Net.Client;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Interfaces;
|
||||
|
||||
public interface IFrostFSClient
|
||||
public interface IFrostFSClient : IDisposable
|
||||
{
|
||||
Task<ModelsV2.Container> GetContainerAsync(ContainerId containerId);
|
||||
Task<ModelsV2.Container> GetContainerAsync(ContainerId containerId, Context? context = default);
|
||||
|
||||
IAsyncEnumerable<ContainerId> ListContainersAsync();
|
||||
IAsyncEnumerable<ContainerId> ListContainersAsync(Context? context = default);
|
||||
|
||||
Task<ContainerId> CreateContainerAsync(ModelsV2.Container container);
|
||||
Task<ContainerId> CreateContainerAsync(ModelsV2.Container container, Context? context = default);
|
||||
|
||||
Task DeleteContainerAsync(ContainerId containerId);
|
||||
Task DeleteContainerAsync(ContainerId containerId, Context? context = default);
|
||||
|
||||
Task<ObjectHeader> GetObjectHeadAsync(ContainerId containerId, ObjectId objectId);
|
||||
Task<ObjectHeader> GetObjectHeadAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
Task<ModelsV2.Object> GetObjectAsync(ContainerId containerId, ObjectId objectId);
|
||||
Task<ObjectId> PutObjectAsync(PutObjectParameters putObjectParameters, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object obj, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutObjectAsync(ObjectHeader header, Stream payload, CancellationToken cancellationToken = default);
|
||||
Task DeleteObjectAsync(ContainerId containerId, ObjectId objectId, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutObjectAsync(ObjectHeader header, byte[] payload, CancellationToken cancellationToken = default);
|
||||
IAsyncEnumerable<ObjectId> SearchObjectsAsync(ContainerId cid, IEnumerable<ObjectFilter> filters, Context? context = default);
|
||||
|
||||
Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object obj, CancellationToken cancellationToken = default);
|
||||
Task<NetmapSnapshot> GetNetmapSnapshotAsync(Context? context = default);
|
||||
|
||||
Task DeleteObjectAsync(ContainerId containerId, ObjectId objectId);
|
||||
Task<NodeInfo> GetNodeInfoAsync(Context? context = default);
|
||||
|
||||
ObjectId CalculateObjectId(ObjectHeader header);
|
||||
|
||||
GrpcChannel Channel { get; }
|
||||
}
|
||||
|
||||
IAsyncEnumerable<ObjectId> SearchObjectsAsync(ContainerId cid, params ObjectFilter[] filters);
|
||||
}
|
|
@ -22,19 +22,15 @@ public static class ContainerMapper
|
|||
|
||||
public static ModelsV2.Container ToModel(this Container.Container container)
|
||||
{
|
||||
var basicAclName = Enum.GetName(typeof(BasicAcl), container.BasicAcl);
|
||||
if (basicAclName is null)
|
||||
{
|
||||
if (!Enum.IsDefined(typeof(BasicAcl),(int)container.BasicAcl))
|
||||
throw new ArgumentException($"Unknown BasicACL rule. Value: '{container.BasicAcl}'.");
|
||||
}
|
||||
|
||||
BasicAcl acl = (BasicAcl)container.BasicAcl;
|
||||
|
||||
return new ModelsV2.Container(
|
||||
(BasicAcl)Enum.Parse(typeof(BasicAcl), basicAclName),
|
||||
container.PlacementPolicy.ToModel()
|
||||
)
|
||||
return new ModelsV2.Container(acl, container.PlacementPolicy.ToModel())
|
||||
{
|
||||
Nonce = container.Nonce.ToUuid(),
|
||||
Version = container.Version.ToModel()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
|
||||
public static class NodeInfoMapper
|
||||
{
|
||||
public static NodeInfo ToModel(this LocalNodeInfoResponse.Types.Body nodeInfo)
|
||||
{
|
||||
var nodeStateName = Enum.GetName(typeof(NodeState), nodeInfo.NodeInfo.State);
|
||||
if (nodeStateName is null)
|
||||
{
|
||||
throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.NodeInfo.State}'.");
|
||||
}
|
||||
return new NodeInfo
|
||||
{
|
||||
State = (NodeState)Enum.Parse(typeof(NodeState), nodeStateName),
|
||||
Version = nodeInfo.Version.ToModel()
|
||||
};
|
||||
}
|
||||
}
|
15
src/FrostFS.SDK.ClientV2/Mappers/Netmap/Netmap.cs
Normal file
15
src/FrostFS.SDK.ClientV2/Mappers/Netmap/Netmap.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.Linq;
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
|
||||
public static class NetmapMapper
|
||||
{
|
||||
public static NetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
|
||||
{
|
||||
return new NetmapSnapshot(
|
||||
netmap.Body.Netmap.Epoch,
|
||||
netmap.Body.Netmap.Nodes.Select(n => n.ToModel(netmap.MetaHeader.Version)).ToArray());
|
||||
}
|
||||
}
|
35
src/FrostFS.SDK.ClientV2/Mappers/Netmap/NodeInfo.cs
Normal file
35
src/FrostFS.SDK.ClientV2/Mappers/Netmap/NodeInfo.cs
Normal file
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
|
||||
public static class NodeInfoMapper
|
||||
{
|
||||
public static NodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
|
||||
{
|
||||
return node.NodeInfo.ToModel(node.Version);
|
||||
}
|
||||
|
||||
public static NodeInfo ToModel(this FrostFS.Netmap.NodeInfo nodeInfo, Refs.Version version)
|
||||
{
|
||||
NodeState state = nodeInfo.State switch
|
||||
{
|
||||
FrostFS.Netmap.NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
|
||||
FrostFS.Netmap.NodeInfo.Types.State.Online => NodeState.Online,
|
||||
FrostFS.Netmap.NodeInfo.Types.State.Offline => NodeState.Offline,
|
||||
FrostFS.Netmap.NodeInfo.Types.State.Maintenance => NodeState.Maintenance,
|
||||
_ => throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.State}'.")
|
||||
};
|
||||
|
||||
return new NodeInfo(
|
||||
version: version.ToModel(),
|
||||
state: state,
|
||||
addresses: [.. nodeInfo.Addresses],
|
||||
attributes: nodeInfo.Attributes.ToDictionary(n => n.Key, n => n.Value),
|
||||
publicKey: nodeInfo.PublicKey.ToByteArray()
|
||||
);
|
||||
}
|
||||
}
|
14
src/FrostFS.SDK.ClientV2/Mappers/Object/Object.cs
Normal file
14
src/FrostFS.SDK.ClientV2/Mappers/Object/Object.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class ObjectMapper
|
||||
{
|
||||
public static ModelsV2.Object ToModel(this Object.Object obj)
|
||||
{
|
||||
return new ModelsV2.Object(
|
||||
ObjectId.FromHash(obj.ObjectId.Value.ToByteArray()),
|
||||
obj.Header.ToModel(),
|
||||
obj.Payload.ToByteArray());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using FrostFS.Object;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class ObjectAttributeMapper
|
||||
{
|
||||
public static Header.Types.Attribute ToGrpcMessage(this ObjectAttribute attribute)
|
||||
{
|
||||
return new Header.Types.Attribute
|
||||
{
|
||||
Key = attribute.Key,
|
||||
Value = attribute.Value
|
||||
};
|
||||
}
|
||||
|
||||
public static ObjectAttribute ToModel(this Header.Types.Attribute attribute)
|
||||
{
|
||||
return new ObjectAttribute(attribute.Key, attribute.Value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
using FrostFS.Object;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using MatchType = FrostFS.Object.MatchType;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class ObjectFilterMapper
|
||||
{
|
||||
public static SearchRequest.Types.Body.Types.Filter ToGrpcMessage(this ObjectFilter filter)
|
||||
{
|
||||
var objMatchTypeName = filter.MatchType switch
|
||||
{
|
||||
ModelsV2.Enums.ObjectMatchType.Unspecified => MatchType.Unspecified,
|
||||
ModelsV2.Enums.ObjectMatchType.Equals => MatchType.StringEqual,
|
||||
ModelsV2.Enums.ObjectMatchType.NotEquals => MatchType.StringNotEqual,
|
||||
ModelsV2.Enums.ObjectMatchType.KeyAbsent => MatchType.NotPresent,
|
||||
ModelsV2.Enums.ObjectMatchType.StartsWith => MatchType.CommonPrefix,
|
||||
|
||||
_ => throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.")
|
||||
};
|
||||
|
||||
return new SearchRequest.Types.Body.Types.Filter
|
||||
{
|
||||
MatchType = objMatchTypeName,
|
||||
Key = filter.Key,
|
||||
Value = filter.Value
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,52 +4,10 @@ using FrostFS.Object;
|
|||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using Google.Protobuf;
|
||||
using MatchType = FrostFS.Object.MatchType;
|
||||
using ObjectType = FrostFS.Object.ObjectType;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class ObjectAttributeMapper
|
||||
{
|
||||
public static Header.Types.Attribute ToGrpcMessage(this ObjectAttribute attribute)
|
||||
{
|
||||
return new Header.Types.Attribute
|
||||
{
|
||||
Key = attribute.Key,
|
||||
Value = attribute.Value
|
||||
};
|
||||
}
|
||||
|
||||
public static ObjectAttribute ToModel(this Header.Types.Attribute attribute)
|
||||
{
|
||||
return new ObjectAttribute(attribute.Key, attribute.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectFilterMapper
|
||||
{
|
||||
public static SearchRequest.Types.Body.Types.Filter ToGrpcMessage(this ObjectFilter filter)
|
||||
{
|
||||
var objMatchTypeName = filter.MatchType switch
|
||||
{
|
||||
ModelsV2.Enums.ObjectMatchType.Unspecified => MatchType.Unspecified,
|
||||
ModelsV2.Enums.ObjectMatchType.Equals => MatchType.StringEqual,
|
||||
ModelsV2.Enums.ObjectMatchType.NotEquals => MatchType.StringNotEqual,
|
||||
ModelsV2.Enums.ObjectMatchType.KeyAbsent => MatchType.NotPresent,
|
||||
ModelsV2.Enums.ObjectMatchType.StartsWith => MatchType.CommonPrefix,
|
||||
|
||||
_ => throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.")
|
||||
};
|
||||
|
||||
return new SearchRequest.Types.Body.Types.Filter
|
||||
{
|
||||
MatchType = objMatchTypeName,
|
||||
Key = filter.Key,
|
||||
Value = filter.Value
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectHeaderMapper
|
||||
{
|
||||
public static Header ToGrpcMessage(this ObjectHeader header)
|
||||
|
@ -116,7 +74,7 @@ public static class ObjectHeaderMapper
|
|||
|
||||
if (header.Split != null)
|
||||
{
|
||||
model.Split = new Split(SplitId.CrateFromBinary(header.Split.SplitId.ToByteArray()))
|
||||
model.Split = new Split(SplitId.CreateFromBinary(header.Split.SplitId.ToByteArray()))
|
||||
{
|
||||
Parent = header.Split.Parent?.ToModel(),
|
||||
ParentHeader = header.Split.ParentHeader?.ToModel(),
|
||||
|
@ -130,37 +88,3 @@ public static class ObjectHeaderMapper
|
|||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ObjectMapper
|
||||
{
|
||||
public static ModelsV2.Object ToModel(this Object.Object obj)
|
||||
{
|
||||
return new ModelsV2.Object()
|
||||
{
|
||||
Header = obj.Header.ToModel(),
|
||||
ObjectId = ObjectId.FromHash(obj.ObjectId.Value.ToByteArray()),
|
||||
Payload = obj.Payload.ToByteArray()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignatureMapper
|
||||
{
|
||||
public static Refs.Signature ToGrpcMessage(this Signature signature)
|
||||
{
|
||||
var scheme = signature.Scheme switch
|
||||
{
|
||||
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
|
||||
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
|
||||
_ => throw new ArgumentException(message: $"Unexpected enum value: {signature.Scheme}", paramName: nameof(signature.Scheme))
|
||||
};
|
||||
|
||||
return new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(signature.Key),
|
||||
Scheme = scheme,
|
||||
Sign = ByteString.CopyFrom(signature.Sign)
|
||||
};
|
||||
}
|
||||
}
|
25
src/FrostFS.SDK.ClientV2/Mappers/Session/Session.cs
Normal file
25
src/FrostFS.SDK.ClientV2/Mappers/Session/Session.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
|
||||
using System;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class SessionMapper
|
||||
{
|
||||
internal static string SerializeSessionToken(this Session.SessionToken token)
|
||||
{
|
||||
byte[] bytes = new byte[token.CalculateSize()];
|
||||
CodedOutputStream stream = new(bytes);
|
||||
token.WriteTo(stream);
|
||||
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
internal static Session.SessionToken DeserializeSessionToken(this byte[] bytes)
|
||||
{
|
||||
Session.SessionToken token = new();
|
||||
token.MergeFrom(bytes);
|
||||
|
||||
return token;
|
||||
}
|
||||
}
|
26
src/FrostFS.SDK.ClientV2/Mappers/SignatureMapper.cs
Normal file
26
src/FrostFS.SDK.ClientV2/Mappers/SignatureMapper.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using Google.Protobuf;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
public static class SignatureMapper
|
||||
{
|
||||
public static Refs.Signature ToGrpcMessage(this Signature signature)
|
||||
{
|
||||
var scheme = signature.Scheme switch
|
||||
{
|
||||
SignatureScheme.EcdsaRfc6979Sha256 => Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
SignatureScheme.EcdsaRfc6979Sha256WalletConnect => Refs.SignatureScheme.EcdsaRfc6979Sha256WalletConnect,
|
||||
SignatureScheme.EcdsaSha512 => Refs.SignatureScheme.EcdsaSha512,
|
||||
_ => throw new ArgumentException(message: $"Unexpected enum value: {signature.Scheme}", paramName: nameof(signature.Scheme))
|
||||
};
|
||||
|
||||
return new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(signature.Key),
|
||||
Scheme = scheme,
|
||||
Sign = ByteString.CopyFrom(signature.Sign)
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public partial class Client
|
||||
{
|
||||
public async Task<ModelsV2.Container> GetContainerAsync(ContainerId cid)
|
||||
{
|
||||
var request = new GetRequest
|
||||
{
|
||||
Body = new GetRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage()
|
||||
},
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _containerServiceClient.GetAsync(request);
|
||||
Verifier.CheckResponse(response);
|
||||
return response.Body.Container.ToModel();
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<ContainerId> ListContainersAsync()
|
||||
{
|
||||
var request = new ListRequest
|
||||
{
|
||||
Body = new ListRequest.Types.Body
|
||||
{
|
||||
OwnerId = OwnerId.ToGrpcMessage()
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _containerServiceClient.ListAsync(request);
|
||||
Verifier.CheckResponse(response);
|
||||
foreach (var cid in response.Body.ContainerIds)
|
||||
{
|
||||
yield return new ContainerId(Base58.Encode(cid.Value.ToByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<ContainerId> CreateContainerAsync(ModelsV2.Container container)
|
||||
{
|
||||
var cntnr = container.ToGrpcMessage();
|
||||
cntnr.OwnerId = OwnerId.ToGrpcMessage();
|
||||
cntnr.Version = Version.ToGrpcMessage();
|
||||
|
||||
var request = new PutRequest
|
||||
{
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
Container = cntnr,
|
||||
Signature = _key.SignRFC6979(cntnr),
|
||||
}
|
||||
};
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _containerServiceClient.PutAsync(request);
|
||||
Verifier.CheckResponse(response);
|
||||
return new ContainerId(Base58.Encode(response.Body.ContainerId.Value.ToByteArray()));
|
||||
}
|
||||
|
||||
public async Task DeleteContainerAsync(ContainerId cid)
|
||||
{
|
||||
var request = new DeleteRequest
|
||||
{
|
||||
Body = new DeleteRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
Signature = _key.SignRFC6979(cid.ToGrpcMessage().Value)
|
||||
}
|
||||
};
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _containerServiceClient.DeleteAsync(request);
|
||||
Verifier.CheckResponse(response);
|
||||
}
|
||||
}
|
113
src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs
Normal file
113
src/FrostFS.SDK.ClientV2/Services/ContainerServiceProvider.cs
Normal file
|
@ -0,0 +1,113 @@
|
|||
using System.Threading.Tasks;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.Container;
|
||||
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
internal class ContainerServiceProvider : ContextAccessor
|
||||
{
|
||||
private readonly ContainerService.ContainerServiceClient containerServiceClient;
|
||||
|
||||
internal ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context)
|
||||
: base(context)
|
||||
{
|
||||
containerServiceClient = service;
|
||||
}
|
||||
|
||||
internal async Task<ModelsV2.Container> GetContainerAsync(ContainerId cid, Context context)
|
||||
{
|
||||
var request = new GetRequest
|
||||
{
|
||||
Body = new GetRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage()
|
||||
},
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await containerServiceClient.GetAsync(request, null, context.Deadline, context.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.Body.Container.ToModel();
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<ContainerId> ListContainersAsync(Context ctx)
|
||||
{
|
||||
var request = new ListRequest
|
||||
{
|
||||
Body = new ListRequest.Types.Body
|
||||
{
|
||||
OwnerId = Context.Owner.ToGrpcMessage()
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await containerServiceClient.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
foreach (var cid in response.Body.ContainerIds)
|
||||
{
|
||||
yield return new ContainerId(Base58.Encode(cid.Value.ToByteArray()));
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task<ContainerId> CreateContainerAsync(ModelsV2.Container container, Context ctx)
|
||||
{
|
||||
var grpcContainer = container.ToGrpcMessage();
|
||||
grpcContainer.OwnerId = Context.Owner.ToGrpcMessage();
|
||||
grpcContainer.Version = Context.Version.ToGrpcMessage();
|
||||
|
||||
var request = new PutRequest
|
||||
{
|
||||
Body = new PutRequest.Types.Body
|
||||
{
|
||||
Container = grpcContainer,
|
||||
Signature = Context.Key.SignRFC6979(grpcContainer),
|
||||
}
|
||||
};
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await containerServiceClient.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
//var response = await Context.InvokeAsyncUnaryWithMetrics(() =>
|
||||
// containerServiceClient.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken),
|
||||
// nameof(containerServiceClient.PutAsync));
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return new ContainerId(Base58.Encode(response.Body.ContainerId.Value.ToByteArray()));
|
||||
}
|
||||
|
||||
internal async Task DeleteContainerAsync(ContainerId cid, Context ctx)
|
||||
{
|
||||
var request = new DeleteRequest
|
||||
{
|
||||
Body = new DeleteRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
Signature = Context.Key.SignRFC6979(cid.ToGrpcMessage().Value)
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await containerServiceClient.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
|
||||
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public partial class Client
|
||||
{
|
||||
public async Task<NodeInfo> GetLocalNodeInfoAsync()
|
||||
{
|
||||
var request = new LocalNodeInfoRequest
|
||||
{
|
||||
Body = new LocalNodeInfoRequest.Types.Body { }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _netmapServiceClient.LocalNodeInfoAsync(request);
|
||||
|
||||
return response.Body.ToModel();
|
||||
}
|
||||
|
||||
public async Task<NetworkInfoResponse> GetNetworkInfoAsync()
|
||||
{
|
||||
var request = new NetworkInfoRequest
|
||||
{
|
||||
Body = new NetworkInfoRequest.Types.Body { }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
|
||||
return await _netmapServiceClient.NetworkInfoAsync(request);
|
||||
}
|
||||
}
|
132
src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs
Normal file
132
src/FrostFS.SDK.ClientV2/Services/NetmapServiceProvider.cs
Normal file
|
@ -0,0 +1,132 @@
|
|||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FrostFS.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using NodeInfo = FrostFS.SDK.ModelsV2.Netmap.NodeInfo;
|
||||
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using static FrostFS.Netmap.NetworkConfig.Types;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
internal class NetmapServiceProvider : ContextAccessor
|
||||
{
|
||||
private readonly NetmapService.NetmapServiceClient netmapServiceClient;
|
||||
|
||||
internal NetmapServiceProvider(NetmapService.NetmapServiceClient netmapServiceClient, ClientEnvironment context)
|
||||
: base(context)
|
||||
{
|
||||
this.netmapServiceClient = netmapServiceClient;
|
||||
}
|
||||
|
||||
internal async Task<NetworkSettings> GetNetworkSettingsAsync(Context ctx)
|
||||
{
|
||||
if (Context.NetworkSettings != null)
|
||||
return Context.NetworkSettings;
|
||||
|
||||
var info = await GetNetworkInfoAsync(ctx);
|
||||
|
||||
var settings = new NetworkSettings();
|
||||
|
||||
foreach (var param in info.Body.NetworkInfo.NetworkConfig.Parameters)
|
||||
{
|
||||
SetNetworksParam(param, settings);
|
||||
}
|
||||
|
||||
Context.NetworkSettings = settings;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
internal async Task<NodeInfo> GetLocalNodeInfoAsync(Context ctx)
|
||||
{
|
||||
var request = new LocalNodeInfoRequest
|
||||
{
|
||||
Body = new LocalNodeInfoRequest.Types.Body { }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
//var response = await Context.InvokeAsyncUnaryWithMetrics(() =>
|
||||
// netmapServiceClient.LocalNodeInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken),
|
||||
// nameof(netmapServiceClient.LocalNodeInfoAsync));
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.Body.ToModel();
|
||||
}
|
||||
|
||||
internal async Task<NetworkInfoResponse> GetNetworkInfoAsync(Context ctx)
|
||||
{
|
||||
var request = new NetworkInfoRequest
|
||||
{
|
||||
Body = new NetworkInfoRequest.Types.Body { }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await netmapServiceClient.NetworkInfoAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
internal async Task<NetmapSnapshot> GetNetmapSnapshotAsync(Context ctx)
|
||||
{
|
||||
var request = new NetmapSnapshotRequest
|
||||
{
|
||||
Body = new NetmapSnapshotRequest.Types.Body { }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await netmapServiceClient.NetmapSnapshotAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.ToModel();
|
||||
}
|
||||
|
||||
private static bool GetBoolValue(byte[] bytes)
|
||||
{
|
||||
return bytes.Any(b => b != 0);
|
||||
}
|
||||
|
||||
private static ulong GetLongValue(byte[] bytes)
|
||||
{
|
||||
ulong val = 0;
|
||||
for (var i = bytes.Length - 1; i >= 0; i--)
|
||||
val = (val << 8) + bytes[i];
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
private static void SetNetworksParam(Parameter param, NetworkSettings settings)
|
||||
{
|
||||
var key = Encoding.UTF8.GetString(param.Key.ToByteArray());
|
||||
|
||||
var valueBytes = param.Value.ToByteArray();
|
||||
switch (key)
|
||||
{
|
||||
case "ContainerFee": settings.ContainerFee = GetLongValue(valueBytes); break;
|
||||
case "EpochDuration": settings.EpochDuration = GetLongValue(valueBytes); break;
|
||||
case "IRCandidateFee": settings.IRCandidateFee = 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 "WithdrawalFee": settings.WithdrawalFee = GetLongValue(valueBytes); break;
|
||||
case "HomomorphicHashingDisabled": settings.HomomorphicHashingDisabled = GetBoolValue(valueBytes); break;
|
||||
case "MaintenanceModeAllowed": settings.MaintenanceModeAllowed = GetBoolValue(valueBytes); break;
|
||||
default: settings.UnnamedSettings.Add(key, valueBytes); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -7,20 +7,20 @@ using FrostFS.Object;
|
|||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
internal class ObjectReader : IDisposable
|
||||
internal class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IDisposable
|
||||
{
|
||||
public AsyncServerStreamingCall<GetResponse> Call { get; set; }
|
||||
public AsyncServerStreamingCall<GetResponse> Call { get; private set; } = call;
|
||||
|
||||
public async Task<Object.Object> ReadHeader()
|
||||
{
|
||||
if (!await Call.ResponseStream.MoveNext())
|
||||
throw new InvalidOperationException("unexpect end of stream");
|
||||
throw new InvalidOperationException("unexpected end of stream");
|
||||
|
||||
var response = Call.ResponseStream.Current;
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Init)
|
||||
throw new InvalidOperationException("unexpect message type");
|
||||
throw new InvalidOperationException("unexpected message type");
|
||||
|
||||
return new Object.Object
|
||||
{
|
||||
|
@ -38,7 +38,7 @@ internal class ObjectReader : IDisposable
|
|||
Verifier.CheckResponse(response);
|
||||
|
||||
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
|
||||
throw new InvalidOperationException("unexpect message type");
|
||||
throw new InvalidOperationException("unexpected message type");
|
||||
|
||||
return response.Body.Chunk.ToByteArray();
|
||||
}
|
||||
|
|
|
@ -1,26 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
using Google.Protobuf;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using FrostFS.Object;
|
||||
using FrostFS.Refs;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Session;
|
||||
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ClientV2.Extensions;
|
||||
using System.Threading;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public partial class Client
|
||||
internal class ObjectServiceProvider : ContextAccessor
|
||||
{
|
||||
public async Task<ObjectHeader> GetObjectHeadAsync(ContainerId cid, ObjectId oid)
|
||||
private readonly ObjectService.ObjectServiceClient objectServiceClient;
|
||||
|
||||
internal ObjectServiceProvider(ObjectService.ObjectServiceClient objectServiceClient, ClientEnvironment context)
|
||||
: base (context)
|
||||
{
|
||||
this.objectServiceClient = objectServiceClient;
|
||||
}
|
||||
|
||||
internal async Task<ObjectHeader> GetObjectHeadAsync(ContainerId cid, ObjectId oid, Context ctx)
|
||||
{
|
||||
var request = new HeadRequest
|
||||
{
|
||||
|
@ -34,18 +41,20 @@ public partial class Client
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _objectServiceClient!.HeadAsync(request);
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await objectServiceClient!.HeadAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.Body.Header.Header.ToModel();
|
||||
}
|
||||
|
||||
public async Task<ModelsV2.Object> GetObjectAsync(ContainerId cid, ObjectId oid)
|
||||
internal async Task<ModelsV2.Object> GetObjectAsync(ContainerId cid, ObjectId oid, Context ctx)
|
||||
{
|
||||
var sessionToken = await CreateSessionAsync(uint.MaxValue);
|
||||
var sessionToken = await GetOrCreateSession(ctx);
|
||||
|
||||
var request = new GetRequest
|
||||
{
|
||||
Body = new GetRequest.Types.Body
|
||||
|
@ -64,41 +73,131 @@ public partial class Client
|
|||
cid.ToGrpcMessage(),
|
||||
oid.ToGrpcMessage(),
|
||||
ObjectSessionContext.Types.Verb.Get,
|
||||
_key
|
||||
Context.Key
|
||||
);
|
||||
|
||||
request.Sign(_key);
|
||||
var obj = await GetObject(request);
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var obj = await GetObject(request, ctx);
|
||||
|
||||
return obj.ToModel();
|
||||
}
|
||||
|
||||
public async Task<ObjectId> PutObjectAsync(ObjectHeader header, Stream payload, CancellationToken cancellationToken = default)
|
||||
internal Task<ObjectId> PutObjectAsync(PutObjectParameters parameters, Context ctx)
|
||||
{
|
||||
return await PutObject(header, payload, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<ObjectId> PutObjectAsync(ObjectHeader header, byte[] payload, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var stream = new MemoryStream(payload);
|
||||
return await PutObject(header, stream, cancellationToken);
|
||||
}
|
||||
|
||||
private Task<ObjectId> PutObject(ObjectHeader header, Stream payload, CancellationToken cancellationToken)
|
||||
{
|
||||
if (header.ClientCut)
|
||||
return PutClientCutObject(header, payload, cancellationToken);
|
||||
if (parameters.Header == null)
|
||||
throw new ArgumentException("Value cannot be null", nameof(parameters.Header));
|
||||
|
||||
if (parameters.Payload == null)
|
||||
throw new ArgumentException("Value cannot be null", nameof(parameters.Payload));
|
||||
|
||||
if (parameters.ClientCut)
|
||||
return PutClientCutObject(parameters, ctx);
|
||||
else
|
||||
return PutStreamObject(header, payload, cancellationToken);
|
||||
return PutStreamObject(parameters, ctx);
|
||||
}
|
||||
|
||||
internal async Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object @object, Context ctx)
|
||||
{
|
||||
var sessionToken = await GetOrCreateSession(ctx);
|
||||
|
||||
var obj = CreateObject(@object);
|
||||
|
||||
var request = new PutSingleRequest
|
||||
{
|
||||
Body = new PutSingleRequest.Types.Body()
|
||||
{
|
||||
Object = obj
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.AddObjectSessionToken(
|
||||
sessionToken,
|
||||
obj.Header.ContainerId,
|
||||
obj.ObjectId,
|
||||
ObjectSessionContext.Types.Verb.Put,
|
||||
Context.Key
|
||||
);
|
||||
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await objectServiceClient!.PutSingleAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return ObjectId.FromHash(obj.ObjectId.Value.ToByteArray());
|
||||
}
|
||||
|
||||
private async Task<ObjectId> PutClientCutObject(ObjectHeader header, Stream payloadStream, CancellationToken cancellationToken)
|
||||
internal ObjectId CalculateObjectId(ObjectHeader header)
|
||||
{
|
||||
ObjectId? objectId = null;
|
||||
var grpcHeader = CreateHeader(header, []);
|
||||
|
||||
return new ObjectID { Value = grpcHeader.Sha256() }.ToModel();
|
||||
}
|
||||
|
||||
internal async Task DeleteObjectAsync(ContainerId cid, ObjectId oid, Context ctx)
|
||||
{
|
||||
var request = new DeleteRequest
|
||||
{
|
||||
Body = new DeleteRequest.Types.Body
|
||||
{
|
||||
Address = new Address
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
ObjectId = oid.ToGrpcMessage()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var response = await objectServiceClient!.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
}
|
||||
|
||||
internal async IAsyncEnumerable<ObjectId> SearchObjectsAsync(
|
||||
ContainerId cid,
|
||||
IEnumerable<ObjectFilter> filters,
|
||||
Context ctx)
|
||||
{
|
||||
var request = new SearchRequest
|
||||
{
|
||||
Body = new SearchRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
Filters = { },
|
||||
Version = 1 // TODO: clarify this param
|
||||
}
|
||||
};
|
||||
|
||||
request.Body.Filters.AddRange(filters.Select(f => f.ToGrpcMessage()));
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(Context.Key);
|
||||
|
||||
var objectsIds = SearchObjects(request, ctx);
|
||||
|
||||
await foreach (var oid in objectsIds)
|
||||
{
|
||||
yield return ObjectId.FromHash(oid.Value.ToByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<ObjectId> PutClientCutObject(PutObjectParameters parameters, Context ctx)
|
||||
{
|
||||
var payloadStream = parameters.Payload!;
|
||||
var header = parameters.Header!;
|
||||
|
||||
ObjectId? objectId;
|
||||
List<ObjectId> sentObjectIds = [];
|
||||
ModelsV2.Object? currentObject;
|
||||
|
||||
var partSize = (int)NetworkSettings["MaxObjectSize"];
|
||||
var networkSettings = await Context.NetmapService!.GetNetworkSettingsAsync(ctx);
|
||||
|
||||
var partSize = (int)networkSettings.MaxObjectSize;
|
||||
var buffer = new byte[partSize];
|
||||
|
||||
var largeObject = new LargeObject(header.ContainerId);
|
||||
|
@ -109,8 +208,6 @@ public partial class Client
|
|||
|
||||
while (true)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var bytesCount = await payloadStream.ReadAsync(buffer, 0, partSize);
|
||||
|
||||
split.Previous = sentObjectIds.LastOrDefault();
|
||||
|
@ -124,37 +221,41 @@ public partial class Client
|
|||
if (largeObject.PayloadLength == fullLength)
|
||||
break;
|
||||
|
||||
objectId = await PutSingleObjectAsync(currentObject, cancellationToken);
|
||||
objectId = await PutSingleObjectAsync(currentObject, ctx);
|
||||
|
||||
sentObjectIds.Add(objectId!);
|
||||
}
|
||||
|
||||
if (sentObjectIds.Any())
|
||||
if (sentObjectIds.Count != 0)
|
||||
{
|
||||
largeObject.CalculateHash();
|
||||
|
||||
currentObject.SetParent(largeObject);
|
||||
|
||||
objectId = await PutSingleObjectAsync(currentObject, cancellationToken);
|
||||
objectId = await PutSingleObjectAsync(currentObject, ctx);
|
||||
sentObjectIds.Add(objectId);
|
||||
|
||||
var linkObject = new LinkObject(header.ContainerId, split.SplitId, largeObject)
|
||||
.AddChildren(sentObjectIds);
|
||||
|
||||
_ = await PutSingleObjectAsync(linkObject, cancellationToken);
|
||||
_ = await PutSingleObjectAsync(linkObject, ctx);
|
||||
|
||||
return currentObject.GetParentId();
|
||||
return CalculateObjectId(largeObject.Header);
|
||||
}
|
||||
|
||||
return await PutSingleObjectAsync(currentObject, cancellationToken);
|
||||
return await PutSingleObjectAsync(currentObject, ctx);
|
||||
}
|
||||
|
||||
private async Task<ObjectId> PutStreamObject(ObjectHeader header, Stream payload, CancellationToken cancellationToken)
|
||||
private async Task<ObjectId> PutStreamObject(PutObjectParameters parameters, Context ctx)
|
||||
{
|
||||
var sessionToken = await CreateSessionAsync(uint.MaxValue);
|
||||
var payload = parameters.Payload!;
|
||||
var header = parameters.Header!;
|
||||
|
||||
var sessionToken = await GetOrCreateSession(ctx);
|
||||
|
||||
var hdr = header.ToGrpcMessage();
|
||||
hdr.OwnerId = OwnerId.ToGrpcMessage();
|
||||
hdr.Version = Version.ToGrpcMessage();
|
||||
hdr.OwnerId = Context.Owner.ToGrpcMessage();
|
||||
hdr.Version = Context.Version.ToGrpcMessage();
|
||||
|
||||
var oid = new ObjectID
|
||||
{
|
||||
|
@ -178,19 +279,17 @@ public partial class Client
|
|||
hdr.ContainerId,
|
||||
oid,
|
||||
ObjectSessionContext.Types.Verb.Put,
|
||||
_key
|
||||
Context.Key
|
||||
);
|
||||
|
||||
request.Sign(_key);
|
||||
request.Sign(Context.Key);
|
||||
|
||||
using var stream = await PutObjectInit(request);
|
||||
using var stream = await PutObjectInit(request, ctx);
|
||||
var buffer = new byte[Constants.ObjectChunkSize];
|
||||
|
||||
while (true)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var bufferLength = await payload.ReadAsync(buffer, 0, Constants.ObjectChunkSize);
|
||||
var bufferLength = await payload.ReadAsync(buffer, 0, Constants.ObjectChunkSize, ctx.CancellationToken);
|
||||
|
||||
if (bufferLength == 0)
|
||||
break;
|
||||
|
@ -201,7 +300,7 @@ public partial class Client
|
|||
};
|
||||
|
||||
request.VerifyHeader = null;
|
||||
request.Sign(_key);
|
||||
request.Sign(Context.Key);
|
||||
await stream.Write(request);
|
||||
}
|
||||
|
||||
|
@ -211,168 +310,11 @@ public partial class Client
|
|||
return ObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray());
|
||||
}
|
||||
|
||||
public async Task<ObjectId> PutSingleObjectAsync(ModelsV2.Object @object, CancellationToken cancellationToken = default)
|
||||
// TODO: add implementation with stream writer!
|
||||
private async Task<Object.Object> GetObject(GetRequest request, Context ctx)
|
||||
{
|
||||
var sessionToken = await CreateSessionAsync(uint.MaxValue);
|
||||
|
||||
var obj = CreateObject(@object);
|
||||
|
||||
var request = new PutSingleRequest
|
||||
{
|
||||
Body = new () { Object = obj }
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.AddObjectSessionToken(
|
||||
sessionToken,
|
||||
obj.Header.ContainerId,
|
||||
obj.ObjectId,
|
||||
ObjectSessionContext.Types.Verb.Put,
|
||||
_key
|
||||
);
|
||||
|
||||
request.Sign(_key);
|
||||
|
||||
var response = await _objectServiceClient!.PutSingleAsync(request, null, null, cancellationToken);
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return ObjectId.FromHash(obj.ObjectId.Value.ToByteArray());
|
||||
}
|
||||
|
||||
public Object.Object CreateObject(ModelsV2.Object @object)
|
||||
{
|
||||
var grpcHeader = @object.Header.ToGrpcMessage();
|
||||
|
||||
grpcHeader.OwnerId = OwnerId.ToGrpcMessage();
|
||||
grpcHeader.Version = Version.ToGrpcMessage();
|
||||
|
||||
if (@object.Payload != null)
|
||||
{
|
||||
grpcHeader.PayloadLength = (ulong)@object.Payload.Length;
|
||||
grpcHeader.PayloadHash = Sha256Checksum(@object.Payload);
|
||||
}
|
||||
|
||||
var split = @object.Header.Split;
|
||||
if (split != null)
|
||||
{
|
||||
grpcHeader.Split = new Header.Types.Split
|
||||
{
|
||||
SplitId = split.SplitId != null ? ByteString.CopyFrom(split.SplitId.ToBinary()) : null
|
||||
};
|
||||
|
||||
if (split.Children != null && split.Children.Any())
|
||||
grpcHeader.Split.Children.AddRange(split.Children.Select(id => id.ToGrpcMessage()));
|
||||
|
||||
if (split.ParentHeader is not null)
|
||||
{
|
||||
var grpcParentHeader = CreateHeader(split.ParentHeader, []);
|
||||
|
||||
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
|
||||
grpcHeader.Split.ParentHeader = grpcParentHeader;
|
||||
grpcHeader.Split.ParentSignature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(_key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(_key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||
};
|
||||
|
||||
split.Parent = grpcHeader.Split.Parent.ToModel();
|
||||
}
|
||||
|
||||
grpcHeader.Split.Previous = split.Previous?.ToGrpcMessage();
|
||||
}
|
||||
|
||||
var obj = new Object.Object
|
||||
{
|
||||
Header = grpcHeader,
|
||||
ObjectId = new ObjectID { Value = grpcHeader.Sha256() },
|
||||
Payload = ByteString.CopyFrom(@object.Payload)
|
||||
};
|
||||
|
||||
obj.Signature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(_key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(_key.SignData(obj.ObjectId.ToByteArray())),
|
||||
};
|
||||
using var stream = GetObjectInit(request, ctx);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Header CreateHeader(ObjectHeader header, byte[]? payload)
|
||||
{
|
||||
var grpcHeader = header.ToGrpcMessage();
|
||||
|
||||
grpcHeader.OwnerId = OwnerId.ToGrpcMessage();
|
||||
grpcHeader.Version = Version.ToGrpcMessage();
|
||||
|
||||
if (header.PayloadCheckSum != null)
|
||||
{
|
||||
grpcHeader.PayloadHash = new Checksum
|
||||
{
|
||||
Type = ChecksumType.Sha256,
|
||||
Sum = ByteString.CopyFrom(header.PayloadCheckSum)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (payload != null)
|
||||
grpcHeader.PayloadHash = Sha256Checksum(payload);
|
||||
}
|
||||
|
||||
return grpcHeader;
|
||||
}
|
||||
|
||||
public async Task DeleteObjectAsync(ContainerId cid, ObjectId oid)
|
||||
{
|
||||
var request = new DeleteRequest
|
||||
{
|
||||
Body = new DeleteRequest.Types.Body
|
||||
{
|
||||
Address = new Address
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
ObjectId = oid.ToGrpcMessage()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var response = await _objectServiceClient!.DeleteAsync(request);
|
||||
Verifier.CheckResponse(response);
|
||||
}
|
||||
|
||||
public async IAsyncEnumerable<ObjectId> SearchObjectsAsync(ContainerId cid, params ObjectFilter[] filters)
|
||||
{
|
||||
var request = new SearchRequest
|
||||
{
|
||||
Body = new SearchRequest.Types.Body
|
||||
{
|
||||
ContainerId = cid.ToGrpcMessage(),
|
||||
Filters = { },
|
||||
Version = 1
|
||||
}
|
||||
};
|
||||
|
||||
foreach (var filter in filters)
|
||||
{
|
||||
request.Body.Filters.Add(filter.ToGrpcMessage());
|
||||
}
|
||||
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
var objectsIds = SearchObjects(request);
|
||||
|
||||
|
||||
await foreach (var oid in objectsIds)
|
||||
{
|
||||
yield return ObjectId.FromHash(oid.Value.ToByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<Object.Object> GetObject(GetRequest request)
|
||||
{
|
||||
using var stream = GetObjectInit(request);
|
||||
var obj = await stream.ReadHeader();
|
||||
var payload = new byte[obj.Header.PayloadLength];
|
||||
var offset = 0L;
|
||||
|
@ -392,57 +334,134 @@ public partial class Client
|
|||
return obj;
|
||||
}
|
||||
|
||||
private ObjectReader GetObjectInit(GetRequest initRequest)
|
||||
private ObjectReader GetObjectInit(GetRequest initRequest, Context ctx)
|
||||
{
|
||||
if (initRequest is null)
|
||||
throw new ArgumentNullException(nameof(initRequest));
|
||||
|
||||
|
||||
return new ObjectReader
|
||||
{
|
||||
Call = _objectServiceClient!.Get(initRequest)
|
||||
};
|
||||
var call = objectServiceClient!.Get(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
return new ObjectReader(call);
|
||||
}
|
||||
|
||||
private async Task<ObjectStreamer> PutObjectInit(PutRequest initRequest)
|
||||
private async Task<ObjectStreamer> PutObjectInit(PutRequest initRequest, Context ctx)
|
||||
{
|
||||
if (initRequest is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(initRequest));
|
||||
}
|
||||
|
||||
var call = _objectServiceClient!.Put();
|
||||
var call = objectServiceClient!.Put(null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
await call.RequestStream.WriteAsync(initRequest);
|
||||
|
||||
return new ObjectStreamer(call);
|
||||
}
|
||||
|
||||
private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request)
|
||||
private async IAsyncEnumerable<ObjectID> SearchObjects(SearchRequest request, Context ctx)
|
||||
{
|
||||
using var stream = GetSearchReader(request);
|
||||
var ids = await stream.Read();
|
||||
while (ids is not null)
|
||||
using var stream = GetSearchReader(request, ctx);
|
||||
|
||||
while (true)
|
||||
{
|
||||
var ids = await stream.Read(ctx.CancellationToken);
|
||||
|
||||
if (ids == null)
|
||||
break;
|
||||
|
||||
foreach (var oid in ids)
|
||||
{
|
||||
yield return oid;
|
||||
}
|
||||
|
||||
ids = await stream.Read();
|
||||
}
|
||||
}
|
||||
|
||||
private SearchReader GetSearchReader(SearchRequest initRequest)
|
||||
private SearchReader GetSearchReader(SearchRequest initRequest, Context ctx)
|
||||
{
|
||||
if (initRequest is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(initRequest));
|
||||
}
|
||||
|
||||
return new SearchReader(_objectServiceClient!.Search(initRequest));
|
||||
var call = objectServiceClient!.Search(initRequest, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
return new SearchReader(call);
|
||||
}
|
||||
|
||||
private Object.Object CreateObject(ModelsV2.Object @object)
|
||||
{
|
||||
var grpcHeader = @object.Header.ToGrpcMessage();
|
||||
|
||||
grpcHeader.OwnerId = Context.Owner.ToGrpcMessage();
|
||||
grpcHeader.Version = Context.Version.ToGrpcMessage();
|
||||
|
||||
if (@object.Payload != null)
|
||||
{
|
||||
grpcHeader.PayloadLength = (ulong)@object.Payload.Length;
|
||||
grpcHeader.PayloadHash = Sha256Checksum(@object.Payload);
|
||||
}
|
||||
|
||||
var split = @object.Header.Split;
|
||||
if (split != null)
|
||||
{
|
||||
grpcHeader.Split = new Header.Types.Split
|
||||
{
|
||||
SplitId = split.SplitId != null ? ByteString.CopyFrom(split.SplitId.ToBinary()) : null
|
||||
};
|
||||
|
||||
if (split.Children != null && split.Children.Count != 0)
|
||||
grpcHeader.Split.Children.AddRange(split.Children.Select(id => id.ToGrpcMessage()));
|
||||
|
||||
if (split.ParentHeader is not null)
|
||||
{
|
||||
var grpcParentHeader = CreateHeader(split.ParentHeader, []);
|
||||
|
||||
grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() };
|
||||
grpcHeader.Split.ParentHeader = grpcParentHeader;
|
||||
grpcHeader.Split.ParentSignature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Context.Key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(Context.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||
};
|
||||
|
||||
split.Parent = grpcHeader.Split.Parent.ToModel();
|
||||
}
|
||||
|
||||
grpcHeader.Split.Previous = split.Previous?.ToGrpcMessage();
|
||||
}
|
||||
|
||||
var obj = new Object.Object
|
||||
{
|
||||
Header = grpcHeader,
|
||||
ObjectId = new ObjectID { Value = grpcHeader.Sha256() },
|
||||
Payload = ByteString.CopyFrom(@object.Payload)
|
||||
};
|
||||
|
||||
obj.Signature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Context.Key.PublicKey()),
|
||||
Sign = ByteString.CopyFrom(Context.Key.SignData(obj.ObjectId.ToByteArray())),
|
||||
};
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public Checksum Sha256Checksum(byte[] data)
|
||||
private Header CreateHeader(ObjectHeader header, byte[]? payload)
|
||||
{
|
||||
var grpcHeader = header.ToGrpcMessage();
|
||||
|
||||
grpcHeader.OwnerId = Context.Owner.ToGrpcMessage();
|
||||
grpcHeader.Version = Context.Version.ToGrpcMessage();
|
||||
|
||||
if (header.PayloadCheckSum != null)
|
||||
grpcHeader.PayloadHash = Sha256Checksum(header.PayloadCheckSum);
|
||||
else if (payload != null)
|
||||
grpcHeader.PayloadHash = Sha256Checksum(payload);
|
||||
|
||||
return grpcHeader;
|
||||
}
|
||||
|
||||
private static Checksum Sha256Checksum(byte[] data)
|
||||
{
|
||||
return new Checksum
|
||||
{
|
||||
|
@ -450,8 +469,14 @@ public partial class Client
|
|||
Sum = ByteString.CopyFrom(data.Sha256())
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<Session.SessionToken> GetOrCreateSession(Context ctx)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ctx.SessionToken))
|
||||
{
|
||||
return await Context.SessionService!.CreateSessionAsync(uint.MaxValue, ctx);
|
||||
}
|
||||
|
||||
return Convert.FromBase64String(ctx.SessionToken).DeserializeSessionToken();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ using Grpc.Core;
|
|||
|
||||
using FrostFS.Object;
|
||||
using FrostFS.Refs;
|
||||
using System.Threading;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
|
@ -14,14 +15,13 @@ internal class SearchReader(AsyncServerStreamingCall<SearchResponse> call) : IDi
|
|||
{
|
||||
public AsyncServerStreamingCall<SearchResponse> Call { get; private set; } = call;
|
||||
|
||||
public async Task<List<ObjectID>?> Read()
|
||||
public async Task<List<ObjectID>?> Read(CancellationToken cancellationToken)
|
||||
{
|
||||
if (!await Call.ResponseStream.MoveNext())
|
||||
{
|
||||
if (!await Call.ResponseStream.MoveNext(cancellationToken))
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
var response = Call.ResponseStream.Current;
|
||||
|
||||
Verifier.CheckResponse(response);
|
||||
|
||||
return response.Body?.IdList.ToList();
|
||||
|
|
|
@ -5,28 +5,38 @@ using FrostFS.Session;
|
|||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public partial class Client
|
||||
{
|
||||
private async Task<SessionToken> CreateSessionAsync(ulong expiration)
|
||||
internal class SessionServiceProvider : ContextAccessor
|
||||
{
|
||||
private readonly SessionService.SessionServiceClient? _sessionServiceClient;
|
||||
|
||||
internal SessionServiceProvider(SessionService.SessionServiceClient? sessionServiceClient, ClientEnvironment context)
|
||||
: base (context)
|
||||
{
|
||||
_sessionServiceClient = sessionServiceClient;
|
||||
}
|
||||
|
||||
internal async Task<SessionToken> CreateSessionAsync(ulong expiration, Context ctx)
|
||||
{
|
||||
var request = new CreateRequest
|
||||
{
|
||||
Body = new CreateRequest.Types.Body
|
||||
{
|
||||
OwnerId = OwnerId.ToGrpcMessage(),
|
||||
Expiration = expiration,
|
||||
OwnerId = Context.Owner.ToGrpcMessage(),
|
||||
Expiration = expiration
|
||||
}
|
||||
};
|
||||
|
||||
request.AddMetaHeader();
|
||||
request.Sign(_key);
|
||||
request.Sign(Context.Key);
|
||||
|
||||
return await CreateSession(request);
|
||||
var token = await CreateSession(request, ctx);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private async Task<SessionToken> CreateSession(CreateRequest request)
|
||||
internal async Task<SessionToken> CreateSession(CreateRequest request, Context ctx)
|
||||
{
|
||||
var resp = await _sessionServiceClient.CreateAsync(request);
|
||||
var resp = await _sessionServiceClient!.CreateAsync(request, null, ctx.Deadline, ctx.CancellationToken);
|
||||
|
||||
return new SessionToken
|
||||
{
|
40
src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs
Normal file
40
src/FrostFS.SDK.ClientV2/Tools/ClientEnvironment.cs
Normal file
|
@ -0,0 +1,40 @@
|
|||
using FrostFS.SDK.ModelsV2;
|
||||
using Grpc.Net.Client;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public class ClientEnvironment(ECDsa key, OwnerId owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
|
||||
{
|
||||
internal OwnerId Owner { get; } = owner;
|
||||
internal GrpcChannel Channel { get; private set; } = channel;
|
||||
internal ECDsa Key { get; } = key;
|
||||
internal ModelsV2.Version Version { get; } = version;
|
||||
internal NetworkSettings? NetworkSettings { get; set; }
|
||||
|
||||
internal ContainerServiceProvider? ContainerService { get; set; }
|
||||
internal NetmapServiceProvider? NetmapService { get; set; }
|
||||
internal SessionServiceProvider? SessionService { get; set; }
|
||||
internal ObjectServiceProvider? ObjectService { get; set; }
|
||||
|
||||
internal bool Initialized =>
|
||||
ContainerService != null
|
||||
&& NetmapService != null
|
||||
&& SessionService != null
|
||||
&& ObjectService != null;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
dstepanov-yadro marked this conversation as resolved
Outdated
dstepanov-yadro
commented
Looks like the same result could be the same result can be achieved with the interceptor list for GrpcChannel. If it is really required I'm ok with this. But other option is to allow to pass GrpcChannel to Looks like the same result could be the same result can be achieved with the interceptor list for GrpcChannel. If it is really required I'm ok with this. But other option is to allow to pass GrpcChannel to `Client`, so SDK user could add any interceptors to grpc pipeline.
PavelGrossSpb
commented
Good idea. GRPC channal is available now to add any interceptors Good idea. GRPC channal is available now to add any interceptors
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Channel.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
8
src/FrostFS.SDK.ClientV2/Tools/ContextAccessor.cs
Normal file
8
src/FrostFS.SDK.ClientV2/Tools/ContextAccessor.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
internal class ContextAccessor(ClientEnvironment context)
|
||||
{
|
||||
protected ClientEnvironment Context { get; set; } = context;
|
||||
}
|
||||
|
||||
|
21
src/FrostFS.SDK.ClientV2/Tools/NetworkSettings.cs
Normal file
21
src/FrostFS.SDK.ClientV2/Tools/NetworkSettings.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public class NetworkSettings
|
||||
{
|
||||
public ulong ContainerFee { get; internal set; }
|
||||
public ulong ContainerAliasFee { get; internal set; }
|
||||
public ulong InnerRingCandidateFee { get; internal set; }
|
||||
public ulong WithdrawFee { get; internal set; }
|
||||
public ulong EpochDuration { get; internal set; }
|
||||
public ulong IRCandidateFee { get; internal set; }
|
||||
public ulong MaxObjectSize { get; internal set; }
|
||||
public ulong MaxECDataCount { get; internal set; }
|
||||
public ulong MaxECParityCount { get; internal set; }
|
||||
public ulong WithdrawalFee { get; internal set; }
|
||||
public bool HomomorphicHashingDisabled { get; internal set; }
|
||||
public bool MaintenanceModeAllowed { get; internal set; }
|
||||
|
||||
public Dictionary<string, object> UnnamedSettings { get; } = [];
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2.Extensions;
|
||||
|
||||
public static class Extensions
|
||||
public static class ObjectExtensions
|
||||
{
|
||||
public static ModelsV2.Object SetPayloadLength(this ModelsV2.Object obj, ulong length)
|
||||
{
|
||||
|
@ -41,4 +42,15 @@ public static class Extensions
|
|||
linkObject.Header.Split!.Children.AddRange(objectIds);
|
||||
return linkObject;
|
||||
}
|
||||
|
||||
public static ModelsV2.Object CalculateObjectId(this ModelsV2.Object obj)
|
||||
{
|
||||
if (obj.Payload == null)
|
||||
throw new MissingFieldException("Payload cannot be null");
|
||||
|
||||
if (obj.Header == null)
|
||||
throw new MissingFieldException("Header cannot be null");
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
|
@ -41,10 +41,10 @@ namespace System
|
|||
}
|
||||
|
||||
/// <summary>Create an Index pointing at first element.</summary>
|
||||
public static Index Start => new Index(0);
|
||||
public static Index Start => new(0);
|
||||
|
||||
/// <summary>Create an Index pointing at beyond last element.</summary>
|
||||
public static Index End => new Index(~0);
|
||||
public static Index End => new(~0);
|
||||
|
||||
/// <summary>Create an Index from the start at the position indicated by the value.</summary>
|
||||
/// <param name="value">The index value from the start.</param>
|
||||
|
@ -116,7 +116,7 @@ namespace System
|
|||
|
||||
/// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
|
||||
/// <param name="value">An object to compare with this object</param>
|
||||
public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value;
|
||||
public override bool Equals(object? value) => value is Index index && _value == index._value;
|
||||
|
||||
/// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
|
||||
/// <param name="other">An object to compare with this object</param>
|
||||
|
@ -147,22 +147,16 @@ namespace System
|
|||
/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
internal readonly struct Range : IEquatable<Range>
|
||||
/// <remarks>Construct a Range object using the start and end indexes.</remarks>
|
||||
/// <param name="start">Represent the inclusive start index of the range.</param>
|
||||
/// <param name="end">Represent the exclusive end index of the range.</param>
|
||||
internal readonly struct Range(Index start, Index end) : IEquatable<Range>
|
||||
{
|
||||
/// <summary>Represent the inclusive start index of the Range.</summary>
|
||||
public Index Start { get; }
|
||||
public Index Start { get; } = start;
|
||||
|
||||
/// <summary>Represent the exclusive end index of the Range.</summary>
|
||||
public Index End { get; }
|
||||
|
||||
/// <summary>Construct a Range object using the start and end indexes.</summary>
|
||||
/// <param name="start">Represent the inclusive start index of the range.</param>
|
||||
/// <param name="end">Represent the exclusive end index of the range.</param>
|
||||
public Range(Index start, Index end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
public Index End { get; } = end;
|
||||
|
||||
/// <summary>Indicates whether the current Range object is equal to another object of the same type.</summary>
|
||||
/// <param name="value">An object to compare with this object</param>
|
||||
|
@ -188,13 +182,13 @@ namespace System
|
|||
}
|
||||
|
||||
/// <summary>Create a Range object starting from start index to the end of the collection.</summary>
|
||||
public static Range StartAt(Index start) => new Range(start, Index.End);
|
||||
public static Range StartAt(Index start) => new(start, Index.End);
|
||||
|
||||
/// <summary>Create a Range object starting from first element in the collection to the end Index.</summary>
|
||||
public static Range EndAt(Index end) => new Range(Index.Start, end);
|
||||
public static Range EndAt(Index end) => new(Index.Start, end);
|
||||
|
||||
/// <summary>Create a Range object starting from first element to the end.</summary>
|
||||
public static Range All => new Range(Index.Start, Index.End);
|
||||
public static Range All => new(Index.Start, Index.End);
|
||||
|
||||
/// <summary>Calculate the start offset and length of range object using a collection length.</summary>
|
||||
/// <param name="length">The length of the collection that the range will be used with. length has to be a positive value.</param>
|
||||
|
@ -252,7 +246,7 @@ namespace System.Runtime.CompilerServices
|
|||
|
||||
if (length == 0)
|
||||
{
|
||||
return Array.Empty<T>();
|
||||
return [];
|
||||
}
|
||||
|
||||
var dest = new T[length];
|
|
@ -17,13 +17,15 @@ public static class RequestConstructor
|
|||
|
||||
public static void AddObjectSessionToken(
|
||||
this IRequest request,
|
||||
SessionToken sessionToken,
|
||||
Session.SessionToken sessionToken,
|
||||
ContainerID cid,
|
||||
ObjectID oid,
|
||||
ObjectSessionContext.Types.Verb verb,
|
||||
ECDsa key)
|
||||
{
|
||||
if (request.MetaHeader.SessionToken is not null) return;
|
||||
if (request.MetaHeader.SessionToken is not null)
|
||||
return;
|
||||
|
||||
request.MetaHeader.SessionToken = sessionToken;
|
||||
var ctx = new ObjectSessionContext
|
||||
{
|
||||
|
@ -34,6 +36,7 @@ public static class RequestConstructor
|
|||
},
|
||||
Verb = verb
|
||||
};
|
||||
|
||||
request.MetaHeader.SessionToken.Body.Object = ctx;
|
||||
request.MetaHeader.SessionToken.Signature = key.SignMessagePart(request.MetaHeader.SessionToken.Body);
|
||||
}
|
|
@ -84,7 +84,7 @@ public static class RequestSigner
|
|||
return sig;
|
||||
}
|
||||
|
||||
public static void Sign(this IVerificableMessage message, ECDsa key)
|
||||
public static void Sign(this IVerifiableMessage message, ECDsa key)
|
||||
{
|
||||
var meta = message.GetMetaHeader();
|
||||
IVerificationHeader verify = message switch
|
||||
|
@ -95,12 +95,15 @@ public static class RequestSigner
|
|||
};
|
||||
|
||||
var verifyOrigin = message.GetVerificationHeader();
|
||||
|
||||
if (verifyOrigin is null)
|
||||
verify.BodySignature = key.SignMessagePart(message.GetBody());
|
||||
|
||||
else
|
||||
verify.SetOrigin(verifyOrigin);
|
||||
|
||||
verify.MetaSignature = key.SignMessagePart(meta);
|
||||
verify.OriginSignature = key.SignMessagePart(verifyOrigin);
|
||||
verify.SetOrigin(verifyOrigin);
|
||||
|
||||
message.SetVerificationHeader(verify);
|
||||
}
|
||||
}
|
|
@ -68,7 +68,7 @@ public static class Verifier
|
|||
return false;
|
||||
|
||||
using var key = sig.Key.ToByteArray().LoadPublicKey();
|
||||
var data2Verify = data is null ? Array.Empty<byte>() : data.ToByteArray();
|
||||
var data2Verify = data is null ? [] : data.ToByteArray();
|
||||
|
||||
return key.VerifyData(data2Verify, sig.Sign.ToByteArray());
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ public static class Verifier
|
|||
return verification.BodySignature is null && VerifyMatryoskaLevel(body, meta.GetOrigin(), origin);
|
||||
}
|
||||
|
||||
public static bool Verify(this IVerificableMessage message)
|
||||
public static bool Verify(this IVerifiableMessage message)
|
||||
{
|
||||
return VerifyMatryoskaLevel(message.GetBody(), message.GetMetaHeader(), message.GetVerificationHeader());
|
||||
}
|
||||
|
@ -100,7 +100,17 @@ public static class Verifier
|
|||
throw new FormatException($"invalid response, type={resp.GetType()}");
|
||||
|
||||
var status = resp.MetaHeader.Status.ToModel();
|
||||
if (!status.IsSuccess())
|
||||
if (!status.IsSuccess)
|
||||
throw new ApplicationException(status.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is intended for unit tests for request verification.
|
||||
/// </summary>
|
||||
/// <param name="request">Created by SDK request to gRpc proxy</param>
|
||||
public static void CheckRequest(IRequest request)
|
||||
{
|
||||
if (!request.Verify())
|
||||
throw new FormatException($"invalid response, type={request.GetType()}");
|
||||
}
|
||||
}
|
|
@ -17,4 +17,4 @@ using System.Runtime.InteropServices;
|
|||
|
||||
[assembly: Guid("08a8487e-39ce-41fb-9c24-13f73ff2bde0")]
|
||||
|
||||
[assembly: InternalsVisibleToAttribute("FrostFS.SDK.Cryptography.Test")]
|
||||
[assembly: InternalsVisibleTo("FrostFS.SDK.Cryptography.Test")]
|
|
@ -34,9 +34,11 @@ public static class Base58
|
|||
byte[] checksum = data.ToArray().Sha256().Sha256();
|
||||
Span<byte> buffer = stackalloc byte[data.Length + 4];
|
||||
data.CopyTo(buffer);
|
||||
|
||||
checksum[..4].AsSpan().CopyTo(buffer[data.Length..]);
|
||||
var ret = Encode(buffer);
|
||||
buffer.Clear();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Security.Cryptography;
|
|||
|
||||
namespace FrostFS.SDK.Cryptography;
|
||||
|
||||
public static class Helper
|
||||
public static class Extentions
|
||||
{
|
||||
internal static byte[] RIPEMD160(this byte[] value)
|
||||
{
|
|
@ -6,6 +6,10 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
|
||||
<PackageReference Include="Google.Protobuf" Version="3.27.0" />
|
||||
|
|
|
@ -56,7 +56,7 @@ public static class KeyExtension
|
|||
|
||||
var script = new byte[] { 0x0c, CompressedPublicKeyLength }; //PUSHDATA1 33
|
||||
script = ArrayHelper.Concat(script, publicKey);
|
||||
script = ArrayHelper.Concat(script, new byte[] { 0x41 }); //SYSCALL
|
||||
script = ArrayHelper.Concat(script, [0x41]); //SYSCALL
|
||||
script = ArrayHelper.Concat(script, BitConverter.GetBytes(CheckSigDescriptor)); //Neo_Crypto_CheckSig
|
||||
|
||||
return script;
|
||||
|
@ -80,7 +80,7 @@ public static class KeyExtension
|
|||
private static byte[] GetPrivateKeyFromWIF(string wif)
|
||||
{
|
||||
if (wif == null)
|
||||
throw new ArgumentNullException();
|
||||
throw new ArgumentNullException(nameof(wif));
|
||||
|
||||
var data = wif.Base58CheckDecode();
|
||||
|
||||
|
@ -117,7 +117,7 @@ public static class KeyExtension
|
|||
var pos = 33 - param.Q.X.Length;
|
||||
|
||||
param.Q.X.CopyTo(pubkey, pos);
|
||||
if (new BigInteger(param.Q.Y.Reverse().Concat(new byte[] { 0x00 }).ToArray()).IsEven)
|
||||
if (new BigInteger(param.Q.Y.Reverse().Concat(new byte[] { 0x0 }).ToArray()).IsEven)
|
||||
pubkey[0] = 0x2;
|
||||
else
|
||||
pubkey[0] = 0x3;
|
||||
|
|
|
@ -41,10 +41,10 @@ namespace System
|
|||
}
|
||||
|
||||
/// <summary>Create an Index pointing at first element.</summary>
|
||||
public static Index Start => new Index(0);
|
||||
public static Index Start => new(0);
|
||||
|
||||
/// <summary>Create an Index pointing at beyond last element.</summary>
|
||||
public static Index End => new Index(~0);
|
||||
public static Index End => new(~0);
|
||||
|
||||
/// <summary>Create an Index from the start at the position indicated by the value.</summary>
|
||||
/// <param name="value">The index value from the start.</param>
|
||||
|
@ -116,7 +116,7 @@ namespace System
|
|||
|
||||
/// <summary>Indicates whether the current Index object is equal to another object of the same type.</summary>
|
||||
/// <param name="value">An object to compare with this object</param>
|
||||
public override bool Equals(object? value) => value is Index && _value == ((Index)value)._value;
|
||||
public override bool Equals(object? value) => value is Index index && _value == index._value;
|
||||
|
||||
/// <summary>Indicates whether the current Index object is equal to another Index object.</summary>
|
||||
/// <param name="other">An object to compare with this object</param>
|
||||
|
@ -147,22 +147,16 @@ namespace System
|
|||
/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
|
||||
/// </code>
|
||||
/// </remarks>
|
||||
internal readonly struct Range : IEquatable<Range>
|
||||
/// <remarks>Construct a Range object using the start and end indexes.</remarks>
|
||||
/// <param name="start">Represent the inclusive start index of the range.</param>
|
||||
/// <param name="end">Represent the exclusive end index of the range.</param>
|
||||
internal readonly struct Range (Index start, Index end) : IEquatable<Range>
|
||||
{
|
||||
/// <summary>Represent the inclusive start index of the Range.</summary>
|
||||
public Index Start { get; }
|
||||
public Index Start { get; } = start;
|
||||
|
||||
/// <summary>Represent the exclusive end index of the Range.</summary>
|
||||
public Index End { get; }
|
||||
|
||||
/// <summary>Construct a Range object using the start and end indexes.</summary>
|
||||
/// <param name="start">Represent the inclusive start index of the range.</param>
|
||||
/// <param name="end">Represent the exclusive end index of the range.</param>
|
||||
public Range(Index start, Index end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
public Index End { get; } = end;
|
||||
|
||||
/// <summary>Indicates whether the current Range object is equal to another object of the same type.</summary>
|
||||
/// <param name="value">An object to compare with this object</param>
|
||||
|
@ -188,13 +182,13 @@ namespace System
|
|||
}
|
||||
|
||||
/// <summary>Create a Range object starting from start index to the end of the collection.</summary>
|
||||
public static Range StartAt(Index start) => new Range(start, Index.End);
|
||||
public static Range StartAt(Index start) => new(start, Index.End);
|
||||
|
||||
/// <summary>Create a Range object starting from first element in the collection to the end Index.</summary>
|
||||
public static Range EndAt(Index end) => new Range(Index.Start, end);
|
||||
public static Range EndAt(Index end) => new(Index.Start, end);
|
||||
|
||||
/// <summary>Create a Range object starting from first element to the end.</summary>
|
||||
public static Range All => new Range(Index.Start, Index.End);
|
||||
public static Range All => new(Index.Start, Index.End);
|
||||
|
||||
/// <summary>Calculate the start offset and length of range object using a collection length.</summary>
|
||||
/// <param name="length">The length of the collection that the range will be used with. length has to be a positive value.</param>
|
||||
|
@ -252,7 +246,7 @@ namespace System.Runtime.CompilerServices
|
|||
|
||||
if (length == 0)
|
||||
{
|
||||
return Array.Empty<T>();
|
||||
return [];
|
||||
}
|
||||
|
||||
var dest = new T[length];
|
||||
|
|
28
src/FrostFS.SDK.ModelsV2/ClientSettings.cs
Normal file
28
src/FrostFS.SDK.ModelsV2/ClientSettings.cs
Normal file
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
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;
|
||||
|
||||
public string Host { get; set; } = string.Empty;
|
||||
|
||||
public 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());
|
||||
}
|
||||
|
||||
}
|
|
@ -5,17 +5,10 @@ using FrostFS.SDK.ModelsV2.Netmap;
|
|||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class Container
|
||||
public class Container(BasicAcl basicAcl, PlacementPolicy placementPolicy)
|
||||
{
|
||||
public Guid Nonce { get; set; }
|
||||
public BasicAcl BasicAcl { get; set; }
|
||||
public PlacementPolicy PlacementPolicy { get; set; }
|
||||
public Version Version { get; set; }
|
||||
|
||||
public Container(BasicAcl basicAcl, PlacementPolicy placementPolicy)
|
||||
{
|
||||
Nonce = Guid.NewGuid();
|
||||
BasicAcl = basicAcl;
|
||||
PlacementPolicy = placementPolicy;
|
||||
}
|
||||
public Guid Nonce { get; set; } = Guid.NewGuid();
|
||||
public BasicAcl BasicAcl { get; set; } = basicAcl;
|
||||
public PlacementPolicy PlacementPolicy { get; set; } = placementPolicy;
|
||||
public Version? Version { get; set; }
|
||||
}
|
13
src/FrostFS.SDK.ModelsV2/Context.cs
Normal file
13
src/FrostFS.SDK.ModelsV2/Context.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace FrostFS.SDK.ClientV2;
|
||||
|
||||
public class Context()
|
||||
{
|
||||
public CancellationToken CancellationToken { get; set; } = default;
|
||||
public TimeSpan Timeout { get; set; } = default;
|
||||
public string SessionToken { get; set; } = string.Empty;
|
||||
|
||||
public DateTime? Deadline => Timeout.Ticks > 0 ? DateTime.UtcNow.Add(Timeout) : null;
|
||||
}
|
|
@ -3,7 +3,10 @@ using System.ComponentModel;
|
|||
namespace FrostFS.SDK.ModelsV2.Enums;
|
||||
|
||||
public enum BasicAcl
|
||||
{
|
||||
{
|
||||
[Description("Not defined ACL")]
|
||||
NotDefined = 0x00000000,
|
||||
|
||||
[Description("Basic ACL for private container")]
|
||||
Private = 0x1C8C8CCC,
|
||||
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
8
src/FrostFS.SDK.ModelsV2/GrpcCallInfo.cs
Normal file
8
src/FrostFS.SDK.ModelsV2/GrpcCallInfo.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class GrpcCallInfo(string methodName, long elapsedMicroSec, bool hasError)
|
||||
{
|
||||
public string MethodName { get; set; } = methodName;
|
||||
public long ElapsedTimeMicroSec { get; set; } = elapsedMicroSec;
|
||||
public bool HasError { get; } = hasError;
|
||||
}
|
|
@ -1,17 +1,10 @@
|
|||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class MetaHeader
|
||||
public class MetaHeader(Version version, int epoch, int ttl)
|
||||
{
|
||||
public Version Version { get; set; }
|
||||
public int Epoch { get; set; }
|
||||
public int Ttl { get; set; }
|
||||
|
||||
public MetaHeader(Version version, int epoch, int ttl)
|
||||
{
|
||||
Version = version;
|
||||
Epoch = epoch;
|
||||
Ttl = ttl;
|
||||
}
|
||||
public Version Version { get; set; } = version;
|
||||
public int Epoch { get; set; } = epoch;
|
||||
public int Ttl { get; set; } = ttl;
|
||||
|
||||
public static MetaHeader Default()
|
||||
{
|
||||
|
|
10
src/FrostFS.SDK.ModelsV2/Netmap/NetmapInfo.cs
Normal file
10
src/FrostFS.SDK.ModelsV2/Netmap/NetmapInfo.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
public class NetmapSnapshot(ulong epoch, IReadOnlyList<NodeInfo> nodeInfoCollection)
|
||||
{
|
||||
public ulong Epoch { get; private set; } = epoch;
|
||||
|
||||
public IReadOnlyList<NodeInfo> NodeInfoCollection { get; private set; } = nodeInfoCollection;
|
||||
}
|
|
@ -1,9 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
public class NodeInfo
|
||||
{
|
||||
public NodeState State { get; set; }
|
||||
public Version? Version { get; set; }
|
||||
public NodeInfo(
|
||||
Version version,
|
||||
NodeState state,
|
||||
IReadOnlyCollection<string> addresses,
|
||||
IReadOnlyDictionary<string, string> attributes,
|
||||
ReadOnlyMemory<byte> publicKey)
|
||||
{
|
||||
Version = version;
|
||||
State = state;
|
||||
Addresses = addresses;
|
||||
Attributes = attributes;
|
||||
PublicKey = publicKey;
|
||||
}
|
||||
|
||||
public NodeState State { get; private set; }
|
||||
public Version Version { get; private set; }
|
||||
public IReadOnlyCollection<string> Addresses { get; private set; }
|
||||
public IReadOnlyDictionary<string, string> Attributes { get; private set; }
|
||||
public ReadOnlyMemory<byte> PublicKey { get; private set; }
|
||||
}
|
|
@ -1,13 +1,28 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
public class PlacementPolicy
|
||||
public class PlacementPolicy(bool unique, params Replica[] replicas) : IComparable<PlacementPolicy>
|
||||
{
|
||||
public Replica[] Replicas { get; private set; }
|
||||
public bool Unique { get; private set; }
|
||||
public Replica[] Replicas { get; private set; } = replicas;
|
||||
public bool Unique { get; private set; } = unique;
|
||||
|
||||
public PlacementPolicy(bool unique, params Replica[] replicas)
|
||||
public int CompareTo(PlacementPolicy other)
|
||||
{
|
||||
Replicas = replicas;
|
||||
Unique = unique;
|
||||
var notEqual = other == null
|
||||
|| Unique != other.Unique
|
||||
|| Replicas.Length != other.Replicas.Length;
|
||||
|
||||
if (notEqual)
|
||||
return 1;
|
||||
|
||||
foreach (var replica in Replicas)
|
||||
{
|
||||
if (!other!.Replicas.Any(r => r.Count == replica.Count && r.Selector == replica.Selector))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
9
src/FrostFS.SDK.ModelsV2/Object/IObjectReader.cs
Normal file
9
src/FrostFS.SDK.ModelsV2/Object/IObjectReader.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public interface IObjectReader : IDisposable
|
||||
{
|
||||
Task<byte[]?> ReadChunk();
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
|
||||
|
@ -5,8 +6,11 @@ namespace FrostFS.SDK.ModelsV2;
|
|||
|
||||
public class Object
|
||||
{
|
||||
public Object()
|
||||
public Object(ObjectId objectId, ObjectHeader header, byte[] payload)
|
||||
{
|
||||
ObjectId = objectId;
|
||||
Payload = payload;
|
||||
Header = header;
|
||||
}
|
||||
|
||||
public Object(ContainerId container, byte[] payload, ObjectType objectType = ObjectType.Regular)
|
||||
|
@ -14,43 +18,47 @@ public class Object
|
|||
Payload = payload;
|
||||
Header = new ObjectHeader(containerId: container, type: objectType, attributes: []);
|
||||
}
|
||||
|
||||
|
||||
public ObjectHeader Header { get; set; }
|
||||
public ObjectId ObjectId { get; set; }
|
||||
|
||||
public ObjectId? ObjectId
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
public byte[] Payload { get; set; }
|
||||
public Signature Signature { get; set; }
|
||||
|
||||
public Signature? Signature { get; set; }
|
||||
|
||||
public void SetParent(LargeObject largeObject)
|
||||
{
|
||||
Header.Split.ParentHeader = largeObject.Header;
|
||||
}
|
||||
if (Header?.Split == null)
|
||||
throw new Exception("The object is not initialized properly");
|
||||
|
||||
public ObjectId? GetParentId()
|
||||
{
|
||||
return Header.Split?.Parent;
|
||||
Header.Split.ParentHeader = largeObject.Header;
|
||||
}
|
||||
}
|
||||
|
||||
public class LargeObject(ContainerId container) : Object(container, [])
|
||||
{
|
||||
private SHA256 payloadHash = SHA256.Create();
|
||||
private readonly SHA256 payloadHash = SHA256.Create();
|
||||
|
||||
public void AppendBlock(byte[] bytes, int count)
|
||||
{
|
||||
Header.PayloadLength += (ulong)count;
|
||||
Header!.PayloadLength += (ulong)count;
|
||||
this.payloadHash.TransformBlock(bytes, 0, count, bytes, 0);
|
||||
}
|
||||
|
||||
public LargeObject CalculateHash()
|
||||
{
|
||||
this.payloadHash.TransformFinalBlock([], 0, 0);
|
||||
Header.PayloadCheckSum = this.payloadHash.Hash;
|
||||
Header!.PayloadCheckSum = this.payloadHash.Hash;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ulong PayloadLength
|
||||
{
|
||||
get { return Header.PayloadLength; }
|
||||
get { return Header!.PayloadLength; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +66,7 @@ public class LinkObject : Object
|
|||
{
|
||||
public LinkObject(ContainerId containerId, SplitId splitId, LargeObject largeObject) : base (containerId, [])
|
||||
{
|
||||
Header.Split = new Split(splitId)
|
||||
Header!.Split = new Split(splitId)
|
||||
{
|
||||
ParentHeader = largeObject.Header
|
||||
};
|
||||
|
|
|
@ -22,8 +22,6 @@ public class ObjectHeader
|
|||
|
||||
public Split? Split { get; set; }
|
||||
|
||||
public bool ClientCut { get; set; }
|
||||
|
||||
public ObjectHeader(
|
||||
ContainerId containerId,
|
||||
ObjectType type = ObjectType.Regular,
|
||||
|
|
|
@ -4,14 +4,9 @@ using FrostFS.SDK.Cryptography;
|
|||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class OwnerId
|
||||
public class OwnerId(string id)
|
||||
{
|
||||
public string Value { get; }
|
||||
|
||||
public OwnerId(string id)
|
||||
{
|
||||
Value = id;
|
||||
}
|
||||
public string Value { get; } = id;
|
||||
|
||||
public static OwnerId FromKey(ECDsa key)
|
||||
{
|
||||
|
|
12
src/FrostFS.SDK.ModelsV2/PutObjectParameters.cs
Normal file
12
src/FrostFS.SDK.ModelsV2/PutObjectParameters.cs
Normal file
|
@ -0,0 +1,12 @@
|
|||
using System.IO;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class PutObjectParameters
|
||||
{
|
||||
public ObjectHeader? Header { get; set; }
|
||||
|
||||
public Stream? Payload { get; set; }
|
||||
|
||||
public bool ClientCut { get; set; }
|
||||
}
|
8
src/FrostFS.SDK.ModelsV2/SessionToken.cs
Normal file
8
src/FrostFS.SDK.ModelsV2/SessionToken.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class SessionToken(byte[] sessionKey, byte[] id)
|
||||
{
|
||||
public byte[] Id { get; } = id;
|
||||
|
||||
public byte[] SessionKey { get; } = sessionKey;
|
||||
}
|
8
src/FrostFS.SDK.ModelsV2/Signature.cs
Normal file
8
src/FrostFS.SDK.ModelsV2/Signature.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class Signature
|
||||
{
|
||||
public byte[]? Key { get; set; }
|
||||
public byte[]? Sign { get; set; }
|
||||
public SignatureScheme Scheme { get; set; }
|
||||
}
|
7
src/FrostFS.SDK.ModelsV2/SignatureScheme.cs
Normal file
7
src/FrostFS.SDK.ModelsV2/SignatureScheme.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public enum SignatureScheme {
|
||||
EcdsaSha512,
|
||||
EcdsaRfc6979Sha256,
|
||||
EcdsaRfc6979Sha256WalletConnect
|
||||
}
|
50
src/FrostFS.SDK.ModelsV2/SplitId.cs
Normal file
50
src/FrostFS.SDK.ModelsV2/SplitId.cs
Normal file
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class SplitId
|
||||
{
|
||||
private Guid id;
|
||||
|
||||
public SplitId()
|
||||
{
|
||||
this.id = Guid.NewGuid();
|
||||
}
|
||||
public SplitId(Guid guid)
|
||||
{
|
||||
this.id = guid;
|
||||
}
|
||||
|
||||
private SplitId(byte[] binary)
|
||||
{
|
||||
this.id = new Guid(binary);
|
||||
}
|
||||
|
||||
private SplitId(string str)
|
||||
{
|
||||
this.id = new Guid(str);
|
||||
}
|
||||
|
||||
public static SplitId CreateFromBinary(byte[] binaryData)
|
||||
dstepanov-yadro marked this conversation as resolved
Outdated
dstepanov-yadro
commented
CrateFromBinary -> CreateFromBinary CrateFromBinary -> Cr**e**ateFromBinary
PavelGrossSpb
commented
Fixed. Fixed.
dstepanov-yadro
commented
Don't see any changes Don't see any changes
PavelGrossSpb
commented
Pushed. Pushed.
|
||||
{
|
||||
return new SplitId(binaryData);
|
||||
}
|
||||
|
||||
public static SplitId CreateFromString(string stringData)
|
||||
{
|
||||
return new SplitId(stringData);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.id.ToString();
|
||||
}
|
||||
|
||||
public byte[]? ToBinary()
|
||||
{
|
||||
if (this.id == Guid.Empty)
|
||||
return null;
|
||||
|
||||
return this.id.ToByteArray();
|
||||
}
|
||||
}
|
|
@ -1,20 +1,14 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class Split
|
||||
public class Split(SplitId splitId)
|
||||
{
|
||||
public Split() : this(new SplitId())
|
||||
{
|
||||
}
|
||||
|
||||
public Split(SplitId splitId)
|
||||
{
|
||||
SplitId = splitId;
|
||||
}
|
||||
|
||||
public SplitId SplitId { get; private set; }
|
||||
public SplitId SplitId { get; private set; } = splitId;
|
||||
|
||||
public ObjectId? Parent { get; set; }
|
||||
|
||||
|
@ -26,63 +20,3 @@ public class Split
|
|||
|
||||
public List<ObjectId> Children { get; } = [];
|
||||
}
|
||||
|
||||
public enum SignatureScheme {
|
||||
EcdsaSha512,
|
||||
EcdsaRfc6979Sha256,
|
||||
EcdsaRfc6979Sha256WalletConnect
|
||||
}
|
||||
|
||||
public class Signature
|
||||
{
|
||||
public byte[] Key { get; set; }
|
||||
public byte[] Sign { get; set; }
|
||||
public SignatureScheme Scheme { get; set; }
|
||||
}
|
||||
|
||||
public class SplitId
|
||||
{
|
||||
private Guid id;
|
||||
|
||||
public SplitId()
|
||||
{
|
||||
this.id = Guid.NewGuid();
|
||||
}
|
||||
public SplitId(Guid guid)
|
||||
{
|
||||
this.id = guid;
|
||||
}
|
||||
|
||||
private SplitId(byte[] binary)
|
||||
{
|
||||
this.id = new Guid(binary);
|
||||
}
|
||||
|
||||
private SplitId(string str)
|
||||
{
|
||||
this.id = new Guid(str);
|
||||
}
|
||||
|
||||
public static SplitId CrateFromBinary(byte[] binaryData)
|
||||
{
|
||||
return new SplitId(binaryData);
|
||||
}
|
||||
|
||||
public static SplitId CrateFromString(string stringData)
|
||||
{
|
||||
return new SplitId(stringData);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.id.ToString();
|
||||
}
|
||||
|
||||
public byte[]? ToBinary()
|
||||
{
|
||||
if (this.id == Guid.Empty)
|
||||
return null;
|
||||
|
||||
return this.id.ToByteArray();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,21 +2,12 @@ using FrostFS.SDK.ModelsV2.Enums;
|
|||
|
||||
namespace FrostFS.SDK.ModelsV2;
|
||||
|
||||
public class Status
|
||||
public class Status(StatusCode code, string? message = null)
|
||||
{
|
||||
public StatusCode Code { get; set; }
|
||||
public string Message { get; set; }
|
||||
public StatusCode Code { get; set; } = code;
|
||||
public string Message { get; set; } = message ?? string.Empty;
|
||||
|
||||
public Status(StatusCode code, string? message = null)
|
||||
{
|
||||
Code = code;
|
||||
Message = message ?? string.Empty;
|
||||
}
|
||||
|
||||
public bool IsSuccess()
|
||||
{
|
||||
return Code == StatusCode.Success;
|
||||
}
|
||||
public bool IsSuccess => Code == StatusCode.Success;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<EnableNETAnalyzers>true</EnableNETAnalyzers>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Google.Protobuf" Version="3.26.1" />
|
||||
<PackageReference Include="Grpc.Net.Client" Version="2.62.0" />
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace FrostFS.Session;
|
||||
|
||||
public interface IRequest : IVerificableMessage
|
||||
public interface IRequest : IVerifiableMessage
|
||||
{
|
||||
RequestMetaHeader MetaHeader { get; set; }
|
||||
RequestVerificationHeader VerifyHeader { get; set; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace FrostFS.Session;
|
||||
|
||||
public interface IResponse : IVerificableMessage
|
||||
public interface IResponse : IVerifiableMessage
|
||||
{
|
||||
ResponseMetaHeader MetaHeader { get; set; }
|
||||
ResponseVerificationHeader VerifyHeader { get; set; }
|
||||
|
|
|
@ -2,7 +2,7 @@ using Google.Protobuf;
|
|||
|
||||
namespace FrostFS.Session;
|
||||
|
||||
public interface IVerificableMessage : IMessage
|
||||
public interface IVerifiableMessage : IMessage
|
||||
{
|
||||
IMetaHeader GetMetaHeader();
|
||||
void SetMetaHeader(IMetaHeader metaHeader);
|
||||
|
|
|
@ -6,22 +6,22 @@ namespace FrostFS.Container;
|
|||
|
||||
public partial class AnnounceUsedSpaceRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -34,22 +34,22 @@ public partial class AnnounceUsedSpaceRequest : IRequest
|
|||
|
||||
public partial class AnnounceUsedSpaceResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -62,22 +62,22 @@ public partial class AnnounceUsedSpaceResponse : IResponse
|
|||
|
||||
public partial class GetRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -90,22 +90,22 @@ public partial class GetRequest : IRequest
|
|||
|
||||
public partial class GetResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -118,22 +118,22 @@ public partial class GetResponse : IResponse
|
|||
|
||||
public partial class PutRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -146,22 +146,22 @@ public partial class PutRequest : IRequest
|
|||
|
||||
public partial class PutResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -174,22 +174,22 @@ public partial class PutResponse : IResponse
|
|||
|
||||
public partial class DeleteRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -202,22 +202,22 @@ public partial class DeleteRequest : IRequest
|
|||
|
||||
public partial class DeleteResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -230,22 +230,22 @@ public partial class DeleteResponse : IResponse
|
|||
|
||||
public partial class ListRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -258,22 +258,22 @@ public partial class ListRequest : IRequest
|
|||
|
||||
public partial class ListResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -286,22 +286,22 @@ public partial class ListResponse : IResponse
|
|||
|
||||
public partial class SetExtendedACLRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -314,22 +314,22 @@ public partial class SetExtendedACLRequest : IRequest
|
|||
|
||||
public partial class SetExtendedACLResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -342,22 +342,22 @@ public partial class SetExtendedACLResponse : IResponse
|
|||
|
||||
public partial class GetExtendedACLRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -370,22 +370,22 @@ public partial class GetExtendedACLRequest : IRequest
|
|||
|
||||
public partial class GetExtendedACLResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
|
|
@ -5,22 +5,22 @@ namespace FrostFS.Netmap;
|
|||
|
||||
public partial class LocalNodeInfoRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -33,22 +33,22 @@ public partial class LocalNodeInfoRequest : IRequest
|
|||
|
||||
public partial class LocalNodeInfoResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -61,22 +61,22 @@ public partial class LocalNodeInfoResponse : IResponse
|
|||
|
||||
public partial class NetworkInfoRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -89,22 +89,22 @@ public partial class NetworkInfoRequest : IRequest
|
|||
|
||||
public partial class NetworkInfoResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -114,3 +114,60 @@ public partial class NetworkInfoResponse : IResponse
|
|||
return Body;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public partial class NetmapSnapshotRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
||||
public IMessage GetBody()
|
||||
{
|
||||
return Body;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class NetmapSnapshotResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
||||
public IMessage GetBody()
|
||||
{
|
||||
return Body;
|
||||
}
|
||||
}
|
|
@ -6,22 +6,22 @@ namespace FrostFS.Object
|
|||
{
|
||||
public partial class GetRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -34,22 +34,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class GetResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -62,22 +62,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class PutRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -90,22 +90,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class PutResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -118,22 +118,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class PutSingleRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -146,22 +146,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class PutSingleResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -174,22 +174,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class DeleteRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -203,25 +203,25 @@ namespace FrostFS.Object
|
|||
public partial class DeleteResponse : IResponse
|
||||
{
|
||||
[DebuggerStepThrough]
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -235,22 +235,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class HeadRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -263,22 +263,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class HeadResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -290,22 +290,22 @@ namespace FrostFS.Object
|
|||
}
|
||||
public partial class SearchRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -318,22 +318,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class SearchResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -346,22 +346,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class GetRangeRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -374,22 +374,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class GetRangeResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -402,22 +402,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class GetRangeHashRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -430,22 +430,22 @@ namespace FrostFS.Object
|
|||
|
||||
public partial class GetRangeHashResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
|
|
@ -4,22 +4,22 @@ namespace FrostFS.Session;
|
|||
|
||||
public partial class CreateResponse : IResponse
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (ResponseMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (ResponseVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
@ -32,22 +32,22 @@ public partial class CreateResponse : IResponse
|
|||
|
||||
public partial class CreateRequest : IRequest
|
||||
{
|
||||
IMetaHeader IVerificableMessage.GetMetaHeader()
|
||||
IMetaHeader IVerifiableMessage.GetMetaHeader()
|
||||
{
|
||||
return MetaHeader;
|
||||
}
|
||||
|
||||
IVerificationHeader IVerificableMessage.GetVerificationHeader()
|
||||
IVerificationHeader IVerifiableMessage.GetVerificationHeader()
|
||||
{
|
||||
return VerifyHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
void IVerifiableMessage.SetMetaHeader(IMetaHeader metaHeader)
|
||||
{
|
||||
MetaHeader = (RequestMetaHeader)metaHeader;
|
||||
}
|
||||
|
||||
void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
void IVerifiableMessage.SetVerificationHeader(IVerificationHeader verificationHeader)
|
||||
{
|
||||
VerifyHeader = (RequestVerificationHeader)verificationHeader;
|
||||
}
|
||||
|
|
87
src/FrostFS.SDK.Tests/ClientTest.cs
Normal file
87
src/FrostFS.SDK.Tests/ClientTest.cs
Normal file
|
@ -0,0 +1,87 @@
|
|||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ClientTest
|
||||
{
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
|
||||
[Fact]
|
||||
public async void CreateContainerTest()
|
||||
{
|
||||
var factory = new PutContainerMock(this.key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
ContainerGuid = Guid.NewGuid()
|
||||
};
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
null,
|
||||
new NetmapMock(this.key).GetMock().Object,
|
||||
new SessionMock(this.key).GetMock().Object,
|
||||
factory.GetMock().Object,
|
||||
new ObjectMock(this.key).GetMock().Object);
|
||||
|
||||
var result = await fsClient.CreateContainerAsync(new ModelsV2.Container(BasicAcl.PublicRW, factory.PlacementPolicy));
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.NotNull(result.Value);
|
||||
Assert.True(Base58.Encode(factory.ContainerGuid.ToBytes()) == result.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void GetContainerTest()
|
||||
{
|
||||
var factory = new GetContainerMock(this.key)
|
||||
{
|
||||
PlacementPolicy = new PlacementPolicy(true, new Replica(1)),
|
||||
Version = new ModelsV2.Version(2, 13),
|
||||
Acl = BasicAcl.PublicRO,
|
||||
ContainerGuid = Guid.NewGuid(),
|
||||
};
|
||||
|
||||
var settings = Options.Create(new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = "http://localhost:8080"
|
||||
});
|
||||
|
||||
var fsClient = Client.GetTestInstance(
|
||||
settings,
|
||||
null,
|
||||
new NetmapMock(this.key).GetMock().Object,
|
||||
new SessionMock(this.key).GetMock().Object,
|
||||
factory.GetMock().Object,
|
||||
new ObjectMock(this.key).GetMock().Object);
|
||||
|
||||
var cid = new ContainerId(Base58.Encode(factory.ContainerGuid.ToBytes()));
|
||||
|
||||
var context = new Context();
|
||||
|
||||
var result = await fsClient.GetContainerAsync(cid, context);
|
||||
|
||||
Assert.NotNull(result);
|
||||
Assert.Equal(factory.Acl, result.BasicAcl);
|
||||
Assert.Equal(factory.ContainerGuid, result.Nonce);
|
||||
Assert.Equal(0, factory.PlacementPolicy.CompareTo(result.PlacementPolicy));
|
||||
Assert.Equal(factory.Version.ToString(), result.Version!.ToString());
|
||||
}
|
||||
|
||||
// [Fact]
|
||||
// public async void DeleteObjectAsyncTest()
|
||||
// {
|
||||
// }
|
||||
}
|
229
src/FrostFS.SDK.Tests/ClientTestLive.cs
Normal file
229
src/FrostFS.SDK.Tests/ClientTestLive.cs
Normal file
|
@ -0,0 +1,229 @@
|
|||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Interfaces;
|
||||
using FrostFS.SDK.ModelsV2;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using Grpc.Core;
|
||||
using Grpc.Net.Client;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ClientTestLive
|
||||
{
|
||||
private readonly string key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
|
||||
private readonly string url = "http://172.29.238.97:8080";
|
||||
|
||||
[Fact]
|
||||
public async void NetworkMapTest()
|
||||
{
|
||||
var channelOptions = new GrpcChannelOptions
|
||||
{
|
||||
Credentials = ChannelCredentials.Insecure,
|
||||
HttpHandler = new HttpClientHandler()
|
||||
};
|
||||
|
||||
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
|
||||
|
||||
var result = await fsClient.GetNetmapSnapshotAsync();
|
||||
|
||||
Assert.True(result.Epoch > 0);
|
||||
Assert.Single(result.NodeInfoCollection);
|
||||
|
||||
var item = result.NodeInfoCollection[0];
|
||||
Assert.Equal(2, item.Version.Major);
|
||||
Assert.Equal(13, item.Version.Minor);
|
||||
Assert.Equal(NodeState.Online, item.State);
|
||||
Assert.True(item.PublicKey.Length > 0);
|
||||
Assert.Single(item.Addresses);
|
||||
Assert.Equal(9, item.Attributes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void NodeInfoTest()
|
||||
{
|
||||
var channelOptions = new GrpcChannelOptions
|
||||
{
|
||||
Credentials = ChannelCredentials.Insecure,
|
||||
HttpHandler = new HttpClientHandler()
|
||||
};
|
||||
|
||||
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
|
||||
|
||||
var result = await fsClient.GetNodeInfoAsync();
|
||||
|
||||
Assert.Equal(2, result.Version.Major);
|
||||
Assert.Equal(13, result.Version.Minor);
|
||||
Assert.Equal(NodeState.Online, result.State);
|
||||
Assert.True(result.PublicKey.Length > 0);
|
||||
Assert.Single(result.Addresses);
|
||||
Assert.Equal(9, result.Attributes.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void SimpleScenarioTest()
|
||||
{
|
||||
var channelOptions = new GrpcChannelOptions
|
||||
{
|
||||
Credentials = ChannelCredentials.Insecure,
|
||||
HttpHandler = new HttpClientHandler()
|
||||
};
|
||||
|
||||
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
|
||||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
var containerId = await fsClient.CreateContainerAsync(
|
||||
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
|
||||
|
||||
var context = new Context { Timeout = TimeSpan.FromSeconds(10) };
|
||||
|
||||
var container = await GetContainer(fsClient, containerId, context);
|
||||
|
||||
Assert.NotNull(container);
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
Header = new ObjectHeader(
|
||||
containerId: containerId,
|
||||
type: ObjectType.Regular,
|
||||
new ObjectAttribute("fileName", "test")),
|
||||
Payload = new MemoryStream([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
|
||||
ClientCut = false
|
||||
};
|
||||
|
||||
var objectId = await fsClient.PutObjectAsync(param);
|
||||
|
||||
var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", "test");
|
||||
|
||||
bool hasObject = false;
|
||||
await foreach (var objId in fsClient.SearchObjectsAsync(containerId, [filter]))
|
||||
{
|
||||
hasObject = true;
|
||||
|
||||
var objHeader = await fsClient.GetObjectHeadAsync(containerId, objectId);
|
||||
Assert.Equal(10u, objHeader.PayloadLength);
|
||||
Assert.Single(objHeader.Attributes);
|
||||
Assert.Equal("fileName", objHeader.Attributes.First().Key);
|
||||
Assert.Equal("test", objHeader.Attributes.First().Value);
|
||||
}
|
||||
|
||||
Assert.True(hasObject);
|
||||
|
||||
var @object = await fsClient.GetObjectAsync(containerId, objectId!);
|
||||
|
||||
Assert.Equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], @object.Payload);
|
||||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
await Task.Delay(2000);
|
||||
|
||||
await foreach (var _ in fsClient.ListContainersAsync())
|
||||
{
|
||||
Assert.Fail("Containers exist");
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ClientCutScenarioTest()
|
||||
{
|
||||
var channelOptions = new GrpcChannelOptions
|
||||
{
|
||||
Credentials = ChannelCredentials.Insecure,
|
||||
HttpHandler = new HttpClientHandler()
|
||||
};
|
||||
|
||||
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
|
||||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
var containerId = await fsClient.CreateContainerAsync(
|
||||
new ModelsV2.Container(BasicAcl.PublicRW, new PlacementPolicy(true, new Replica(1))));
|
||||
|
||||
var context = new Context { Timeout = TimeSpan.FromSeconds(10) };
|
||||
var container = await GetContainer(fsClient, containerId, context);
|
||||
|
||||
Assert.NotNull(container);
|
||||
|
||||
var param = new PutObjectParameters
|
||||
{
|
||||
Header = new ObjectHeader(
|
||||
containerId: containerId,
|
||||
type: ObjectType.Regular,
|
||||
new ObjectAttribute("fileName", "test")),
|
||||
Payload = new MemoryStream([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
|
||||
ClientCut = true
|
||||
};
|
||||
|
||||
var objectId = await fsClient.PutObjectAsync(param);
|
||||
|
||||
var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", "test");
|
||||
|
||||
bool hasObject = false;
|
||||
await foreach (var objId in fsClient.SearchObjectsAsync(containerId, [filter]))
|
||||
{
|
||||
hasObject = true;
|
||||
|
||||
var objHeader = await fsClient.GetObjectHeadAsync(containerId, objectId);
|
||||
Assert.Equal(10u, objHeader.PayloadLength);
|
||||
Assert.Single(objHeader.Attributes);
|
||||
Assert.Equal("fileName", objHeader.Attributes.First().Key);
|
||||
Assert.Equal("test", objHeader.Attributes.First().Value);
|
||||
}
|
||||
|
||||
Assert.True(hasObject);
|
||||
|
||||
var @object = await fsClient.GetObjectAsync(containerId, objectId!);
|
||||
|
||||
Assert.Equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 0], @object.Payload);
|
||||
|
||||
await Cleanup(fsClient);
|
||||
|
||||
await Task.Delay(2000);
|
||||
|
||||
await foreach (var _ in fsClient.ListContainersAsync())
|
||||
{
|
||||
Assert.Fail("Containers exist");
|
||||
}
|
||||
}
|
||||
|
||||
private static IOptions<ClientSettings> GetOptions(string key, string url)
|
||||
{
|
||||
var settings = new ClientSettings
|
||||
{
|
||||
Key = key,
|
||||
Host = url
|
||||
};
|
||||
|
||||
return Options.Create(settings);
|
||||
}
|
||||
|
||||
static async Task Cleanup(IFrostFSClient fsClient)
|
||||
{
|
||||
await foreach (var cid in fsClient.ListContainersAsync())
|
||||
{
|
||||
await fsClient.DeleteContainerAsync(cid);
|
||||
}
|
||||
}
|
||||
|
||||
static async Task<ModelsV2.Container> GetContainer(IFrostFSClient fsClient, ContainerId id, Context ctx)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
await Task.Delay(100);
|
||||
return await fsClient.GetContainerAsync(id, ctx);
|
||||
}
|
||||
catch (ApplicationException)
|
||||
{
|
||||
if (DateTime.UtcNow >= ctx.Deadline)
|
||||
throw new TimeoutException();
|
||||
}
|
||||
catch (Grpc.Core.RpcException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
using System.Security.Cryptography;
|
||||
using FrostFS.Container;
|
||||
using Moq;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ModelsV2.Enums;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public abstract class ServiceBase(string key)
|
||||
{
|
||||
public ECDsa Key { get; private set; } = key.LoadWif();
|
||||
public ModelsV2.Version Version { get; set; } = DefaultVersion;
|
||||
public BasicAcl Acl { get; set; } = DefaultAcl;
|
||||
public PlacementPolicy PlacementPolicy { get; set; } = DefaultPlacementPolicy;
|
||||
|
||||
public static ModelsV2.Version DefaultVersion { get; } = new(2, 13);
|
||||
public static BasicAcl DefaultAcl { get; } = BasicAcl.PublicRW;
|
||||
public static PlacementPolicy DefaultPlacementPolicy { get; } = new PlacementPolicy(true, new Replica(1));
|
||||
}
|
||||
|
||||
public abstract class ContainerServiceBase(string key) : ServiceBase (key)
|
||||
{
|
||||
public Guid ContainerGuid { get; set; } = Guid.NewGuid();
|
||||
|
||||
public abstract Mock<ContainerService.ContainerServiceClient> GetMock();
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class DeleteContainerMock(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ContainerService.ContainerServiceClient>();
|
||||
|
||||
var v = mock.Setup(x => x.DeleteAsync(
|
||||
It.IsAny<DeleteRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()));
|
||||
|
||||
|
||||
v.Returns((Object.DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
var deleteResponse = new Object.DeleteResponse
|
||||
{
|
||||
Body = new Object.DeleteResponse.Types.Body
|
||||
{
|
||||
Tombstone = new Refs.Address
|
||||
{
|
||||
ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
|
||||
ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader()
|
||||
};
|
||||
|
||||
var metadata = new Metadata();
|
||||
|
||||
return new AsyncUnaryCall<Object.DeleteResponse>(
|
||||
Task.FromResult(deleteResponse),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// objectServiceClientMock.Setup(x => x.Head(It.IsAny<Object.HeadRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
// .Returns((Object.DeleteRequest r, Metadata m, DateTime dt, CancellationToken ct) =>
|
||||
// {
|
||||
// return new
|
||||
// {
|
||||
// Body = new Object.DeleteResponse.Types.Body
|
||||
// {
|
||||
// Tombstone = new Refs.Address
|
||||
// {
|
||||
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
|
||||
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// });
|
||||
|
||||
|
||||
|
163
src/FrostFS.SDK.Tests/ContainerServiceMocks/GetContainerMock.cs
Normal file
163
src/FrostFS.SDK.Tests/ContainerServiceMocks/GetContainerMock.cs
Normal file
|
@ -0,0 +1,163 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ModelsV2.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class GetContainerMock(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ContainerService.ContainerServiceClient>();
|
||||
|
||||
var grpcVersion = Version.ToGrpcMessage();
|
||||
|
||||
var getResponse = new GetResponse
|
||||
{
|
||||
Body = new GetResponse.Types.Body
|
||||
{
|
||||
Container = new Container.Container
|
||||
{
|
||||
Version = grpcVersion,
|
||||
Nonce = ByteString.CopyFrom(ContainerGuid.ToBytes()),
|
||||
BasicAcl = (uint)Acl,
|
||||
PlacementPolicy = PlacementPolicy.ToGrpcMessage()
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader
|
||||
{
|
||||
Version = grpcVersion,
|
||||
Epoch = 100,
|
||||
Ttl = 1
|
||||
}
|
||||
};
|
||||
|
||||
getResponse.VerifyHeader = GetResponseVerificationHeader(getResponse);
|
||||
|
||||
var metadata = new Metadata();
|
||||
var getContainerResponse = new AsyncUnaryCall<GetResponse>(
|
||||
Task.FromResult(getResponse),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
|
||||
mock.Setup(x => x.GetAsync(
|
||||
It.IsAny<GetRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((GetRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return getContainerResponse;
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private ResponseVerificationHeader GetResponseVerificationHeader(GetResponse response)
|
||||
{
|
||||
var verifyHeader = new ResponseVerificationHeader
|
||||
{
|
||||
MetaSignature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
|
||||
},
|
||||
BodySignature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
|
||||
},
|
||||
OriginSignature = new Refs.Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = FrostFS.Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData([]))
|
||||
}
|
||||
};
|
||||
|
||||
return verifyHeader;
|
||||
}
|
||||
}
|
||||
|
||||
// objectServiceClientMock.Setup(
|
||||
// x => x.Put(It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
// .Returns((Metadata m, DateTime dt, CancellationToken ct) =>
|
||||
// {
|
||||
// return new AsyncClientStreamingCall<FrostFS.Object.PutRequest, FrostFS.Object.PutResponse>(null, null, null, null, null, null);
|
||||
|
||||
// //IClientStreamWriter<TRequest> requestStream, Task<TResponse> responseAsync, Task<Metadata> responseHeadersAsync, Func<Status> getStatusFunc, Func<Metadata> getTrailersFunc, Action disposeAction
|
||||
// });
|
||||
|
||||
// return objectServiceClientMock;
|
||||
// }
|
||||
|
||||
|
||||
// }
|
||||
|
||||
|
||||
// public virtual global::FrostFS.Object.HeadResponse Head(global::FrostFS.Object.HeadRequest request, grpc::Metadata headers = null, global::System.DateTime? deadline = null, global::System.Threading.CancellationToken cancellationToken = default(global::System.Threading.CancellationToken))
|
||||
// {
|
||||
// return Head(request, new grpc::CallOptions(headers, deadline, cancellationToken));
|
||||
// }
|
||||
|
||||
// objectServiceClientMock.Setup(x => x.Head(It.IsAny<Object.HeadRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime>(), It.IsAny<CancellationToken>()))
|
||||
// .Returns((Object.DeleteRequest r, Metadata m, DateTime dt, CancellationToken ct) =>
|
||||
// {
|
||||
// return new
|
||||
// {
|
||||
// Body = new Object.DeleteResponse.Types.Body
|
||||
// {
|
||||
// Tombstone = new Refs.Address
|
||||
// {
|
||||
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
|
||||
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
// });
|
||||
|
||||
|
||||
// objectServiceClientMock.Setup(x => x.Delete(It.IsAny<Object.DeleteRequest>(), It.IsAny<Metadata>(), It.IsAny<DateTime?>(), It.IsAny<CancellationToken>()))
|
||||
// .Returns((Object.DeleteRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
// {
|
||||
// return new Object.DeleteResponse
|
||||
// {
|
||||
// Body = new Object.DeleteResponse.Types.Body
|
||||
// {
|
||||
// Tombstone = new Refs.Address
|
||||
// {
|
||||
// ContainerId = new Refs.ContainerID { Value = ByteString.CopyFrom([1, 2, 3]) },
|
||||
// ObjectId = new Refs.ObjectID { Value = ByteString.CopyFrom([4, 5, 6]) }
|
||||
// }
|
||||
// },
|
||||
// MetaHeader = new ResponseMetaHeader()
|
||||
// {
|
||||
// },
|
||||
// VerifyHeader = new ResponseVerificationHeader()
|
||||
// {
|
||||
// MetaSignature = new Refs.Signature
|
||||
// {
|
||||
// Key = ByteString.CopyFrom(_key.PublicKey()),
|
||||
// Scheme = Refs.SignatureScheme.EcdsaRfc6979Sha256,
|
||||
// Sign = ByteString.CopyFrom(_key.SignData(Array.Empty<byte>()))
|
||||
|
||||
// // ByteString.CopyFrom(_key.SignData(grpcHeader.Split.Parent.ToByteArray())),
|
||||
// }
|
||||
// }
|
||||
|
||||
// };
|
||||
// });
|
|
@ -0,0 +1,88 @@
|
|||
using FrostFS.Container;
|
||||
using FrostFS.Session;
|
||||
using Google.Protobuf;
|
||||
using Grpc.Core;
|
||||
using Moq;
|
||||
using FrostFS.SDK.ClientV2;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
|
||||
using FrostFS.SDK.ClientV2.Mappers.GRPC;
|
||||
using FrostFS.SDK.Cryptography;
|
||||
using FrostFS.Refs;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class PutContainerMock(string key) : ContainerServiceBase(key)
|
||||
{
|
||||
public override Mock<ContainerService.ContainerServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ContainerService.ContainerServiceClient>();
|
||||
|
||||
PutResponse response = new()
|
||||
{
|
||||
Body = new PutResponse.Types.Body
|
||||
{
|
||||
ContainerId = new ContainerID
|
||||
{
|
||||
Value = ByteString.CopyFrom(ContainerGuid.ToBytes())
|
||||
}
|
||||
},
|
||||
MetaHeader = new ResponseMetaHeader
|
||||
{
|
||||
Version = Version is null ? DefaultVersion.ToGrpcMessage() : Version.ToGrpcMessage(),
|
||||
Epoch = 100,
|
||||
Ttl = 1
|
||||
}
|
||||
};
|
||||
|
||||
response.VerifyHeader = PutResponseVerificationHeader(response);
|
||||
|
||||
var metadata = new Metadata();
|
||||
var putContainerResponse = new AsyncUnaryCall<PutResponse>(
|
||||
Task.FromResult(response),
|
||||
Task.FromResult(metadata),
|
||||
() => new Grpc.Core.Status(StatusCode.OK, string.Empty),
|
||||
() => metadata,
|
||||
() => { });
|
||||
|
||||
mock.Setup(x => x.PutAsync(
|
||||
It.IsAny<PutRequest>(),
|
||||
It.IsAny<Metadata>(),
|
||||
It.IsAny<DateTime?>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.Returns((PutRequest r, Metadata m, DateTime? dt, CancellationToken ct) =>
|
||||
{
|
||||
Verifier.CheckRequest(r);
|
||||
|
||||
return putContainerResponse;
|
||||
});
|
||||
|
||||
return mock;
|
||||
}
|
||||
|
||||
private ResponseVerificationHeader PutResponseVerificationHeader(PutResponse response)
|
||||
{
|
||||
var verifyHeader = new ResponseVerificationHeader
|
||||
{
|
||||
MetaSignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.MetaHeader.ToByteArray()))
|
||||
},
|
||||
BodySignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData(response.GetBody().ToByteArray()))
|
||||
},
|
||||
OriginSignature = new Signature
|
||||
{
|
||||
Key = ByteString.CopyFrom(Key.PublicKey()),
|
||||
Scheme = SignatureScheme.EcdsaRfc6979Sha256,
|
||||
Sign = ByteString.CopyFrom(Key.SignData([]))
|
||||
}
|
||||
};
|
||||
|
||||
return verifyHeader;
|
||||
}
|
||||
}
|
14
src/FrostFS.SDK.Tests/NetmapMock.cs
Normal file
14
src/FrostFS.SDK.Tests/NetmapMock.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Moq;
|
||||
using FrostFS.Netmap;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class NetmapMock(string key) : ServiceBase(key)
|
||||
{
|
||||
public Mock<NetmapService.NetmapServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<NetmapService.NetmapServiceClient>();
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
14
src/FrostFS.SDK.Tests/ObjectMock.cs
Normal file
14
src/FrostFS.SDK.Tests/ObjectMock.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Moq;
|
||||
using FrostFS.Object;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class ObjectMock(string key) : ServiceBase(key)
|
||||
{
|
||||
public Mock<ObjectService.ObjectServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<ObjectService.ObjectServiceClient>();
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
14
src/FrostFS.SDK.Tests/SessionMock.cs
Normal file
14
src/FrostFS.SDK.Tests/SessionMock.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using Moq;
|
||||
using FrostFS.Session;
|
||||
|
||||
namespace FrostFS.SDK.Tests;
|
||||
|
||||
public class SessionMock(string key) : ServiceBase(key)
|
||||
{
|
||||
public Mock<SessionService.SessionServiceClient> GetMock()
|
||||
{
|
||||
var mock = new Mock<SessionService.SessionServiceClient>();
|
||||
|
||||
return mock;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue
If
Client
is disposable, then how it can be disposed having private constructor?Thx, I forgot to inherit the interface from IDisposable
public interface IFrostFSClient : IDisposable
this way is recommended:
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
or Dispose directly
var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
...
fsClient.Dispose();