[#11] Add Network Snapshot
All checks were successful
DCO / DCO (pull_request) Successful in 41s
All checks were successful
DCO / DCO (pull_request) Successful in 41s
Signed-off-by: Pavel Gross <p.gross@yadro.com>
This commit is contained in:
parent
b69d22966f
commit
c988ff3c76
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);
|
||||
}
|
||||
|
||||
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>
|
||||
|
||||
<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()
|
||||
{
|
||||
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)
|
||||
{
|
||||
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