[#10] Netmap snapshot, options, metrics #11

Merged
PavelGrossSpb merged 1 commit from PavelGrossSpb/frostfs-sdk-csharp:Netmap_Options_Metrics into master 2024-06-26 09:30:39 +00:00
84 changed files with 2238 additions and 933 deletions

1
.gitignore vendored
View file

@ -18,6 +18,7 @@ vendor/
# IDE
.idea
.vscode
.vs
# coverage
coverage.txt

View file

@ -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

View file

@ -1,93 +1,223 @@
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using FrostFS.Container;
using FrostFS.Container;
using FrostFS.Netmap;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.Session;
using Grpc.Core;
using Grpc.Net.Client;
using static FrostFS.Netmap.NetworkConfig.Types;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Version = FrostFS.SDK.ModelsV2.Version;
namespace FrostFS.SDK.ClientV2;
public partial class Client: IFrostFSClient
public class Client : IFrostFSClient
{
private GrpcChannel? _channel;
private readonly ECDsa _key;
public readonly OwnerId OwnerId;
public readonly Version Version = new(2, 13);
private bool isDisposed;
private readonly Dictionary<string, ulong> NetworkSettings = [];
internal ClientEnvironment ClientCtx { get; set; }
private ContainerService.ContainerServiceClient? _containerServiceClient;
private NetmapService.NetmapServiceClient? _netmapServiceClient;
private ObjectService.ObjectServiceClient? _objectServiceClient;
private SessionService.SessionServiceClient? _sessionServiceClient;
public static IFrostFSClient GetInstance(string key, string host)
public static IFrostFSClient GetInstance(IOptions<ClientSettings> clientOptions, GrpcChannelOptions channelOptions)
{
return new Client(key, host);
return new Client(clientOptions, channelOptions);
}
private Client(string key, string host)
/// <summary>
/// For test only. Provide custom implementation or mock object to inject required logic instead of internal gRPC client.
/// </summary>
/// <param name="clientOptions">Global setting for client</param>
/// <param name="channelOptions">Setting for gRPC cjannel</param>
/// <param name="containerService">ContainerService.ContainerServiceClient implementation</param>
/// <param name="netmapService">Netmap.NetmapService.NetmapServiceClient implementation</param>
/// <param name="sessionService">Session.SessionService.SessionServiceClient implementation</param>
/// <param name="objectService">Object.ObjectService.ObjectServiceClient implementation</param>
/// <returns></returns>
public static IFrostFSClient GetTestInstance(
IOptions<ClientSettings> clientOptions,
GrpcChannelOptions? channelOptions,
NetmapService.NetmapServiceClient netmapService,
SessionService.SessionServiceClient sessionService,
ContainerService.ContainerServiceClient containerService,
ObjectService.ObjectServiceClient objectService)
{
// TODO: Развязать клиент и реализацию GRPC
_key = key.LoadWif();
OwnerId = OwnerId.FromKey(_key);
InitGrpcChannel(host);
InitContainerClient();
InitNetmapClient();
InitObjectClient();
InitSessionClient();
return new Client(clientOptions, channelOptions, containerService, netmapService, sessionService, objectService);
}
dstepanov-yadro marked this conversation as resolved Outdated

If Client is disposable, then how it can be disposed having private constructor?

If `Client` is disposable, then how it can be disposed having private constructor?

Thx, I forgot to inherit the interface from IDisposable

public interface IFrostFSClient : IDisposable

this way is recommended:
using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);

or Dispose directly
var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);
...
fsClient.Dispose();

Thx, I forgot to inherit the interface from IDisposable ``public interface IFrostFSClient : IDisposable`` this way is recommended: ``using var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);`` or Dispose directly `` var fsClient = Client.GetInstance(GetOptions(this.key, this.url), channelOptions);`` ``...`` ``fsClient.Dispose();``
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()
});
}
}

View file

@ -6,9 +6,14 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="8.0.0" />
<PackageReference Include="Moq.AutoMock" Version="3.5.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
<PackageReference Include="System.Diagnostics.DiagnosticSource" Version="8.0.1" />
</ItemGroup>
dstepanov-yadro marked this conversation as resolved Outdated

Why cross-platform SDK have Windows dependency?

Why cross-platform SDK have Windows dependency?

Right. These are some artefacts from my research. Wrong references have been removed.

Right. These are some artefacts from my research. Wrong references have been removed.
<ItemGroup>

View file

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

View file

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

View file

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

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

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

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

View file

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

View file

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

View file

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

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

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

View file

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

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

View file

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

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

View file

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

View file

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

View file

@ -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();

View file

@ -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
{

View file

@ -0,0 +1,40 @@
using FrostFS.SDK.ModelsV2;
using Grpc.Net.Client;
using System;
using System.Security.Cryptography;
namespace FrostFS.SDK.ClientV2;
public class ClientEnvironment(ECDsa key, OwnerId owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
{
internal OwnerId Owner { get; } = owner;
internal GrpcChannel Channel { get; private set; } = channel;
internal ECDsa Key { get; } = key;
internal ModelsV2.Version Version { get; } = version;
internal NetworkSettings? NetworkSettings { get; set; }
internal ContainerServiceProvider? ContainerService { get; set; }
internal NetmapServiceProvider? NetmapService { get; set; }
internal SessionServiceProvider? SessionService { get; set; }
internal ObjectServiceProvider? ObjectService { get; set; }
internal bool Initialized =>
ContainerService != null
&& NetmapService != null
&& SessionService != null
&& ObjectService != null;
public void Dispose()
{
dstepanov-yadro marked this conversation as resolved Outdated

Looks like the same result could be the same result can be achieved with the interceptor list for GrpcChannel. If it is really required I'm ok with this. But other option is to allow to pass GrpcChannel to Client, so SDK user could add any interceptors to grpc pipeline.

Looks like the same result could be the same result can be achieved with the interceptor list for GrpcChannel. If it is really required I'm ok with this. But other option is to allow to pass GrpcChannel to `Client`, so SDK user could add any interceptors to grpc pipeline.

Good idea. GRPC channal is available now to add any interceptors

Good idea. GRPC channal is available now to add any interceptors
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
Channel.Dispose();
}
}
}

View file

@ -0,0 +1,8 @@
namespace FrostFS.SDK.ClientV2;
internal class ContextAccessor(ClientEnvironment context)
{
protected ClientEnvironment Context { get; set; } = context;
}

View 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; } = [];
}

View file

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

View file

@ -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];

View file

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

View file

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

View file

@ -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()}");
}
}

View file

@ -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")]

View file

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

View file

@ -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)
{

View file

@ -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" />

View file

@ -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;

View file

@ -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];

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

View file

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

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

View file

@ -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,

View file

@ -6,6 +6,10 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
</ItemGroup>

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

View file

@ -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()
{

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

View file

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

View file

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

View file

@ -0,0 +1,9 @@
using System;
using System.Threading.Tasks;
namespace FrostFS.SDK.ModelsV2;
public interface IObjectReader : IDisposable
{
Task<byte[]?> ReadChunk();
}

View file

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

View file

@ -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,

View file

@ -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)
{

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

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

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

View file

@ -0,0 +1,7 @@
namespace FrostFS.SDK.ModelsV2;
public enum SignatureScheme {
EcdsaSha512,
EcdsaRfc6979Sha256,
EcdsaRfc6979Sha256WalletConnect
}

View file

@ -0,0 +1,50 @@
using System;
namespace FrostFS.SDK.ModelsV2;
public class SplitId
{
private Guid id;
public SplitId()
{
this.id = Guid.NewGuid();
}
public SplitId(Guid guid)
{
this.id = guid;
}
private SplitId(byte[] binary)
{
this.id = new Guid(binary);
}
private SplitId(string str)
{
this.id = new Guid(str);
}
public static SplitId CreateFromBinary(byte[] binaryData)
dstepanov-yadro marked this conversation as resolved Outdated

CrateFromBinary -> CreateFromBinary

CrateFromBinary -> Cr**e**ateFromBinary

Fixed.

Fixed.

Don't see any changes

Don't see any changes

Pushed.

Pushed.
{
return new SplitId(binaryData);
}
public static SplitId CreateFromString(string stringData)
{
return new SplitId(stringData);
}
public override string ToString()
{
return this.id.ToString();
}
public byte[]? ToBinary()
{
if (this.id == Guid.Empty)
return null;
return this.id.ToByteArray();
}
}

View file

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

View file

@ -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()
{

View file

@ -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" />

View file

@ -1,6 +1,6 @@
namespace FrostFS.Session;
public interface IRequest : IVerificableMessage
public interface IRequest : IVerifiableMessage
{
RequestMetaHeader MetaHeader { get; set; }
RequestVerificationHeader VerifyHeader { get; set; }

View file

@ -1,6 +1,6 @@
namespace FrostFS.Session;
public interface IResponse : IVerificableMessage
public interface IResponse : IVerifiableMessage
{
ResponseMetaHeader MetaHeader { get; set; }
ResponseVerificationHeader VerifyHeader { get; set; }

View file

@ -2,7 +2,7 @@ using Google.Protobuf;
namespace FrostFS.Session;
public interface IVerificableMessage : IMessage
public interface IVerifiableMessage : IMessage
{
IMetaHeader GetMetaHeader();
void SetMetaHeader(IMetaHeader metaHeader);

View file

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

View file

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

View file

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

View file

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

View 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()
// {
// }
}

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

View file

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

View file

@ -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]) }
// }
// }
// };
// });

View 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())),
// }
// }
// };
// });

View file

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

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

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

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