[#23] Client: Refactoring to optimize memory usage

Signed-off-by: Pavel Gross <p.gross@yando.com>
This commit is contained in:
Pavel Gross 2024-09-11 10:44:30 +03:00
parent 1a02ac2ae7
commit 6562aa27a5
141 changed files with 1722 additions and 896 deletions

View file

@ -1,16 +1,13 @@

Microsoft Visual Studio Solution File, Format Version 12.00
#
VisualStudioVersion = 17.5.002.0
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}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}"
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}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrostFS.SDK.Tests", "src\FrostFS.SDK.Tests\FrostFS.SDK.Tests.csproj", "{8FDA7E0D-9C75-4874-988E-6592CD28F76C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -26,10 +23,6 @@ Global
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3D804F4A-B0B2-47A5-B006-BE447BE64B50}.Release|Any CPU.Build.0 = Release|Any CPU
{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{14DC8AC7-E310-40C2-ACDF-5BE78FC0E1B2}.Release|Any CPU.Build.0 = Release|Any CPU
{5012EF96-9C9E-4E77-BC78-B4111EE54107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{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

175
README.md
View file

@ -21,137 +21,62 @@ neo-go wallet export -w <path_to_your_wallet> -d <address_from_p1>
### Container
```csharp
using FrostFS.SDK;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
var fsClient = Client.GetInstance(<your_key>, <your_host>);
using Microsoft.Extensions.Options;
// List containers
var containersIds = await fsClient.ListContainersAsync();
var Key = "KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq";
var Host = "http://172.22.33.44:8080";
// Create container
var placementPolicy = new PlacementPolicy(true, new Replica(1));
var containerId = await fsClient.CreateContainerAsync(
new Container(
BasicAcl.PublicRW,
placementPolicy
)
);
// Get container
var container = await fsClient.GetContainerAsync(cId);
// Delete container
await fsClient.DeleteContainerAsync(containerId);
```
### Object
```csharp
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
var fsClient = Client.GetInstance(<your_key>, <your_host>);
// Search regular objects
var objectsIds = await fsClient.SearchObjectAsync(
cId,
ObjectFilter.RootFilter()
);
// Put object
var f = File.OpenRead("cat.jpg");
var cat = new ObjectHeader(
containerId: cId,
type: ObjectType.Regular,
new ObjectAttribute("Filename", "cat.jpg")
);
var oId = await fsClient.PutObjectAsync(cat, f);
// Get object header
var objHeader = await fsClient.GetObjectHeadAsync(cId, oId);
// Get object
var obj = await fsClient.GetObjectAsync(cId, oId);
```
### Custom client cut
```csharp
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.SDK.ClientV2.Extensions;
using FrostFS.SDK.ClientV2.Interfaces;
var fsClient = Client.GetInstance(<your_key>, <your_host>);
ContainerId containerId = <containerId>;
string fileName = <fileName>;
await PutObjectClientCut(fsClient, containerId, fileName);
static async Task<ObjectId?> PutObjectClientCut(IFrostFSClient fsClient, ContainerId containerId, string fileName)
var options = Options.Create(new SingleOwnerClientSettings
{
List<ObjectId> sentObjectIds = [];
FrostFS.SDK.ModelsV2.Object? currentObject;
Key = Key,
Host = Host
});
var partSize = 1024 * 1024;
var buffer = new byte[partSize];
using var client = Client.GetSingleOwnerInstance(options);
var largeObject = new LargeObject(containerId);
var split = new Split();
var fileInfo = new FileInfo(fileName);
var fullLength = (ulong)fileInfo.Length;
var fileNameAttribute = new ObjectAttribute("fileName", fileInfo.Name);
using var stream = File.OpenRead(fileName);
while (true)
{
var bytesCount = await stream.ReadAsync(buffer.AsMemory(0, partSize));
split.Previous = sentObjectIds.LastOrDefault();
largeObject.AppendBlock(buffer, bytesCount);
currentObject = new FrostFS.SDK.ModelsV2.Object(containerId, bytesCount < partSize ? buffer.Take(bytesCount).ToArray() : buffer)
.AddAttribute(fileNameAttribute)
.SetSplit(split);
if (largeObject.PayloadLength == fullLength)
break;
var objectId = await fsClient.PutSingleObjectAsync(currentObject);
sentObjectIds.Add(objectId);
}
if (sentObjectIds.Any())
{
largeObject.CalculateHash()
.AddAttribute(fileNameAttribute);
currentObject.SetParent(largeObject);
var objectId = await fsClient.PutSingleObjectAsync(currentObject);
sentObjectIds.Add(objectId);
var linkObject = new LinkObject(containerId, split.SplitId, largeObject)
.AddChildren(sentObjectIds)
.AddAttribute(fileNameAttribute);
_ = await fsClient.PutSingleObjectAsync(linkObject);
return currentObject.GetParentId();
}
return await fsClient.PutSingleObjectAsync(currentObject);
await foreach (var cid in client.ListContainersAsync())
{
await client.DeleteContainerAsync(new PrmContainerDelete(cid));
}
```
var placementPolicy = new FrostFsPlacementPolicy(true, new FrostFsReplica(1));
var createContainerParam = new PrmContainerCreate(
new FrostFsContainerInfo(BasicAcl.PublicRW, new FrostFsPlacementPolicy(true, new FrostFsReplica(1))));
var containerId = await client.CreateContainerAsync(createContainerParam);
using var fileStream = File.OpenRead(@"C:\Users\Paul\Pictures\cat.jpeg");
var param = new PrmObjectPut
{
Header = new FrostFsObjectHeader(
containerId: containerId,
type: FrostFsObjectType.Regular,
[new FrostFsAttribute("fileName", "test")]),
Payload = fileStream
};
FrostFsObjectId objectId = await client.PutObjectAsync(param);
var filter = new FilterByAttribute(FrostFsObjectMatchType.Equals, "fileName", "test");
await foreach (var objId in client.SearchObjectsAsync(new PrmObjectSearch(containerId) { Filters = [filter] }))
{
var objHeader = await client.GetObjectHeadAsync(new PrmObjectHeadGet(containerId, objId));
}
var @object = await client.GetObjectAsync(new PrmObjectGet(containerId, objectId));
var downloadedBytes = new byte[@object.Header.PayloadLength];
MemoryStream ms = new(downloadedBytes);
ReadOnlyMemory<byte>? chunk = null;
while ((chunk = await @object.ObjectReader!.ReadChunk()) != null)
{
ms.Write(chunk.Value.Span);
}
```

View file

@ -1,6 +1,4 @@

using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Memory;
namespace FrostFS.SDK.ClientV2
{

View file

@ -1,21 +1,21 @@
using FrostFS.Container;
using FrostFS.Netmap;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.Session;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Options;
using System;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using Version = FrostFS.SDK.ModelsV2.Version;
using FrostFS.Container;
using FrostFS.Netmap;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Interfaces;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using Grpc.Core;
using Grpc.Core.Interceptors;
using Grpc.Net.Client;
using Microsoft.Extensions.Options;
namespace FrostFS.SDK.ClientV2;
@ -70,14 +70,14 @@ public class Client : IFrostFSClient
ObjectService.ObjectServiceClient objectService)
{
var ecdsaKey = settings.Value.Key.LoadWif();
OwnerId.FromKey(ecdsaKey);
FrostFsOwner.FromKey(ecdsaKey);
ClientCtx = new ClientEnvironment(
client: this,
key: ecdsaKey,
owner: OwnerId.FromKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: InitGrpcChannel(settings.Value.Host, channelOptions),
version: new Version(2, 13));
version: new FrostFsVersion(2, 13));
ContainerServiceClient = containerService;
NetmapServiceClient = netmapService;
@ -98,7 +98,7 @@ public class Client : IFrostFSClient
key: null,
owner: null,
channel: channel,
version: new Version(2, 13));
version: new FrostFsVersion(2, 13));
// TODO: define timeout logic
// CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20) });
@ -117,9 +117,9 @@ public class Client : IFrostFSClient
ClientCtx = new ClientEnvironment(
this,
key: ecdsaKey,
owner: OwnerId.FromKey(ecdsaKey),
owner: FrostFsOwner.FromKey(ecdsaKey),
channel: channel,
version: new Version(2, 13));
version: new FrostFsVersion(2, 13));
// TODO: define timeout logic
CheckFrostFsVersionSupport(new Context { Timeout = TimeSpan.FromSeconds(20)});
@ -135,26 +135,26 @@ public class Client : IFrostFSClient
{
if (disposing && !isDisposed)
{
ClientCtx.Dispose();
ClientCtx?.Dispose();
isDisposed = true;
}
}
#region ContainerImplementation
public Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args)
public Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
{
var service = GetContainerService(args);
return service.GetContainerAsync(args);
}
public IAsyncEnumerable<ContainerId> ListContainersAsync(PrmContainerGetAll? args = null)
public IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null)
{
args ??= new PrmContainerGetAll();
var service = GetContainerService(args);
return service.ListContainersAsync(args);
}
public Task<ContainerId> CreateContainerAsync(PrmContainerCreate args)
public Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args)
{
var service = GetContainerService(args);
return service.CreateContainerAsync(args);
@ -168,14 +168,14 @@ public class Client : IFrostFSClient
#endregion
#region NetworkImplementation
public Task<NetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args)
public Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args)
{
args ??= new PrmNetmapSnapshot();
var service = GetNetmapService(args);
return service.GetNetmapSnapshotAsync(args);
}
public Task<ModelsV2.Netmap.NodeInfo> GetNodeInfoAsync(PrmNodeInfo? args)
public Task<FrostFsNodeInfo> GetNodeInfoAsync(PrmNodeInfo? args)
{
args ??= new PrmNodeInfo();
var service = GetNetmapService(args);
@ -191,7 +191,7 @@ public class Client : IFrostFSClient
#endregion
#region ObjectImplementation
public Task<ObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
public Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
{
var service = GetObjectService(args);
return service.GetObjectHeadAsync(args);
@ -203,13 +203,13 @@ public class Client : IFrostFSClient
return service.GetObjectAsync(args);
}
public Task<ObjectId> PutObjectAsync(PrmObjectPut args)
public Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
{
var service = GetObjectService(args);
return service.PutObjectAsync(args);
}
public Task<ObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
public Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
{
var service = GetObjectService(args);
return service.PutSingleObjectAsync(args);
@ -221,7 +221,7 @@ public class Client : IFrostFSClient
return service.DeleteObjectAsync(args);
}
public IAsyncEnumerable<ObjectId> SearchObjectsAsync(PrmObjectSearch args)
public IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
{
var service = GetObjectService(args);
return service.SearchObjectsAsync(args);
@ -229,12 +229,12 @@ public class Client : IFrostFSClient
#endregion
#region SessionImplementation
public async Task<ModelsV2.SessionToken> CreateSessionAsync(PrmSessionCreate args)
public async Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args)
{
var session = await CreateSessionInternalAsync(args);
var token = session.Serialize();
return new ModelsV2.SessionToken(token);
return new FrostFsSessionToken(token);
}
internal Task<Session.SessionToken> CreateSessionInternalAsync(PrmSessionCreate args)
@ -245,7 +245,7 @@ public class Client : IFrostFSClient
#endregion
#region ToolsImplementation
public ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx)
{
if (header == null)
throw new ArgumentNullException(nameof(header));
@ -286,7 +286,7 @@ public class Client : IFrostFSClient
if (ctx.Context.OwnerId == null)
{
ctx.Context.OwnerId = ClientCtx.Owner ?? OwnerId.FromKey(ctx.Context.Key);
ctx.Context.OwnerId = ClientCtx.Owner ?? FrostFsOwner.FromKey(ctx.Context.Key);
}
if (ctx.Context.Version == null)

View file

@ -1,6 +1,8 @@
using FrostFS.SDK.Cryptography;
using System.Security.Cryptography;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using System.Security.Cryptography;
namespace FrostFS.SDK.ClientV2
{

View file

@ -0,0 +1,7 @@
using System;
namespace FrostFS.SDK.ClientV2;
public class InvalidObjectException() : Exception()
{
}

View file

@ -1,9 +1,8 @@
using FrostFS.SDK.ModelsV2;
using System;
namespace FrostFS.SDK.ClientV2;
public class ResponseException(ResponseStatus status) : Exception()
public class ResponseException(FrostFsResponseStatus status) : Exception()
{
public ResponseStatus Status { get; set; } = status;
public FrostFsResponseStatus Status { get; set; } = status;
}

View file

@ -21,7 +21,6 @@
<ItemGroup>
<ProjectReference Include="..\FrostFS.SDK.Cryptography\FrostFS.SDK.Cryptography.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj" />
<ProjectReference Include="..\FrostFS.SDK.ProtosV2\FrostFS.SDK.ProtosV2.csproj" />
</ItemGroup>

View file

@ -1,7 +1,7 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using FrostFS.SDK.ModelsV2;
using Grpc.Core;
using Grpc.Core.Interceptors;

View file

@ -1,50 +1,49 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ModelsV2.Netmap;
using FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Interfaces;
public interface IFrostFSClient : IDisposable
{
#region Network
Task<NetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args = null);
Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot? args = null);
Task<NodeInfo> GetNodeInfoAsync(PrmNodeInfo? args = null);
Task<FrostFsNodeInfo> GetNodeInfoAsync(PrmNodeInfo? args = null);
Task<NetworkSettings> GetNetworkSettingsAsync(PrmNetworkSettings? args = null);
#endregion
#region Session
Task<SessionToken> CreateSessionAsync(PrmSessionCreate args);
Task<FrostFsSessionToken> CreateSessionAsync(PrmSessionCreate args);
#endregion
#region Container
Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args);
Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args);
IAsyncEnumerable<ContainerId> ListContainersAsync(PrmContainerGetAll? args = null);
IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll? args = null);
Task<ContainerId> CreateContainerAsync(PrmContainerCreate args);
Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args);
Task DeleteContainerAsync(PrmContainerDelete args);
#endregion
#region Object
Task<ObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args);
Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args);
Task<FrostFsObject> GetObjectAsync(PrmObjectGet args);
Task<ObjectId> PutObjectAsync(PrmObjectPut putObjectParameters);
Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args);
Task<ObjectId> PutSingleObjectAsync(PrmSingleObjectPut args);
Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args);
Task DeleteObjectAsync(PrmObjectDelete args);
IAsyncEnumerable<ObjectId> SearchObjectsAsync(PrmObjectSearch args);
IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args);
#endregion
#region Tools
ObjectId CalculateObjectId(ObjectHeader header, Context ctx);
FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx);
#endregion
}

View file

@ -1,36 +1,24 @@
using System;
using System.Linq;
using Google.Protobuf;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ContainerMapper
{
public static Container.Container ToMessage(this ModelsV2.Container container)
{
return new Container.Container
{
BasicAcl = (uint)container.BasicAcl,
PlacementPolicy = container.PlacementPolicy.ToMessage(),
Nonce = ByteString.CopyFrom(container.Nonce.ToBytes())
};
}
public static ModelsV2.Container ToModel(this Container.Container container)
public static FrostFsContainerInfo ToModel(this Container.Container container)
{
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(acl, container.PlacementPolicy.ToModel())
{
Nonce = container.Nonce.ToUuid(),
Version = container.Version.ToModel()
};
return new FrostFsContainerInfo(acl,
container.PlacementPolicy.ToModel(),
container.Attributes?.Select(a => new FrostFsAttribute(a.Key, a.Value)).ToList(),
container.Version?.ToModel(),
container.OwnerId?.ToModel(),
container.Nonce?.ToUuid());
}
}

View file

@ -1,9 +1,11 @@
using System;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
using Microsoft.Extensions.Caching.Memory;
using System;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -13,16 +15,19 @@ public static class ContainerIdMapper
.SetSlidingExpiration(TimeSpan.FromHours(1))
.SetSize(1);
public static ContainerID ToMessage(this ContainerId model)
public static ContainerID ToMessage(this FrostFsContainerId model)
{
if (!Cache.Containers.TryGetValue(model, out ContainerID? message))
if (model.Value == null)
throw new ArgumentNullException(nameof(model));
if (!Cache.Containers.TryGetValue(model.Value, out ContainerID? message))
{
message = new ContainerID
{
Value = ByteString.CopyFrom(Base58.Decode(model.Value))
};
Cache.Containers.Set(model, message, _oneHourExpiration);
Cache.Containers.Set(model.Value, message, _oneHourExpiration);
}
return message!;

View file

@ -1,4 +1,3 @@
using FrostFS.SDK.ModelsV2;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;

View file

@ -1,14 +1,14 @@
using System.Linq;
using FrostFS.Netmap;
using FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class NetmapMapper
{
public static NetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
public static FrostFsNetmapSnapshot ToModel(this NetmapSnapshotResponse netmap)
{
return new NetmapSnapshot(
return new FrostFsNetmapSnapshot(
netmap.Body.Netmap.Epoch,
netmap.Body.Netmap.Nodes
.Select(n => n.ToModel(netmap.MetaHeader.Version))

View file

@ -1,30 +1,30 @@
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;
using FrostFS.Netmap;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK.ClientV2;
public static class NodeInfoMapper
{
public static NodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
public static FrostFsNodeInfo ToModel(this LocalNodeInfoResponse.Types.Body node)
{
return node.NodeInfo.ToModel(node.Version);
}
public static NodeInfo ToModel(this FrostFS.Netmap.NodeInfo nodeInfo, Refs.Version version)
public static FrostFsNodeInfo ToModel(this 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,
NodeInfo.Types.State.Unspecified => NodeState.Unspecified,
NodeInfo.Types.State.Online => NodeState.Online,
NodeInfo.Types.State.Offline => NodeState.Offline,
NodeInfo.Types.State.Maintenance => NodeState.Maintenance,
_ => throw new ArgumentException($"Unknown NodeState. Value: '{nodeInfo.State}'.")
};
return new NodeInfo(
return new FrostFsNodeInfo(
version: version.ToModel(),
state: state,
addresses: [.. nodeInfo.Addresses],

View file

@ -1,11 +1,12 @@
using System.Linq;
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class PlacementPolicyMapper
{
public static PlacementPolicy ToMessage(this ModelsV2.Netmap.PlacementPolicy placementPolicy)
public static PlacementPolicy ToMessage(this FrostFsPlacementPolicy placementPolicy)
{
var pp = new PlacementPolicy
{
@ -23,9 +24,9 @@ public static class PlacementPolicyMapper
return pp;
}
public static ModelsV2.Netmap.PlacementPolicy ToModel(this PlacementPolicy placementPolicy)
public static FrostFsPlacementPolicy ToModel(this PlacementPolicy placementPolicy)
{
return new ModelsV2.Netmap.PlacementPolicy(
return new FrostFsPlacementPolicy(
placementPolicy.Unique,
placementPolicy.Replicas.Select(replica => replica.ToModel()).ToArray()
);

View file

@ -1,10 +1,10 @@
using FrostFS.Netmap;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
namespace FrostFS.SDK.ClientV2;
public static class ReplicaMapper
{
public static Replica ToMessage(this ModelsV2.Netmap.Replica replica)
public static Replica ToMessage(this FrostFsReplica replica)
{
return new Replica
{
@ -13,8 +13,8 @@ public static class ReplicaMapper
};
}
public static ModelsV2.Netmap.Replica ToModel(this Replica replica)
public static FrostFsReplica ToModel(this Replica replica)
{
return new ModelsV2.Netmap.Replica((int)replica.Count, replica.Selector);
return new FrostFsReplica((int)replica.Count, replica.Selector);
}
}

View file

@ -1,5 +1,3 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
internal static class ObjectMapper
@ -8,7 +6,7 @@ internal static class ObjectMapper
{
return new FrostFsObject(obj.Header.ToModel())
{
ObjectId = ObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
ObjectId = FrostFsObjectId.FromHash(obj.ObjectId.Value.ToByteArray())
};
}
}

View file

@ -1,11 +1,10 @@
using FrostFS.Object;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectAttributeMapper
{
public static Header.Types.Attribute ToMessage(this ObjectAttribute attribute)
public static Header.Types.Attribute ToMessage(this FrostFsAttribute attribute)
{
return new Header.Types.Attribute
{
@ -14,8 +13,8 @@ public static class ObjectAttributeMapper
};
}
public static ObjectAttribute ToModel(this Header.Types.Attribute attribute)
public static FrostFsAttribute ToModel(this Header.Types.Attribute attribute)
{
return new ObjectAttribute(attribute.Key, attribute.Value);
return new FrostFsAttribute(attribute.Key, attribute.Value);
}
}

View file

@ -1,7 +1,6 @@
using System;
using FrostFS.Object;
using FrostFS.SDK.ModelsV2;
using MatchType = FrostFS.Object.MatchType;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -11,11 +10,11 @@ public static class ObjectFilterMapper
{
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,
FrostFsObjectMatchType.Unspecified => MatchType.Unspecified,
FrostFsObjectMatchType.Equals => MatchType.StringEqual,
FrostFsObjectMatchType.NotEquals => MatchType.StringNotEqual,
FrostFsObjectMatchType.KeyAbsent => MatchType.NotPresent,
FrostFsObjectMatchType.StartsWith => MatchType.CommonPrefix,
_ => throw new ArgumentException($"Unknown MatchType. Value: '{filter.MatchType}'.")
};

View file

@ -1,75 +1,28 @@
using System;
using System.Linq;
using FrostFS.Object;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
using ObjectType = FrostFS.Object.ObjectType;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectHeaderMapper
{
public static Header ToMessage(this ObjectHeader header)
public static FrostFsObjectHeader ToModel(this Header header)
{
var objTypeName = header.ObjectType switch
{
ModelsV2.Enums.ObjectType.Regular => ObjectType.Regular,
ModelsV2.Enums.ObjectType.Lock => ObjectType.Lock,
ModelsV2.Enums.ObjectType.Tombstone => ObjectType.Tombstone,
ObjectType.Regular => FrostFsObjectType.Regular,
ObjectType.Lock => FrostFsObjectType.Lock,
ObjectType.Tombstone => FrostFsObjectType.Tombstone,
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.")
};
var head = new Header
{
OwnerId = header!.OwnerId != null ? header.OwnerId.ToMessage() : null,
Version = header!.Version != null ? header.Version.ToMessage() : null,
ContainerId = header.ContainerId.ToMessage(),
ObjectType = objTypeName,
PayloadLength = header.PayloadLength
};
foreach (var attribute in header.Attributes)
{
head.Attributes.Add(attribute.ToMessage());
}
var split = header.Split;
if (split != null)
{
head.Split = new Header.Types.Split
{
SplitId = split.SplitId != null ? ByteString.CopyFrom(split.SplitId.ToBinary()) : null
};
}
return head;
}
public static ObjectHeader ToModel(this Header header)
{
var objTypeName = header.ObjectType switch
{
ObjectType.Regular => ModelsV2.Enums.ObjectType.Regular,
ObjectType.Lock => ModelsV2.Enums.ObjectType.Lock,
ObjectType.Tombstone => ModelsV2.Enums.ObjectType.Tombstone,
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{header.ObjectType}'.")
};
var model = new ObjectHeader(
new ContainerId(Base58.Encode(header.ContainerId.Value.ToByteArray())),
objTypeName,
header.Attributes.Select(attribute => attribute.ToModel()).ToArray()
)
{
PayloadLength = header.PayloadLength,
Version = header.Version.ToModel(),
OwnerId = header.OwnerId.ToModel()
};
FrostFsSplit? split = null;
if (header.Split != null)
{
model.Split = new Split(new SplitId(header.Split.SplitId.ToUuid()))
split = new FrostFsSplit(new SplitId(header.Split.SplitId.ToUuid()))
{
Parent = header.Split.Parent?.ToModel(),
ParentHeader = header.Split.ParentHeader?.ToModel(),
@ -77,9 +30,20 @@ public static class ObjectHeaderMapper
};
if (header.Split.Children.Count != 0)
model.Split.Children.AddRange(header.Split.Children.Select(x => x.ToModel()));
split.Children.AddRange(header.Split.Children.Select(x => x.ToModel()));
}
var model = new FrostFsObjectHeader(
new FrostFsContainerId(Base58.Encode(header.ContainerId.Value.ToByteArray())),
objTypeName,
header.Attributes.Select(attribute => attribute.ToModel()).ToArray(),
split,
header.OwnerId.ToModel(),
header.Version.ToModel())
{
PayloadLength = header.PayloadLength,
};
return model;
}
}

View file

@ -1,12 +1,12 @@
using FrostFS.Refs;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class ObjectIdMapper
{
public static ObjectID ToMessage(this ObjectId objectId)
public static ObjectID ToMessage(this FrostFsObjectId objectId)
{
return new ObjectID
{
@ -14,8 +14,8 @@ public static class ObjectIdMapper
};
}
public static ObjectId ToModel(this ObjectID objectId)
public static FrostFsObjectId ToModel(this ObjectID objectId)
{
return ObjectId.FromHash(objectId.Value.ToByteArray());
return FrostFsObjectId.FromHash(objectId.Value.ToByteArray());
}
}

View file

@ -1,9 +1,11 @@
using System;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
using Microsoft.Extensions.Caching.Memory;
using System;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -13,7 +15,7 @@ public static class OwnerIdMapper
.SetSlidingExpiration(TimeSpan.FromHours(1))
.SetSize(1);
public static OwnerID ToMessage(this OwnerId model)
public static OwnerID ToMessage(this FrostFsOwner model)
{
if (!Cache.Owners.TryGetValue(model, out OwnerID? message))
{
@ -28,11 +30,11 @@ public static class OwnerIdMapper
return message!;
}
public static OwnerId ToModel(this OwnerID message)
public static FrostFsOwner ToModel(this OwnerID message)
{
if (!Cache.Owners.TryGetValue(message, out OwnerId? model))
if (!Cache.Owners.TryGetValue(message, out FrostFsOwner? model))
{
model = new OwnerId(Base58.Encode(message.Value.ToByteArray()));
model = new FrostFsOwner(Base58.Encode(message.Value.ToByteArray()));
Cache.Owners.Set(message, model, _oneHourExpiration);
}

View file

@ -1,12 +1,12 @@
using System;
using FrostFS.SDK.ModelsV2;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class SignatureMapper
{
public static Refs.Signature ToMessage(this Signature signature)
public static Refs.Signature ToMessage(this FrostFsSignature signature)
{
var scheme = signature.Scheme switch
{

View file

@ -1,19 +1,18 @@
using System;
using FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
public static class StatusMapper
{
public static ModelsV2.ResponseStatus ToModel(this Status.Status status)
public static FrostFsResponseStatus ToModel(this Status.Status status)
{
if (status is null)
return new ModelsV2.ResponseStatus(StatusCode.Success);
return new FrostFsResponseStatus(FrostFsStatusCode.Success);
var codeName = Enum.GetName(typeof(FrostFsStatusCode), status.Code);
var codeName = Enum.GetName(typeof(StatusCode), status.Code);
return codeName is null
? throw new ArgumentException($"Unknown StatusCode. Value: '{status.Code}'.")
: new ModelsV2.ResponseStatus((StatusCode)Enum.Parse(typeof(StatusCode), codeName), status.Message);
: new FrostFsResponseStatus((FrostFsStatusCode)status.Code, status.Message);
}
}

View file

@ -1,6 +1,7 @@
using System.Collections;
using System.Threading;
using Version = FrostFS.Refs.Version;
using FrostFS.Refs;
namespace FrostFS.SDK.ClientV2.Mappers.GRPC;
@ -10,7 +11,7 @@ public static class VersionMapper
private static readonly Hashtable _cacheModels = [];
private static SpinLock _spinlock = new();
public static Version ToMessage(this ModelsV2.Version model)
public static Version ToMessage(this FrostFsVersion model)
{
var key = model.Major << 16 + model.Minor;
@ -31,7 +32,7 @@ public static class VersionMapper
}
catch (System.ArgumentException)
{
// ignore attempt to add duplicate error.
// ignore attempt to add duplicate
}
finally
{
@ -43,7 +44,7 @@ public static class VersionMapper
return (Version)_cacheMessages[key];
}
public static ModelsV2.Version ToModel(this Version message)
public static FrostFsVersion ToModel(this Version message)
{
var key = (int)message.Major << 16 + (int)message.Minor;
@ -53,14 +54,14 @@ public static class VersionMapper
try
{
_spinlock.Enter(ref lockTaken);
var model = new ModelsV2.Version((int)message.Major, (int)message.Minor);
var model = new FrostFsVersion((int)message.Major, (int)message.Minor);
_cacheModels.Add(key, model);
return model;
}
catch (System.ArgumentException)
{
// ignore attempt to add duplicate error.
// ignore attempt to add duplicate
}
finally
{
@ -69,6 +70,6 @@ public static class VersionMapper
}
}
return (ModelsV2.Version)_cacheModels[key];
return (FrostFsVersion)_cacheModels[key];
}
}

View file

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace FrostFS.SDK;
public class ClientSettings
{
protected static readonly string errorTemplate = "{0} is required parameter";
public string Host { get; set; } = string.Empty;
public virtual void Validate()
{
var errors = CheckFields();
if (errors != null)
ThrowException(errors);
}
protected List<string>? CheckFields()
{
List<string>? errors = null;
if (string.IsNullOrWhiteSpace(Host))
(errors ??= []).Add(string.Format(errorTemplate, nameof(Host)));
return errors;
}
protected static void ThrowException(List<string> errors)
{
StringBuilder messages = new();
foreach (var error in errors)
{
messages.AppendLine(error);
}
throw new ArgumentException(messages.ToString());
}
}
public class SingleOwnerClientSettings : ClientSettings
{
public string Key { get; set; } = string.Empty;
public override void Validate()
{
var errors = CheckFields();
if (errors != null)
ThrowException(errors);
}
protected new List<string>? CheckFields()
{
List<string>? errors = base.CheckFields();
if (string.IsNullOrWhiteSpace(Key))
(errors ??= []).Add(string.Format(errorTemplate, nameof(Key)));
return errors;
}
}

View file

@ -0,0 +1,62 @@
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.ClientV2;
namespace FrostFS.SDK;
public class FrostFsContainerId
{
private string? modelId;
private ContainerID? containerID;
public FrostFsContainerId(string id)
{
this.modelId = id;
}
internal FrostFsContainerId(ContainerID id)
{
this.containerID = id;
}
public string Value
{
get
{
if (this.modelId != null)
return this.modelId;
if (containerID != null)
{
this.modelId = Base58.Encode(containerID.Value.ToByteArray());
return this.modelId;
}
throw new InvalidObjectException();
}
}
internal ContainerID ContainerID
{
get
{
if (this.containerID != null)
return this.containerID;
if (modelId != null)
{
this.containerID = this.ToMessage();
return this.containerID;
}
throw new InvalidObjectException();
}
}
public override string ToString()
{
return Value;
}
}

View file

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using Google.Protobuf;
namespace FrostFS.SDK;
public class FrostFsContainerInfo
{
private Container.Container.Types.Attribute[]? grpsAttributes;
private List<FrostFsAttribute>? attributes;
private FrostFsPlacementPolicy? placementPolicy;
private Guid? nonce;
private Container.Container container;
public FrostFsContainerInfo(
BasicAcl basicAcl,
FrostFsPlacementPolicy placementPolicy,
List<FrostFsAttribute>? attributes = null,
FrostFsVersion? version = null,
FrostFsOwner? owner = null,
Guid? nonce = null)
{
BasicAcl = basicAcl;
this.placementPolicy = placementPolicy;
this.attributes = attributes;
Version = version;
Owner = owner;
this.nonce = nonce;
}
internal FrostFsContainerInfo(Container.Container container)
{
this.container = container;
}
public Guid Nonce
{
get
{
nonce ??= container?.Nonce != null ? container.Nonce.ToUuid() : Guid.NewGuid();
return nonce.Value;
}
}
public BasicAcl BasicAcl { get; private set; }
public FrostFsPlacementPolicy? PlacementPolicy
{
get
{
placementPolicy ??= container.PlacementPolicy?.ToModel();
return placementPolicy;
}
}
public List<FrostFsAttribute>? Attributes
{
get
{
if (attributes == null && grpsAttributes != null)
attributes = grpsAttributes.Select(a => new FrostFsAttribute(a.Key, a.Value)).ToList();
return attributes;
}
}
public FrostFsVersion? Version { get; private set; }
public FrostFsOwner? Owner { get; private set; }
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
{
grpsAttributes ??= Attributes?
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
.ToArray();
return grpsAttributes;
}
internal Container.Container GetContainer()
{
if (this.container == null)
{
this.container = new Container.Container()
{
BasicAcl = (uint)BasicAcl,
PlacementPolicy = PlacementPolicy.ToMessage(),
Nonce = ByteString.CopyFrom(Nonce.ToBytes()),
OwnerId = Owner?.OwnerID,
Version = Version?.Version
};
var attribs = GetGrpsAttributes();
if (attribs != null)
this.container.Attributes.AddRange(attribs);
}
return this.container;
}
}

View file

@ -0,0 +1,21 @@
using System.ComponentModel;
namespace FrostFS.SDK;
public enum BasicAcl
{
[Description("Not defined ACL")]
NotDefined = 0x00000000,
[Description("Basic ACL for private container")]
Private = 0x1C8C8CCC,
[Description("Basic ACL for public RO container")]
PublicRO = 0x1FBF8CFF,
[Description("Basic ACL for public RW container")]
PublicRW = 0x1FBFBFFF,
[Description("Basic ACL for public append container")]
PublicAppend = 0x1FBF9FFF,
}

View file

@ -1,6 +1,6 @@
namespace FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK;
public enum ObjectMatchType
public enum FrostFsObjectMatchType
{
Unspecified = 0,
Equals = 1,

View file

@ -0,0 +1,8 @@
namespace FrostFS.SDK;
public enum FrostFsObjectType
{
Regular = 0,
Tombstone = 1,
Lock = 3
}

View file

@ -1,6 +1,6 @@
namespace FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK;
public enum StatusCode
public enum FrostFsStatusCode
{
Success = 0,
Internal = 1024,

View file

@ -0,0 +1,9 @@
namespace FrostFS.SDK;
public enum NodeState
{
Unspecified = 0,
Online = 1,
Offline = 2,
Maintenance = 3
}

View file

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

View file

@ -0,0 +1,7 @@
namespace FrostFS.SDK;
public class CallStatistics
{
public string? MethodName { get; set; }
public long ElapsedMicroSeconds { get; set; }
}

View file

@ -0,0 +1,20 @@
using FrostFS.SDK.Cryptography;
using System;
namespace FrostFS.SDK;
public class CheckSum
{
// type is always Sha256
public byte[]? Hash { get; set; }
public static CheckSum CreateCheckSum(byte[] content)
{
return new CheckSum { Hash = content.Sha256() };
}
public override string ToString()
{
return BitConverter.ToString(Hash).Replace("-", "");
}
}

View file

@ -0,0 +1,52 @@
namespace FrostFS.SDK;
public class Constants
{
public const int ObjectChunkSize = 3 * (1 << 20);
public const int Sha256HashLength = 32;
// HeaderPrefix is a prefix of key to object header value or property.
public const string HeaderPrefix = "$Object:";
// FilterHeaderVersion is a filter key to "version" field of the object header.
public const string FilterHeaderVersion = HeaderPrefix + "version";
// FilterHeaderObjectID is a filter key to "object_id" field of the object.
public const string FilterHeaderObjectID = HeaderPrefix + "objectID";
// FilterHeaderContainerID is a filter key to "container_id" field of the object header.
public const string FilterHeaderContainerID = HeaderPrefix + "containerID";
// FilterHeaderOwnerID is a filter key to "owner_id" field of the object header.
public const string FilterHeaderOwnerID = HeaderPrefix + "ownerID";
// FilterHeaderCreationEpoch is a filter key to "creation_epoch" field of the object header.
public const string FilterHeaderCreationEpoch = HeaderPrefix + "creationEpoch";
// FilterHeaderPayloadLength is a filter key to "payload_length" field of the object header.
public const string FilterHeaderPayloadLength = HeaderPrefix + "payloadLength";
// FilterHeaderPayloadHash is a filter key to "payload_hash" field of the object header.
public const string FilterHeaderPayloadHash = HeaderPrefix + "payloadHash";
// FilterHeaderObjectType is a filter key to "object_type" field of the object header.
public const string FilterHeaderObjectType = HeaderPrefix + "objectType";
// FilterHeaderHomomorphicHash is a filter key to "homomorphic_hash" field of the object header.
public const string FilterHeaderHomomorphicHash = HeaderPrefix + "homomorphicHash";
// FilterHeaderParent is a filter key to "split.parent" field of the object header.
public const string FilterHeaderParent = HeaderPrefix + "split.parent";
// FilterHeaderSplitID is a filter key to "split.splitID" field of the object header.
public const string FilterHeaderSplitID = HeaderPrefix + "split.splitID";
// FilterHeaderECParent is a filter key to "ec.parent" field of the object header.
public const string FilterHeaderECParent = HeaderPrefix + "ec.parent";
// FilterPropertyRoot is a filter key to check if regular object is on top of split hierarchy.
public const string FilterHeaderRoot = HeaderPrefix + "ROOT";
// FilterPropertyPhy is a filter key to check if an object physically stored on a node.
public const string FilterHeaderPhy = HeaderPrefix + "PHY";
}

View file

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace FrostFS.SDK;
public class FrostFsNetmapSnapshot(ulong epoch, IReadOnlyList<FrostFsNodeInfo> nodeInfoCollection)
{
public ulong Epoch { get; private set; } = epoch;
public IReadOnlyList<FrostFsNodeInfo> NodeInfoCollection { get; private set; } = nodeInfoCollection;
}

View file

@ -1,18 +1,17 @@
using System;
using System.Collections.Generic;
using FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK;
public class NodeInfo(
Version version,
public class FrostFsNodeInfo(
FrostFsVersion version,
NodeState state,
IReadOnlyCollection<string> addresses,
IReadOnlyDictionary<string, string> attributes,
ReadOnlyMemory<byte> publicKey)
{
public NodeState State { get; private set; } = state;
public Version Version { get; private set; } = version;
public FrostFsVersion Version { get; private set; } = version;
public IReadOnlyCollection<string> Addresses { get; private set; } = addresses;
public IReadOnlyDictionary<string, string> Attributes { get; private set; } = attributes;
public ReadOnlyMemory<byte> PublicKey { get; private set; } = publicKey;

View file

@ -1,16 +1,16 @@
using System;
using System.Linq;
namespace FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK;
public class PlacementPolicy(bool unique, params Replica[] replicas) : IComparable<PlacementPolicy>
public class FrostFsPlacementPolicy(bool unique, params FrostFsReplica[] replicas) : IComparable<FrostFsPlacementPolicy>
{
public Replica[] Replicas { get; private set; } = replicas;
public FrostFsReplica[] Replicas { get; private set; } = replicas;
public bool Unique { get; private set; } = unique;
public int CompareTo(PlacementPolicy other)
public int CompareTo(FrostFsPlacementPolicy other)
{
var notEqual = other == null
var notEqual = other == null
|| Unique != other.Unique
|| Replicas.Length != other.Replicas.Length;

View file

@ -1,14 +1,14 @@
namespace FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK;
public class Replica
public class FrostFsReplica
{
public int Count { get; set; }
public string Selector { get; set; }
public Replica(int count, string? selector = null)
public FrostFsReplica(int count, string? selector = null)
{
selector ??= string.Empty;
Count = count;
Selector = selector;
}

View file

@ -0,0 +1,31 @@
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK;
public class FrostFsVersion(int major, int minor)
{
public Version version;
public int Major { get; set; } = major;
public int Minor { get; set; } = minor;
internal Version Version
{
get
{
this.version ??= this.ToMessage();
return this.version;
}
}
public bool IsSupported(FrostFsVersion version)
{
return Major == version.Major;
}
public override string ToString()
{
return $"v{Major}.{Minor}";
}
}

View file

@ -0,0 +1,8 @@
namespace FrostFS.SDK;
public class FrostFsAttribute(string key, string value)
{
public string Key { get; set; } = key;
public string Value { get; set; } = value;
}

View file

@ -0,0 +1,9 @@
namespace FrostFS.SDK;
public class FrostFsLargeObject(FrostFsContainerId container) : FrostFsObject(container)
{
public ulong PayloadLength
{
get { return Header!.PayloadLength; }
}
}

View file

@ -0,0 +1,13 @@
namespace FrostFS.SDK;
public class FrostFsLinkObject : FrostFsObject
{
public FrostFsLinkObject(FrostFsContainerId containerId, SplitId splitId, FrostFsObjectHeader largeObjectHeader)
: base(containerId)
{
Header!.Split = new FrostFsSplit(splitId)
{
ParentHeader = largeObjectHeader
};
}
}

View file

@ -0,0 +1,64 @@
using System;
namespace FrostFS.SDK;
public class FrostFsObject
{
/// <summary>
/// Creates new instance from <c>ObjectHeader</c>
/// </summary>
/// <param name="header"></param> <summary>
public FrostFsObject(FrostFsObjectHeader header)
{
Header = header;
}
/// <summary>
/// Creates new instance with specified parameters
/// </summary>
/// <param name="container"></param>
/// <param name="objectType"></param>
public FrostFsObject(FrostFsContainerId container, FrostFsObjectType objectType = FrostFsObjectType.Regular)
{
Header = new FrostFsObjectHeader(containerId: container, type: objectType);
}
/// <summary>
/// Header contains metadata for the object
/// </summary>
/// <value></value>
public FrostFsObjectHeader Header { get; set; }
/// <summary>
/// The value is calculated internally as a hash of ObjectHeader. Do not use pre-calculated value is the object has been changed.
/// </summary>
public FrostFsObjectId? ObjectId
{
get; set;
}
/// <summary>
/// The size of payload cannot exceed <c>MaxObjectSize</c> value from <c>NetworkSettings</c>
/// Used only for PutSingleObject method
/// </summary>
/// <value>Buffer for output data</value>
public byte[] Payload { get; set; } = [];
/// <summary>
/// A payload is obtained via stream reader
/// </summary>
/// <value>Reader for received data</value>
public IObjectReader? ObjectReader { get; set; }
/// <summary>
/// Applied only for the last Object in chain in case of manual multipart uploading
/// </summary>
/// <param name="largeObject">Parent for multipart object</param>
public void SetParent(FrostFsObjectHeader largeObjectHeader)
{
if (Header?.Split == null)
throw new Exception("The object is not initialized properly");
Header.Split.ParentHeader = largeObjectHeader;
}
}

View file

@ -0,0 +1,111 @@
namespace FrostFS.SDK;
public interface IObjectFilter
{
public FrostFsObjectMatchType MatchType { get; set; }
public string Key { get; set; }
string? GetSerializedValue();
}
public abstract class FrostFsObjectFilter<T>(FrostFsObjectMatchType matchType, string key, T value) : IObjectFilter
{
public FrostFsObjectMatchType MatchType { get; set; } = matchType;
public string Key { get; set; } = key;
public T Value { get; set; } = value;
public string? GetSerializedValue()
{
return Value?.ToString();
}
}
/// <summary>
/// Creates filter to search by Attribute
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="key">Attribute key</param>
/// <param name="value">Attribute value</param>
public class FilterByAttribute(FrostFsObjectMatchType matchType, string key, string value) : FrostFsObjectFilter<string>(matchType, key, value) { }
/// <summary>
/// Creates filter to search by ObjectId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="objectId">ObjectId</param>
public class FilterByObjectId(FrostFsObjectMatchType matchType, FrostFsObjectId objectId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderObjectID, objectId) { }
/// <summary>
/// Creates filter to search by OwnerId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="ownerId">ObjectId</param>
public class FilterByOwnerId(FrostFsObjectMatchType matchType, FrostFsOwner ownerId) : FrostFsObjectFilter<FrostFsOwner>(matchType, Constants.FilterHeaderOwnerID, ownerId) { }
/// <summary>
/// Creates filter to search by Version
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="version">Version</param>
public class FilterByVersion(FrostFsObjectMatchType matchType, FrostFsVersion version) : FrostFsObjectFilter<FrostFsVersion>(matchType, Constants.FilterHeaderVersion, version) { }
/// <summary>
/// Creates filter to search by ContainerId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="containerId">ContainerId</param>
public class FilterByContainerId(FrostFsObjectMatchType matchType, FrostFsContainerId containerId) : FrostFsObjectFilter<FrostFsContainerId>(matchType, Constants.FilterHeaderContainerID, containerId) { }
/// <summary>
/// Creates filter to search by creation Epoch
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="epoch">Creation Epoch</param>
public class FilterByEpoch(FrostFsObjectMatchType matchType, ulong epoch) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderCreationEpoch, epoch) { }
/// <summary>
/// Creates filter to search by Payload Length
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="payloadLength">Payload Length</param>
public class FilterByPayloadLength(FrostFsObjectMatchType matchType, ulong payloadLength) : FrostFsObjectFilter<ulong>(matchType, Constants.FilterHeaderPayloadLength, payloadLength) { }
/// <summary>
/// Creates filter to search by Payload Hash
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="payloadHash">Payload Hash</param>
public class FilterByPayloadHash(FrostFsObjectMatchType matchType, CheckSum payloadHash) : FrostFsObjectFilter<CheckSum>(matchType, Constants.FilterHeaderPayloadHash, payloadHash) { }
/// <summary>
/// Creates filter to search by Parent
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="parentId">Parent</param>
public class FilterByParent(FrostFsObjectMatchType matchType, FrostFsObjectId parentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderParent, parentId) { }
/// <summary>
/// Creates filter to search by SplitId
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="splitId">SplitId</param>
public class FilterBySplitId(FrostFsObjectMatchType matchType, SplitId splitId) : FrostFsObjectFilter<SplitId>(matchType, Constants.FilterHeaderSplitID, splitId) { }
/// <summary>
/// Creates filter to search by Payload Hash
/// </summary>
/// <param name="matchType">Match type</param>
/// <param name="ecParentId">Payload Hash</param>
public class FilterByECParent(FrostFsObjectMatchType matchType, FrostFsObjectId ecParentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderECParent, ecParentId) { }
/// <summary>
/// Creates filter to search Root objects
/// </summary>
public class FilterByRootObject() : FrostFsObjectFilter<string>(FrostFsObjectMatchType.Unspecified, Constants.FilterHeaderRoot, string.Empty) { }
/// <summary>
/// Creates filter to search objects that are physically stored on the server
/// </summary
public class FilterByPhysicallyStored() : FrostFsObjectFilter<string>(FrostFsObjectMatchType.Unspecified, Constants.FilterHeaderPhy, string.Empty) { }

View file

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.Linq;
using FrostFS.Object;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
namespace FrostFS.SDK;
public class FrostFsObjectHeader(
FrostFsContainerId containerId,
FrostFsObjectType type = FrostFsObjectType.Regular,
FrostFsAttribute[]? attributes = null,
FrostFsSplit? split = null,
FrostFsOwner? owner = null,
FrostFsVersion? version = null)
{
private Header header;
private Container.Container.Types.Attribute[]? grpsAttributes;
public List<FrostFsAttribute> Attributes { get; internal set; } = attributes != null ? [.. attributes] : [];
public FrostFsContainerId ContainerId { get; } = containerId;
public ulong PayloadLength { get; set; }
public byte[]? PayloadCheckSum { get; set; }
public FrostFsObjectType ObjectType { get; } = type;
public FrostFsOwner? OwnerId { get; internal set; } = owner;
public FrostFsVersion? Version { get; internal set; } = version;
public FrostFsSplit? Split { get; internal set; } = split;
internal Container.Container.Types.Attribute[]? GetGrpsAttributes()
{
grpsAttributes ??= Attributes?
.Select(a => new Container.Container.Types.Attribute { Key = a.Key, Value = a.Value })
.ToArray();
return grpsAttributes;
}
public Header GetHeader()
{
if (header == null)
{
var objTypeName = ObjectType switch
{
FrostFsObjectType.Regular => Object.ObjectType.Regular,
FrostFsObjectType.Lock => Object.ObjectType.Lock,
FrostFsObjectType.Tombstone => Object.ObjectType.Tombstone,
_ => throw new ArgumentException($"Unknown ObjectType. Value: '{ObjectType}'.")
};
this.header = new Header
{
OwnerId = OwnerId?.ToMessage(),
Version = Version?.ToMessage(),
ContainerId = ContainerId.ToMessage(),
ObjectType = objTypeName,
PayloadLength = PayloadLength
};
foreach (var attribute in Attributes)
{
this.header.Attributes.Add(attribute.ToMessage());
}
var split = Split;
if (split != null)
{
this.header.Split = new Header.Types.Split
{
SplitId = split!.SplitId != null ? split.SplitId.GetSplitId() : null
};
}
}
return this.header;
}
}

View file

@ -0,0 +1,28 @@
using System;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class FrostFsObjectId(string id)
{
public string Value { get; } = id;
public static FrostFsObjectId FromHash(byte[] hash)
{
if (hash.Length != Constants.Sha256HashLength)
throw new FormatException("ObjectID must be a sha256 hash.");
return new FrostFsObjectId(Base58.Encode(hash));
}
public byte[] ToHash()
{
return Base58.Decode(Value);
}
public override string ToString()
{
return Value;
}
}

View file

@ -0,0 +1,38 @@
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
namespace FrostFS.SDK;
public class FrostFsOwner(string id)
{
private OwnerID ownerID;
public string Value { get; } = id;
public static FrostFsOwner FromKey(ECDsa key)
{
return new FrostFsOwner(key.PublicKey().PublicKeyToAddress());
}
internal OwnerID OwnerID
{
get
{
ownerID ??= this.ToMessage();
return ownerID;
}
}
public byte[] ToHash()
{
return Base58.Decode(Value);
}
public override string ToString()
{
return Value;
}
}

View file

@ -0,0 +1,24 @@
using System.Collections.Generic;
namespace FrostFS.SDK;
public class FrostFsSplit(SplitId splitId)
{
public FrostFsSplit() : this(new SplitId())
{
}
public SplitId SplitId { get; private set; } = splitId;
public FrostFsObjectId? Parent { get; set; }
public FrostFsObjectId? Previous { get; set; }
public FrostFsSignature? ParentSignature { get; set; }
public FrostFsObjectHeader? ParentHeader { get; set; }
public List<FrostFsObjectId> Children { get; } = [];
public Refs.Signature ParentSignatureGrpc { get; set; }
}

View file

@ -0,0 +1,10 @@
using System;
using System.Threading;
using System.Threading.Tasks;
namespace FrostFS.SDK;
public interface IObjectReader : IDisposable
{
Task<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default);
}

View file

@ -0,0 +1,62 @@
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using System;
namespace FrostFS.SDK;
public class SplitId
{
private readonly Guid id;
private ByteString? _message;
public SplitId()
{
id = Guid.NewGuid();
}
public SplitId(Guid guid)
{
id = guid;
}
private SplitId(byte[] binary)
{
id = new Guid(binary);
}
private SplitId(string str)
{
id = new Guid(str);
}
public static SplitId CreateFromBinary(byte[] binaryData)
{
return new SplitId(binaryData);
}
public static SplitId CreateFromString(string stringData)
{
return new SplitId(stringData);
}
public override string ToString()
{
return id.ToString();
}
public byte[]? ToBinary()
{
if (id == Guid.Empty)
return null;
return id.ToBytes();
}
public ByteString? GetSplitId()
{
return _message ??= ByteString.CopyFrom(ToBinary());
}
}

View file

@ -0,0 +1,14 @@
namespace FrostFS.SDK;
public class FrostFsResponseStatus(FrostFsStatusCode code, string? message = null)
{
public FrostFsStatusCode Code { get; set; } = code;
public string Message { get; set; } = message ?? string.Empty;
public bool IsSuccess => Code == FrostFsStatusCode.Success;
public override string ToString()
{
return $"Response status: {Code}. Message: {Message}.";
}
}

View file

@ -0,0 +1,10 @@
namespace FrostFS.SDK;
public class FrostFsSignature
{
public byte[]? Key { get; set; }
public byte[]? Sign { get; set; }
public SignatureScheme Scheme { get; set; }
}

View file

@ -0,0 +1,20 @@
namespace FrostFS.SDK;
public class MetaHeader(FrostFsVersion version, int epoch, int ttl)
{
public FrostFsVersion Version { get; set; } = version;
public int Epoch { get; set; } = epoch;
public int Ttl { get; set; } = ttl;
public static MetaHeader Default()
{
return new MetaHeader(
new FrostFsVersion(
major: 2,
minor: 13
),
epoch: 0,
ttl: 2
);
}
}

View file

@ -0,0 +1,6 @@
namespace FrostFS.SDK;
public class FrostFsSessionToken(byte[] token)
{
public byte[] Token { get; private set; } = token;
}

View file

@ -2,9 +2,11 @@ using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Threading;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
using Grpc.Core.Interceptors;
namespace FrostFS.SDK.ClientV2;
@ -13,13 +15,13 @@ public class Context()
{
private List<Interceptor>? interceptors;
private ByteString publicKeyCache;
private ByteString? publicKeyCache;
public ECDsa Key { get; set; }
public OwnerId OwnerId { get; set; }
public FrostFsOwner OwnerId { get; set; }
public ModelsV2.Version Version { get; set; }
public FrostFsVersion Version { get; set; }
public CancellationToken CancellationToken { get; set; } = default;
@ -35,16 +37,13 @@ public class Context()
set { this.interceptors = value; }
}
public ByteString PublicKeyCache
public ByteString? GetPublicKeyCache()
{
get
if (publicKeyCache == null && Key != null)
{
if (publicKeyCache == null)
{
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
}
return publicKeyCache;
publicKeyCache = ByteString.CopyFrom(Key.PublicKey());
}
return publicKeyCache;
}
}

View file

@ -1,11 +1,10 @@
using FrostFS.SDK.ModelsV2;
using System.Security.Cryptography;
using System.Security.Cryptography;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public class Credentials(ECDsa key, OwnerId ownerId)
public class Credentials(ECDsa key, FrostFsOwner ownerId)
{
public ECDsa Key { get; } = key;
public OwnerId OwnerId { get; } = ownerId;
public FrostFsOwner OwnerId { get; } = ownerId;
}

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public interface IContext
{

View file

@ -1,6 +1,4 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public interface ISessionToken
{
@ -10,5 +8,5 @@ public interface ISessionToken
/// member. The session has a limited validity period, and applies to a strictly defined set of operations.
/// </summary>
/// <value>Instance of the session obtained from the server</value>
SessionToken? SessionToken { get; set; }
FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,6 +1,6 @@
using System.Collections.Specialized;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public class PrmBase() : IContext
{

View file

@ -1,11 +1,8 @@
using FrostFS.SDK.ModelsV2;
using System.Security.Cryptography;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmContainerCreate(ModelsV2.Container container) : PrmBase, ISessionToken
public sealed class PrmContainerCreate(FrostFsContainerInfo container) : PrmBase, ISessionToken
{
public ModelsV2.Container Container { get; set; } = container;
public FrostFsContainerInfo Container { get; set; } = container;
/// <summary>
/// Since the container becomes available with some delay, it needs to poll the container status
@ -16,5 +13,5 @@ public sealed class PrmContainerCreate(ModelsV2.Container container) : PrmBase,
/// <summary>
/// Blank session token
/// </summary>
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,10 +1,8 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmContainerDelete(ContainerId containerId) : PrmBase, ISessionToken
public sealed class PrmContainerDelete(FrostFsContainerId containerId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId ContainerId { get; set; } = containerId;
/// <summary>
/// Since the container is removed with some delay, it needs to poll the container status
@ -12,5 +10,5 @@ public sealed class PrmContainerDelete(ContainerId containerId) : PrmBase, ISess
/// <value>Rules for polling the result</value>
public PrmWait? WaitParams { get; set; }
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,8 +1,6 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmContainerGet(ContainerId containerId) : PrmBase
public sealed class PrmContainerGet(FrostFsContainerId container) : PrmBase
{
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId Container { get; set; } = container;
}

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmContainerGetAll() : PrmBase()
{

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNetmapSnapshot() : PrmBase
{

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNetworkSettings() : PrmBase
{

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmNodeInfo() : PrmBase
{

View file

@ -1,13 +1,11 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmObjectDelete(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
public sealed class PrmObjectDelete(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,13 +1,11 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmObjectGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
public sealed class PrmObjectGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,13 +1,11 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2.Parameters;
public sealed class PrmObjectHeadGet(ContainerId containerId, ObjectId objectId) : PrmBase, ISessionToken
public sealed class PrmObjectHeadGet(FrostFsContainerId containerId, FrostFsObjectId objectId) : PrmBase, ISessionToken
{
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId ContainerId { get; set; } = containerId;
public ObjectId ObjectId { get; set; } = objectId;
public FrostFsObjectId ObjectId { get; set; } = objectId;
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,7 +1,6 @@
using System.IO;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectPut : PrmBase, ISessionToken
{
@ -10,7 +9,7 @@ public sealed class PrmObjectPut : PrmBase, ISessionToken
/// Optional parameters ike <c>Attributes</c> can be provided as well.
/// </summary>
/// <value>Header with required parameters to create an object</value>
public ObjectHeader? Header { get; set; }
public FrostFsObjectHeader? Header { get; set; }
/// <summary>
/// A stream with source data
@ -37,7 +36,7 @@ public sealed class PrmObjectPut : PrmBase, ISessionToken
public byte[]? CustomBuffer { get; set; }
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
internal int MaxObjectSizeCache { get; set; }

View file

@ -1,14 +1,14 @@
using FrostFS.SDK.ModelsV2;
using System.Collections.Generic;
namespace FrostFS.SDK.ClientV2.Parameters;
using System.Collections.Generic;
public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilter[] filters) : PrmBase, ISessionToken
namespace FrostFS.SDK.ClientV2;
public sealed class PrmObjectSearch(FrostFsContainerId containerId, params IObjectFilter[] filters) : PrmBase, ISessionToken
{
/// <summary>
/// Defines container for the search
/// </summary>
/// <value></value>
public ContainerId ContainerId { get; set; } = containerId;
public FrostFsContainerId ContainerId { get; set; } = containerId;
/// <summary>
/// Defines the search criteria
@ -17,5 +17,5 @@ public sealed class PrmObjectSearch(ContainerId containerId, params IObjectFilte
public IEnumerable<IObjectFilter> Filters { get; set; } = filters;
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmSessionCreate(ulong expiration) : PrmBase
{

View file

@ -1,11 +1,9 @@
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public sealed class PrmSingleObjectPut(FrostFsObject frostFsObject) : PrmBase, ISessionToken
{
public FrostFsObject FrostFsObject { get; set; } = frostFsObject;
/// <inheritdoc />
public SessionToken? SessionToken { get; set; }
public FrostFsSessionToken? SessionToken { get; set; }
}

View file

@ -1,5 +1,6 @@
using System;
namespace FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
public class PrmWait(TimeSpan timeout, TimeSpan pollInterval)
{

View file

@ -3,12 +3,11 @@ using System.Collections.Generic;
using System.Collections.Specialized;
using System.Threading.Tasks;
using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap;
using FrostFS.SDK.ClientV2;
using FrostFS.Container;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.ClientV2;
using FrostFS.Refs;
using FrostFS.Session;
@ -18,14 +17,14 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
{
readonly SessionProvider sessions = new(context);
public async ValueTask<Session.SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
public async ValueTask<SessionToken> GetOrCreateSession(ISessionToken args, Context ctx)
{
return await sessions.GetOrCreateSession(args, ctx);
}
internal async Task<ModelsV2.Container> GetContainerAsync(PrmContainerGet args)
internal async Task<FrostFsContainerInfo> GetContainerAsync(PrmContainerGet args)
{
GetRequest request = GetContainerRequest(args.ContainerId.ToMessage(), args.XHeaders, args.Context!);
GetRequest request = GetContainerRequest(args.Container.ContainerID, args.XHeaders, args.Context!);
var response = await service.GetAsync(request, null, args.Context!.Deadline, args.Context.CancellationToken);
@ -34,15 +33,15 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
return response.Body.Container.ToModel();
}
internal async IAsyncEnumerable<ContainerId> ListContainersAsync(PrmContainerGetAll args)
internal async IAsyncEnumerable<FrostFsContainerId> ListContainersAsync(PrmContainerGetAll args)
{
var ctx = args.Context!;
var request = new ListRequest
{
Body = new ListRequest.Types.Body
Body = new ()
{
OwnerId = ctx.OwnerId.ToMessage()
OwnerId = ctx.OwnerId.ToMessage()
}
};
@ -55,16 +54,18 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
foreach (var cid in response.Body.ContainerIds)
{
yield return new ContainerId(Base58.Encode(cid.Value.ToByteArray()));
yield return new FrostFsContainerId(Base58.Encode(cid.Value.ToByteArray()));
}
}
internal async Task<ContainerId> CreateContainerAsync(PrmContainerCreate args)
internal async Task<FrostFsContainerId> CreateContainerAsync(PrmContainerCreate args)
{
var ctx = args.Context!;
var grpcContainer = args.Container.ToMessage();
grpcContainer.OwnerId = ctx.OwnerId.ToMessage();
grpcContainer.Version = ctx.Version.ToMessage();
var grpcContainer = args.Container.GetContainer();
grpcContainer.OwnerId ??= ctx.OwnerId.ToMessage();
grpcContainer.Version ??= ctx.Version.ToMessage();
var request = new PutRequest
{
@ -81,9 +82,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
null,
ContainerSessionContext.Types.Verb.Put,
ctx.Key,
ctx.PublicKeyCache);
var v = sessionToken.Body.OwnerId == grpcContainer.OwnerId;
ctx.GetPublicKeyCache());
request.AddMetaHeader(args.XHeaders, sessionToken);
@ -95,7 +94,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
await WaitForContainer(WaitExpects.Exists, response.Body.ContainerId, args.WaitParams, ctx);
return new ContainerId(Base58.Encode(response.Body.ContainerId.Value.ToByteArray()));
return new FrostFsContainerId(response.Body.ContainerId);
}
internal async Task DeleteContainerAsync(PrmContainerDelete args)
@ -116,7 +115,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
request.Body.ContainerId,
ContainerSessionContext.Types.Verb.Delete,
ctx.Key,
ctx.PublicKeyCache);
ctx.GetPublicKeyCache());
request.AddMetaHeader(args.XHeaders, sessionToken);
@ -193,7 +192,7 @@ internal class ContainerServiceProvider(ContainerService.ContainerServiceClient
if (DateTime.UtcNow >= deadLine)
throw new TimeoutException();
if (ex.Status.Code != ModelsV2.Enums.StatusCode.ContainerNotFound)
if (ex.Status.Code != FrostFsStatusCode.ContainerNotFound)
throw;
if (expect == WaitExpects.Removed)

View file

@ -1,13 +1,11 @@
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 FrostFS.Netmap;
using FrostFS.SDK.ClientV2;
using static FrostFS.Netmap.NetworkConfig.Types;
using FrostFS.SDK.ClientV2.Parameters;
namespace FrostFS.SDK.ClientV2;
@ -40,7 +38,7 @@ internal class NetmapServiceProvider : ContextAccessor
return settings;
}
internal async Task<NodeInfo> GetLocalNodeInfoAsync(PrmNodeInfo args)
internal async Task<FrostFsNodeInfo> GetLocalNodeInfoAsync(PrmNodeInfo args)
{
var ctx = args.Context!;
var request = new LocalNodeInfoRequest
@ -72,7 +70,7 @@ internal class NetmapServiceProvider : ContextAccessor
return response;
}
internal async Task<NetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot args)
internal async Task<FrostFsNetmapSnapshot> GetNetmapSnapshotAsync(PrmNetmapSnapshot args)
{
var ctx = args.Context!;

View file

@ -1,23 +1,23 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Google.Protobuf;
using FrostFS.Object;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Extensions;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.ClientV2;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ClientV2.Extensions;
using FrostFS.SDK.ClientV2.Parameters;
using System.Buffers;
using Google.Protobuf;
namespace FrostFS.SDK.ClientV2;
internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, ClientEnvironment env) : ContextAccessor(env), ISessionProvider
internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, ClientEnvironment env)
: ContextAccessor(env), ISessionProvider
{
readonly SessionProvider sessions = new (env);
@ -26,16 +26,17 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
return await sessions.GetOrCreateSession(args, ctx);
}
internal async Task<ObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
internal async Task<FrostFsObjectHeader> GetObjectHeadAsync(PrmObjectHeadGet args)
{
var ctx = args.Context!;
var request = new HeadRequest
{
Body = new HeadRequest.Types.Body
{
Address = new Address
{
ContainerId = args.ContainerId.ToMessage(),
ContainerId = args.ContainerId.ContainerID,
ObjectId = args.ObjectId.ToMessage()
}
}
@ -119,7 +120,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
Verifier.CheckResponse(response);
}
internal async IAsyncEnumerable<ObjectId> SearchObjectsAsync(PrmObjectSearch args)
internal async IAsyncEnumerable<FrostFsObjectId> SearchObjectsAsync(PrmObjectSearch args)
{
var ctx = args.Context!;
var request = new SearchRequest
@ -149,11 +150,11 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
await foreach (var oid in objectsIds)
{
yield return ObjectId.FromHash(oid.Value.ToByteArray());
yield return FrostFsObjectId.FromHash(oid.Value.ToByteArray());
}
}
internal async Task<ObjectId> PutObjectAsync(PrmObjectPut args)
internal async Task<FrostFsObjectId> PutObjectAsync(PrmObjectPut args)
{
if (args.Header == null)
throw new ArgumentException("Value cannot be null", nameof(args.Header));
@ -174,17 +175,14 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
}
}
internal async Task<ObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
internal async Task<FrostFsObjectId> PutSingleObjectAsync(PrmSingleObjectPut args)
{
var ctx = args.Context!;
var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ctx);
var request = new PutSingleRequest
{
Body = new PutSingleRequest.Types.Body()
{
Object = grpcObject
}
Body = new () { Object = grpcObject }
};
var sessionToken = await GetOrCreateSession(args, ctx);
@ -202,15 +200,15 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
Verifier.CheckResponse(response);
return ObjectId.FromHash(grpcObject.ObjectId.Value.ToByteArray());
return FrostFsObjectId.FromHash(grpcObject.ObjectId.Value.ToByteArray());
}
private async Task<ObjectId> PutClientCutObject(PrmObjectPut args)
private async Task<FrostFsObjectId> PutClientCutObject(PrmObjectPut args)
{
var ctx = args.Context!;
var tokenRaw = await GetOrCreateSession(args, ctx);
var token = new ModelsV2.SessionToken(tokenRaw.Serialize());
var token = new FrostFsSessionToken(tokenRaw.Serialize());
args.SessionToken = token;
@ -237,9 +235,9 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
var restPart = (restBytes % (ulong)objectSize) > 0 ? 1 : 0;
var objectsCount = fullLength > 0 ? (int)(restBytes / (ulong)objectSize) + restPart : 0;
List<ObjectId> sentObjectIds = new(objectsCount);
List<FrostFsObjectId> sentObjectIds = new(objectsCount);
Split? split = null;
FrostFsSplit? split = null;
// keep attributes for the large object
var attributes = args.Header!.Attributes;
@ -249,7 +247,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
{
if (split == null)
{
split = new Split();
split = new FrostFsSplit();
args.Header!.Attributes = [];
}
@ -266,7 +264,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
// send the last part and create linkObject
if (sentObjectIds.Count > 0)
{
var largeObjectHeader = new ObjectHeader(header.ContainerId) { PayloadLength = fullLength };
var largeObjectHeader = new FrostFsObjectHeader(header.ContainerId) { PayloadLength = fullLength };
largeObjectHeader.Attributes.AddRange(attributes);
@ -276,7 +274,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
sentObjectIds.Add(result.ObjectId);
var linkObject = new LinkObject(header.ContainerId, split!.SplitId, largeObjectHeader)
var linkObject = new FrostFsLinkObject(header.ContainerId, split!.SplitId, largeObjectHeader)
.AddChildren(sentObjectIds);
_ = await PutSingleObjectAsync(new PrmSingleObjectPut(linkObject) { Context = args.Context});
@ -290,9 +288,9 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
return singlePartResult.ObjectId;
}
struct PutObjectResult(ObjectId objectId, int objectSize)
struct PutObjectResult(FrostFsObjectId objectId, int objectSize)
{
public ObjectId ObjectId = objectId;
public FrostFsObjectId ObjectId = objectId;
public int ObjectSize = objectSize;
}
@ -359,7 +357,7 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
var response = await stream.Close();
Verifier.CheckResponse(response);
return new PutObjectResult(ObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray()), sentBytes);
return new PutObjectResult(FrostFsObjectId.FromHash(response.Body.ObjectId.Value.ToByteArray()), sentBytes);
}
finally
{
@ -374,10 +372,10 @@ internal class ObjectServiceProvider(ObjectService.ObjectServiceClient client, C
{
var header = args.Header!;
header.OwnerId = ctx.OwnerId;
header.Version = ctx.Version;
header.OwnerId ??= ctx.OwnerId;
header.Version ??= ctx.Version;
var grpcHeader = header.ToMessage();
var grpcHeader = header.GetHeader();
if (header.Split != null)
{

View file

@ -1,6 +1,7 @@
using System.Threading.Tasks;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.ClientV2;
using FrostFS.Session;
namespace FrostFS.SDK.ClientV2;

View file

@ -4,5 +4,3 @@ internal class ContextAccessor(ClientEnvironment context)
{
protected ClientEnvironment Context { get; set; } = context;
}

View file

@ -1,6 +1,6 @@
using System.Threading.Tasks;
using FrostFS.SDK.ClientV2.Parameters;
using FrostFS.SDK.ClientV2;
namespace FrostFS.SDK.ClientV2;

View file

@ -1,20 +1,20 @@
using FrostFS.SDK.ModelsV2;
using Grpc.Net.Client;
using System;
using System.Security.Cryptography;
using System.Buffers;
using System.Security.Cryptography;
using Grpc.Net.Client;
namespace FrostFS.SDK.ClientV2;
public class ClientEnvironment(Client client, ECDsa? key, OwnerId? owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable
public class ClientEnvironment(Client client, ECDsa? key, FrostFsOwner? owner, GrpcChannel channel, FrostFsVersion version) : IDisposable
{
private ArrayPool<byte> _arrayPool;
internal OwnerId? Owner { get; } = owner;
internal FrostFsOwner? Owner { get; } = owner;
internal GrpcChannel Channel { get; private set; } = channel;
internal ModelsV2.Version Version { get; } = version;
internal FrostFsVersion Version { get; } = version;
internal NetworkSettings? NetworkSettings { get; set; }
@ -42,7 +42,7 @@ public class ClientEnvironment(Client client, ECDsa? key, OwnerId? owner, GrpcCh
{
if (disposing)
{
Channel.Dispose();
Channel?.Dispose();
}
}
}

View file

@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2.Extensions;
@ -21,29 +19,29 @@ public static class ObjectExtensions
public static FrostFsObject AddAttribute(this FrostFsObject obj, string key, string value)
{
obj.AddAttribute(new ObjectAttribute(key, value));
obj.AddAttribute(new FrostFsAttribute(key, value));
return obj;
}
public static FrostFsObject AddAttribute(this FrostFsObject obj, ObjectAttribute attribute)
public static FrostFsObject AddAttribute(this FrostFsObject obj, FrostFsAttribute attribute)
{
obj.Header.Attributes.Add(attribute);
return obj;
}
public static FrostFsObject AddAttributes(this FrostFsObject obj, IEnumerable<ObjectAttribute> attributes)
public static FrostFsObject AddAttributes(this FrostFsObject obj, IEnumerable<FrostFsAttribute> attributes)
{
obj.Header.Attributes.AddRange(attributes);
return obj;
}
public static FrostFsObject SetSplit(this FrostFsObject obj, Split? split)
public static FrostFsObject SetSplit(this FrostFsObject obj, FrostFsSplit? split)
{
obj.Header.Split = split;
return obj;
}
public static LinkObject AddChildren(this LinkObject linkObject, IEnumerable<ObjectId> objectIds)
public static FrostFsLinkObject AddChildren(this FrostFsLinkObject linkObject, IEnumerable<FrostFsObjectId> objectIds)
{
linkObject.Header.Split!.Children.AddRange(objectIds);
return linkObject;

View file

@ -4,7 +4,6 @@ using System.Threading.Tasks;
using Grpc.Core;
using FrostFS.Object;
using FrostFS.SDK.ModelsV2;
using System.Threading;
namespace FrostFS.SDK.ClientV2;
@ -33,7 +32,7 @@ public class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IObjectR
};
}
public async Task<byte[]?> ReadChunk(CancellationToken cancellationToken = default)
public async Task<ReadOnlyMemory<byte>?> ReadChunk(CancellationToken cancellationToken = default)
{
if (!await Call.ResponseStream.MoveNext(cancellationToken))
return null;
@ -44,14 +43,14 @@ public class ObjectReader(AsyncServerStreamingCall<GetResponse> call) : IObjectR
if (response.Body.ObjectPartCase != GetResponse.Types.Body.ObjectPartOneofCase.Chunk)
throw new InvalidOperationException("unexpected message type");
return response.Body.Chunk.ToByteArray();
return response.Body.Chunk.Memory;
}
public void Dispose()
{
if (!disposed)
{
Call.Dispose();
Call?.Dispose();
GC.SuppressFinalize(this);
disposed = true;

View file

@ -30,6 +30,6 @@ internal class ObjectStreamer(AsyncClientStreamingCall<PutRequest, PutResponse>
public void Dispose()
{
Call.Dispose();
Call?.Dispose();
}
}

View file

@ -6,13 +6,12 @@ using FrostFS.Object;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK.ClientV2;
internal class ObjectTools
{
internal static ObjectId CalculateObjectId(ObjectHeader header, Context ctx)
internal static FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header, Context ctx)
{
var grpcHeader = CreateHeader(header, [], ctx);
@ -24,10 +23,10 @@ internal class ObjectTools
internal static Object.Object CreateObject(FrostFsObject @object, Context ctx)
{
@object.Header.OwnerId = ctx.OwnerId;
@object.Header.Version = ctx.Version;
@object.Header.OwnerId ??= ctx.OwnerId;
@object.Header.Version ??= ctx.Version;
var grpcHeader = @object.Header.ToMessage();
var grpcHeader = @object.Header.GetHeader();
grpcHeader.PayloadLength = (ulong)@object.Payload.Length;
grpcHeader.PayloadHash = Sha256Checksum(@object.Payload);
@ -47,18 +46,21 @@ internal class ObjectTools
obj.Signature = new Refs.Signature
{
Key = ctx.PublicKeyCache,
Key = ctx.GetPublicKeyCache(),
Sign = ByteString.CopyFrom(ctx.Key.SignData(obj.ObjectId.ToByteArray())),
};
return obj;
}
internal static void SetSplitValues(Header grpcHeader, ModelsV2.Split split, Context ctx)
internal static void SetSplitValues(Header grpcHeader, FrostFsSplit split, Context ctx)
{
if (split == null)
return;
grpcHeader.Split = new Header.Types.Split
{
SplitId = split.SplitId != null ? ByteString.CopyFrom(split.SplitId.ToBinary()) : null
SplitId = split.SplitId?.GetSplitId()
};
if (split.Children != null && split.Children.Count != 0)
@ -72,7 +74,7 @@ internal class ObjectTools
grpcHeader.Split.ParentHeader = grpcParentHeader;
grpcHeader.Split.ParentSignature = new Refs.Signature
{
Key = ctx.PublicKeyCache,
Key = ctx.GetPublicKeyCache(),
Sign = ByteString.CopyFrom(ctx.Key.SignData(grpcHeader.Split.Parent.ToByteArray())),
};
@ -82,13 +84,13 @@ internal class ObjectTools
grpcHeader.Split.Previous = split.Previous?.ToMessage();
}
internal static Header CreateHeader(ObjectHeader header, byte[]? payload, Context ctx)
internal static Header CreateHeader(FrostFsObjectHeader header, byte[]? payload, Context ctx)
{
var grpcHeader = header.ToMessage();
grpcHeader.OwnerId = ctx.OwnerId.ToMessage();
grpcHeader.Version = ctx.Version.ToMessage();
header.OwnerId ??= ctx.OwnerId;
header.Version ??= ctx.Version;
var grpcHeader = header.GetHeader();
if (payload != null) // && payload.Length > 0
grpcHeader.PayloadHash = Sha256Checksum(payload);

View file

@ -24,10 +24,8 @@ namespace System
public Index(int value, bool fromEnd = false)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
if (fromEnd)
_value = ~value;
else
@ -52,10 +50,8 @@ namespace System
public static Index FromStart(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(value);
}
@ -65,10 +61,8 @@ namespace System
public static Index FromEnd(int value)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(nameof(value), "value must be non-negative");
}
return new Index(~value);
}
@ -77,14 +71,7 @@ namespace System
{
get
{
if (_value < 0)
{
return ~_value;
}
else
{
return _value;
}
return _value < 0 ? ~_value : _value;
}
}
@ -202,6 +189,7 @@ namespace System
{
int start;
var startIndex = Start;
if (startIndex.IsFromEnd)
start = length - startIndex.Value;
else
@ -209,16 +197,15 @@ namespace System
int end;
var endIndex = End;
if (endIndex.IsFromEnd)
end = length - endIndex.Value;
else
end = endIndex.Value;
if ((uint)end > (uint)length || (uint)start > (uint)end)
{
throw new ArgumentOutOfRangeException(nameof(length));
}
return (start, end - start);
}
}
@ -234,10 +221,8 @@ namespace System.Runtime.CompilerServices
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
throw new ArgumentNullException(nameof(array));
}
(int offset, int length) = range.GetOffsetAndLength(array.Length);
if (default(T) != null || typeof(T[]) == array.GetType())
@ -245,10 +230,8 @@ namespace System.Runtime.CompilerServices
// We know the type of the array to be exactly T[].
if (length == 0)
{
return [];
}
var dest = new T[length];
Array.Copy(array, offset, dest, 0, length);
return dest;

View file

@ -5,7 +5,6 @@ using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ModelsV2;
using FrostFS.SDK.ProtosV2.Interfaces;
using FrostFS.Session;

View file

@ -1,6 +1,11 @@
using System;
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ProtosV2.Interfaces;
using FrostFS.Session;
using Google.Protobuf;
using Org.BouncyCastle.Asn1.Sec;
@ -9,11 +14,6 @@ using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using FrostFS.Refs;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using FrostFS.SDK.ProtosV2.Interfaces;
namespace FrostFS.SDK.ClientV2;
public static class RequestSigner

View file

@ -1,13 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Grpc.Core;
using FrostFS.Object;
using FrostFS.Refs;
using System.Threading;
using Grpc.Core;
namespace FrostFS.SDK.ClientV2;
@ -29,6 +29,6 @@ internal class SearchReader(AsyncServerStreamingCall<SearchResponse> call) : IDi
public void Dispose()
{
Call.Dispose();
Call?.Dispose();
}
}

View file

@ -1,6 +1,12 @@
using System;
using System.Security.Cryptography;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.SDK.ProtosV2.Interfaces;
using FrostFS.Session;
using Google.Protobuf;
using Org.BouncyCastle.Asn1.Sec;
@ -9,12 +15,6 @@ using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
using FrostFS.Refs;
using FrostFS.SDK.ClientV2.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using FrostFS.Session;
using FrostFS.SDK.ProtosV2.Interfaces;
namespace FrostFS.SDK.ClientV2;
public static class Verifier

View file

@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Text;
namespace FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK;
public class ClientSettings
{
@ -13,7 +13,7 @@ public class ClientSettings
public virtual void Validate()
{
var errors = CheckFields();
if (errors != null)
if (errors != null)
ThrowException(errors);
}
@ -28,7 +28,7 @@ public class ClientSettings
}
protected static void ThrowException(List<string> errors)
{
{
StringBuilder messages = new();
foreach (var error in errors)
@ -48,7 +48,7 @@ public class SingleOwnerClientSettings : ClientSettings
{
var errors = CheckFields();
if (errors != null)
ThrowException(errors);
ThrowException(errors);
}
protected List<string>? CheckFields()
@ -59,5 +59,5 @@ public class SingleOwnerClientSettings : ClientSettings
(errors ??= []).Add(string.Format(errorTemplate, nameof(Key)));
return errors;
}
}
}

View file

@ -1,13 +0,0 @@
using System;
using FrostFS.SDK.ModelsV2.Enums;
using FrostFS.SDK.ModelsV2.Netmap;
namespace FrostFS.SDK.ModelsV2;
public class Container(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

@ -1,4 +1,4 @@
namespace FrostFS.SDK.ModelsV2;
namespace FrostFS.SDK;
public class ContainerId(string id)
{

View file

@ -0,0 +1,11 @@
using System;
namespace FrostFS.SDK;
public class FrostFsContainer(BasicAcl basicAcl, FrostFsPlacementPolicy placementPolicy)
{
public Guid Nonce { get; set; } = Guid.NewGuid();
public BasicAcl BasicAcl { get; set; } = basicAcl;
public FrostFsPlacementPolicy PlacementPolicy { get; set; } = placementPolicy;
public FrostFsVersion? Version { get; set; }
}

View file

@ -1,6 +1,6 @@
using System.ComponentModel;
namespace FrostFS.SDK.ModelsV2.Enums;
namespace FrostFS.SDK;
public enum BasicAcl
{

View file

@ -0,0 +1,10 @@
namespace FrostFS.SDK;
public enum FrostFsObjectMatchType
{
Unspecified = 0,
Equals = 1,
NotEquals = 2,
KeyAbsent = 3,
StartsWith = 4
}

Some files were not shown because too many files have changed in this diff Show more