[#23] Client: Refactoring to optimize memory usage #28

Merged
PavelGrossSpb merged 2 commits from PavelGrossSpb/frostfs-sdk-csharp:misc/refactoring into master 2024-09-12 12:54:25 +00:00
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

173
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(FrostFsMatchType.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,
FrostFsMatchType.Unspecified => MatchType.Unspecified,
FrostFsMatchType.Equals => MatchType.StringEqual,
FrostFsMatchType.NotEquals => MatchType.StringNotEqual,
FrostFsMatchType.KeyAbsent => MatchType.NotPresent,
FrostFsMatchType.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(StatusCode), status.Code);
var codeName = Enum.GetName(typeof(FrostFsStatusCode), 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 FrostFsMatchType
{
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,14 +1,14 @@
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
|| Unique != other.Unique

View file

@ -1,11 +1,11 @@
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;

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 FrostFsMatchType MatchType { get; set; }
public string Key { get; set; }
string? GetSerializedValue();
}
public abstract class FrostFsObjectFilter<T>(FrostFsMatchType matchType, string key, T value) : IObjectFilter
{
public FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType 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(FrostFsMatchType matchType, FrostFsObjectId ecParentId) : FrostFsObjectFilter<FrostFsObjectId>(matchType, Constants.FilterHeaderECParent, ecParentId) { }
/// <summary>
/// Creates filter to search Root objects
/// </summary>
public class FilterByRootObject() : FrostFsObjectFilter<string>(FrostFsMatchType.Unspecified, Constants.FilterHeaderRoot, string.Empty) { }
/// <summary>
/// Creates filter to search objects that are physically stored on the server
/// </summary
public class FilterByPhysicallyStored() : FrostFsObjectFilter<string>(FrostFsMatchType.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)
if (publicKeyCache == null && Key != null)
{
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;
dstepanov-yadro marked this conversation as resolved
Review

As far as I remember, C# code style requires that namespace must correspond directory structure.

As far as I remember, C# code style requires that namespace must correspond directory structure.
Review

Yes, it one of the suggestion. Requirements are defined by vendor. As for me, folder hierarchy is useful for structuring, but dozens of using - are not, especially for external users. Do we have such a requirement?

Yes, it one of the suggestion. Requirements are defined by vendor. As for me, folder hierarchy is useful for structuring, but dozens of using - are not, especially for external users. Do we have such a requirement?
Review

No

No
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,13 +33,13 @@ 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()
}
@ -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,12 +84,12 @@ 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();
header.OwnerId ??= ctx.OwnerId;
header.Version ??= ctx.Version;
grpcHeader.OwnerId = ctx.OwnerId.ToMessage();
grpcHeader.Version = ctx.Version.ToMessage();
var grpcHeader = header.GetHeader();
if (payload != null) // && payload.Length > 0
grpcHeader.PayloadHash = Sha256Checksum(payload);

View file

@ -24,9 +24,7 @@ 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;
@ -52,9 +50,7 @@ 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,9 +61,7 @@ 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,15 +197,14 @@ 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,9 +221,7 @@ 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);
@ -245,9 +230,7 @@ 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);

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
{

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