From bb6e187b6164ea1652b93b42118edcc3bef440ec Mon Sep 17 00:00:00 2001 From: Ivan Pchelintsev Date: Mon, 13 May 2024 17:27:32 +0300 Subject: [PATCH] [#1] Add presentation layer Signed-off-by: Ivan Pchelintsev --- sdk/FrostFS.SDK.sln | 6 + sdk/src/FrostFS.SDK.ClientV2/Client.cs | 26 +- .../Interfaces/IFrostFSClient.cs | 11 + .../Mappers/GRPC/Container.cs | 26 ++ .../Mappers/GRPC/ContainerId.cs | 16 + .../Mappers/GRPC/MetaHeader.cs | 22 + .../Mappers/GRPC/Netmap/PlacementPolicy.cs | 34 ++ .../Mappers/GRPC/Netmap/Replica.cs | 20 + .../Mappers/GRPC/ObjectId.cs | 16 + .../Mappers/GRPC/OwnerId.cs | 16 + .../Mappers/GRPC/Version.cs | 18 + .../RequestConstructor.cs | 19 +- .../Services/Container.cs | 56 +-- .../FrostFS.SDK.ClientV2/Services/Object.cs | 43 ++ .../FrostFS.SDK.ClientV2/Services/Session.cs | 6 +- sdk/src/FrostFS.SDK.ModelsV2/Container.cs | 16 + .../Netmap/PlacementPolicy.cs | 10 +- .../FrostFS.SDK.ModelsV2/Netmap/Replica.cs | 10 +- sdk/src/FrostFS.SDK.ModelsV2/ObjectId.cs | 32 ++ .../object/Extension.Message.cs | 396 ++++++++++++++++++ .../FrostFS.SDK.Service.csproj | 13 + sdk/src/FrostFS.SDK.Service/Service.cs | 45 ++ 22 files changed, 778 insertions(+), 79 deletions(-) create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Container.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ContainerId.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/MetaHeader.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/PlacementPolicy.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/Replica.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ObjectId.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/OwnerId.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Version.cs create mode 100644 sdk/src/FrostFS.SDK.ClientV2/Services/Object.cs create mode 100644 sdk/src/FrostFS.SDK.ModelsV2/Container.cs create mode 100644 sdk/src/FrostFS.SDK.ModelsV2/ObjectId.cs create mode 100644 sdk/src/FrostFS.SDK.ProtosV2/object/Extension.Message.cs create mode 100644 sdk/src/FrostFS.SDK.Service/FrostFS.SDK.Service.csproj create mode 100644 sdk/src/FrostFS.SDK.Service/Service.cs diff --git a/sdk/FrostFS.SDK.sln b/sdk/FrostFS.SDK.sln index 424a077..4120cd8 100644 --- a/sdk/FrostFS.SDK.sln +++ b/sdk/FrostFS.SDK.sln @@ -10,6 +10,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Cryptography", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.ModelsV2", "src\FrostFS.SDK.ModelsV2\FrostFS.SDK.ModelsV2.csproj", "{3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrostFS.SDK.Service", "src\FrostFS.SDK.Service\FrostFS.SDK.Service.csproj", "{5807CC9E-BDA3-48B1-9EF3-F76F0F522981}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -36,5 +38,9 @@ Global {3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU {3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU {3F6E5EE6-2AAC-45BE-A5E2-B83D11F90CC3}.Release|Any CPU.Build.0 = Release|Any CPU + {5807CC9E-BDA3-48B1-9EF3-F76F0F522981}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5807CC9E-BDA3-48B1-9EF3-F76F0F522981}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5807CC9E-BDA3-48B1-9EF3-F76F0F522981}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5807CC9E-BDA3-48B1-9EF3-F76F0F522981}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/sdk/src/FrostFS.SDK.ClientV2/Client.cs b/sdk/src/FrostFS.SDK.ClientV2/Client.cs index 56aeb4c..b8a6def 100644 --- a/sdk/src/FrostFS.SDK.ClientV2/Client.cs +++ b/sdk/src/FrostFS.SDK.ClientV2/Client.cs @@ -1,31 +1,37 @@ using System.Security.Cryptography; using FrostFS.Container; using FrostFS.Netmap; +using FrostFS.Object; +using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.Cryptography; +using FrostFS.SDK.ModelsV2; using FrostFS.Session; using Grpc.Core; using Grpc.Net.Client; -using Version = FrostFS.SDK.ModelsV2.Version; namespace FrostFS.SDK.ClientV2; -public partial class Client +public partial class Client: IFrostFSClient { - private readonly ECDsa _key; private GrpcChannel _channel; - private Version _version = new (2, 13); + private readonly ECDsa _key; + private readonly OwnerId _owner; + public readonly ModelsV2.Version Version = new (2, 13); private ContainerService.ContainerServiceClient _containerServiceClient; private NetmapService.NetmapServiceClient _netmapServiceClient; + private ObjectService.ObjectServiceClient _objectServiceClient; private SessionService.SessionServiceClient _sessionServiceClient; public Client(string key, string host) { // TODO: Развязать клиент и реализацию GRPC _key = key.LoadWif(); + _owner = OwnerId.FromKey(_key); InitGrpcChannel(host); InitContainerClient(); InitNetmapClient(); + InitObjectClient(); InitSessionClient(); CheckFrostFsVersionSupport(); } @@ -33,11 +39,8 @@ public partial class Client private void CheckFrostFsVersionSupport() { var localNodeInfo = GetLocalNodeInfoAsync().Result; - var frostFsVersion = new Version( - (int)localNodeInfo.Body.Version.Major, - (int)localNodeInfo.Body.Version.Minor - ); - if (!frostFsVersion.IsSupported(_version)) + var frostFsVersion = localNodeInfo.Body.Version.ToModel(); + if (!frostFsVersion.IsSupported(Version)) { var msg = $"FrostFS {frostFsVersion} is not supported."; Console.WriteLine(msg); @@ -86,6 +89,11 @@ public partial class Client { _netmapServiceClient = new NetmapService.NetmapServiceClient(_channel); } + + private void InitObjectClient() + { + _objectServiceClient = new ObjectService.ObjectServiceClient(_channel); + } private void InitSessionClient() { diff --git a/sdk/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs b/sdk/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs new file mode 100644 index 0000000..bbd3d1d --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Interfaces/IFrostFSClient.cs @@ -0,0 +1,11 @@ +using FrostFS.Refs; + +namespace FrostFS.SDK.ClientV2; + +public interface IFrostFSClient +{ + Task ListContainersAsync(); + Task CreateContainerAsync(Container.Container container); + Task GetContainerAsync(ContainerID containerId); + Task DeleteContainerAsync(ContainerID cid); +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Container.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Container.cs new file mode 100644 index 0000000..d6553bc --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Container.cs @@ -0,0 +1,26 @@ +using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; +using FrostFS.SDK.Cryptography; +using Google.Protobuf; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class ContainerMapper +{ + public static Container.Container ToGrpcMessage(this ModelsV2.Container container) + { + return new Container.Container + { + PlacementPolicy = container.PlacementPolicy.ToGrpcMessage(), + Nonce = ByteString.CopyFrom(container.Nonce.ToBytes()) + }; + } + + public static ModelsV2.Container ToModel(this Container.Container container) + { + return new ModelsV2.Container(container.PlacementPolicy.ToModel()) + { + Nonce = container.Nonce.ToUuid(), + Version = container.Version.ToModel() + }; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ContainerId.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ContainerId.cs new file mode 100644 index 0000000..eb26623 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ContainerId.cs @@ -0,0 +1,16 @@ +using FrostFS.SDK.ModelsV2; +using FrostFS.Refs; +using Google.Protobuf; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class ContainerIdMapper +{ + public static ContainerID ToGrpcMessage(this ContainerId containerId) + { + return new ContainerID + { + Value = ByteString.CopyFrom(containerId.ToHash()) + }; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/MetaHeader.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/MetaHeader.cs new file mode 100644 index 0000000..c32a466 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/MetaHeader.cs @@ -0,0 +1,22 @@ +using FrostFS.SDK.ModelsV2; +using FrostFS.Session; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class MetaHeaderMapper +{ + public static RequestMetaHeader ToGrpcMessage(this MetaHeader metaHeader) + { + return new RequestMetaHeader + { + Version = new Refs.Version + { + Major = (uint)metaHeader.Version.Major, + Minor = (uint)metaHeader.Version.Minor, + + }, + Epoch = (uint)metaHeader.Epoch, + Ttl = (uint)metaHeader.Ttl + }; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/PlacementPolicy.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/PlacementPolicy.cs new file mode 100644 index 0000000..7ca1d10 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/PlacementPolicy.cs @@ -0,0 +1,34 @@ +using FrostFS.Netmap; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; + +public static class PlacementPolicyMapper +{ + public static PlacementPolicy ToGrpcMessage(this ModelsV2.Netmap.PlacementPolicy placementPolicy) + { + var pp = new PlacementPolicy + { + Filters = { }, + Selectors = { }, + Replicas = { }, + Unique = placementPolicy.Unique + }; + foreach (var replica in placementPolicy.Replicas) + { + pp.Replicas.Add(replica.ToGrpcMessage()); + } + + return pp; + } + + public static ModelsV2.Netmap.PlacementPolicy ToModel(this PlacementPolicy placementPolicy) + { + var replicas = new List(); + foreach (var replica in placementPolicy.Replicas) + { + replicas.Add(replica.ToModel()); + } + + return new ModelsV2.Netmap.PlacementPolicy(placementPolicy.Unique, replicas.ToArray()); + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/Replica.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/Replica.cs new file mode 100644 index 0000000..7435085 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Netmap/Replica.cs @@ -0,0 +1,20 @@ +using FrostFS.Netmap; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; + +public static class ReplicaMapper +{ + public static Replica ToGrpcMessage(this ModelsV2.Netmap.Replica replica) + { + return new Replica + { + Count = (uint)replica.Count, + Selector = replica.Selector + }; + } + + public static ModelsV2.Netmap.Replica ToModel(this Replica replica) + { + return new ModelsV2.Netmap.Replica((int)replica.Count, replica.Selector); + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ObjectId.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ObjectId.cs new file mode 100644 index 0000000..c6baae9 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/ObjectId.cs @@ -0,0 +1,16 @@ +using FrostFS.SDK.ModelsV2; +using FrostFS.Refs; +using Google.Protobuf; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class ObjectIdMapper +{ + public static ObjectID ToGrpcMessage(this ObjectId objectId) + { + return new ObjectID + { + Value = ByteString.CopyFrom(objectId.ToHash()) + }; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/OwnerId.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/OwnerId.cs new file mode 100644 index 0000000..8259478 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/OwnerId.cs @@ -0,0 +1,16 @@ +using FrostFS.SDK.ModelsV2; +using FrostFS.Refs; +using Google.Protobuf; + +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class OwnerIdMapper +{ + public static OwnerID ToGrpcMessage(this OwnerId ownerId) + { + return new OwnerID + { + Value = ByteString.CopyFrom(ownerId.ToHash()) + }; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Version.cs b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Version.cs new file mode 100644 index 0000000..db8601d --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Mappers/GRPC/Version.cs @@ -0,0 +1,18 @@ +namespace FrostFS.SDK.ClientV2.Mappers.GRPC; + +public static class VersionMapper +{ + public static Refs.Version ToGrpcMessage(this ModelsV2.Version version) + { + return new Refs.Version + { + Major = (uint)version.Major, + Minor = (uint)version.Minor + }; + } + + public static ModelsV2.Version ToModel(this Refs.Version version) + { + return new ModelsV2.Version((int)version.Major, (int)version.Minor); + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/RequestConstructor.cs b/sdk/src/FrostFS.SDK.ClientV2/RequestConstructor.cs index c365b8c..4b02714 100644 --- a/sdk/src/FrostFS.SDK.ClientV2/RequestConstructor.cs +++ b/sdk/src/FrostFS.SDK.ClientV2/RequestConstructor.cs @@ -1,3 +1,4 @@ +using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.ModelsV2; using FrostFS.Session; @@ -5,22 +6,10 @@ namespace FrostFS.SDK.ClientV2; public static class RequestConstructor { - public static void AddMetaHeader(this IRequest request, MetaHeader? metaHeader = null) + public static void AddMetaHeader(this IRequest request, RequestMetaHeader? metaHeader = null) { if (request.MetaHeader is not null) return; - - metaHeader ??= MetaHeader.Default(); - - request.MetaHeader = new RequestMetaHeader - { - Version = new Refs.Version - { - Major = (uint)metaHeader.Version.Major, - Minor = (uint)metaHeader.Version.Minor, - - }, - Epoch = (uint)metaHeader.Epoch, - Ttl = (uint)metaHeader.Ttl - }; + metaHeader ??= MetaHeader.Default().ToGrpcMessage(); + request.MetaHeader = metaHeader; } } diff --git a/sdk/src/FrostFS.SDK.ClientV2/Services/Container.cs b/sdk/src/FrostFS.SDK.ClientV2/Services/Container.cs index 64746b3..e85c4c9 100644 --- a/sdk/src/FrostFS.SDK.ClientV2/Services/Container.cs +++ b/sdk/src/FrostFS.SDK.ClientV2/Services/Container.cs @@ -1,21 +1,13 @@ using FrostFS.Container; -using FrostFS.Netmap; using FrostFS.Refs; -using FrostFS.SDK.Cryptography; -using FrostFS.SDK.ModelsV2; -using Google.Protobuf; -using Version = FrostFS.Refs.Version; +using FrostFS.SDK.ClientV2.Mappers.GRPC; namespace FrostFS.SDK.ClientV2; public partial class Client { - public async Task GetContainerAsync(ContainerId containerId) + public async Task GetContainerAsync(ContainerID cid) { - var cid = new ContainerID - { - Value = ByteString.CopyFrom(containerId.ToHash()) - }; var request = new GetRequest { Body = new GetRequest.Types.Body @@ -34,10 +26,7 @@ public partial class Client { Body = new ListRequest.Types.Body { - OwnerId = new OwnerID - { - Value = ByteString.CopyFrom(OwnerId.FromKey(_key).ToHash()) - } + OwnerId = _owner.ToGrpcMessage() } }; request.AddMetaHeader(); @@ -45,36 +34,11 @@ public partial class Client return await _containerServiceClient.ListAsync(request); } - public async Task CreateContainerAsync(ModelsV2.Netmap.PlacementPolicy placementPolicy) + public async Task CreateContainerAsync(Container.Container container) { - var container = new Container.Container - { - Version = new Version - { - Major = 2, - Minor = 13 - }, - OwnerId = new OwnerID - { - Value = ByteString.CopyFrom(OwnerId.FromKey(_key).ToHash()) - }, - PlacementPolicy = new PlacementPolicy - { - Filters = { }, - Selectors = { }, - Replicas = { } - }, - Nonce = ByteString.CopyFrom(Guid.NewGuid().ToBytes()) - }; - foreach (var replica in placementPolicy.Replicas) - { - container.PlacementPolicy.Replicas.Add(new Replica - { - Count = (uint)replica.Count, - Selector = replica.Selector - } - ); - } + container.BasicAcl = 0x1FBFBFFF; + container.OwnerId = _owner.ToGrpcMessage(); + container.Version = Version.ToGrpcMessage(); var request = new PutRequest { Body = new PutRequest.Types.Body @@ -88,12 +52,8 @@ public partial class Client return await _containerServiceClient.PutAsync(request); } - public async Task DeleteContainerAsync(ContainerId containerId) + public async Task DeleteContainerAsync(ContainerID cid) { - var cid = new ContainerID - { - Value = ByteString.CopyFrom(containerId.ToHash()) - }; var request = new DeleteRequest { Body = new DeleteRequest.Types.Body diff --git a/sdk/src/FrostFS.SDK.ClientV2/Services/Object.cs b/sdk/src/FrostFS.SDK.ClientV2/Services/Object.cs new file mode 100644 index 0000000..da98868 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ClientV2/Services/Object.cs @@ -0,0 +1,43 @@ +using FrostFS.Object; +using FrostFS.Refs; + +namespace FrostFS.SDK.ClientV2; + +public partial class Client +{ + public async Task GetObjectHeadAsync(ContainerID cid, ObjectID oid) + { + var request = new HeadRequest + { + Body = new HeadRequest.Types.Body + { + Address = new Address + { + ContainerId = cid, + ObjectId = oid + } + }, + }; + request.AddMetaHeader(); + request.Sign(_key); + return await _objectServiceClient.HeadAsync(request); + } + + public async Task DeleteObjectAsync(ContainerID cid, ObjectID oid) + { + var request = new DeleteRequest + { + Body = new DeleteRequest.Types.Body + { + Address = new Address + { + ContainerId = cid, + ObjectId = oid + } + } + }; + request.AddMetaHeader(); + request.Sign(_key); + return await _objectServiceClient.DeleteAsync(request); + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ClientV2/Services/Session.cs b/sdk/src/FrostFS.SDK.ClientV2/Services/Session.cs index 008a270..96104b4 100644 --- a/sdk/src/FrostFS.SDK.ClientV2/Services/Session.cs +++ b/sdk/src/FrostFS.SDK.ClientV2/Services/Session.cs @@ -1,4 +1,5 @@ using FrostFS.Refs; +using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.ModelsV2; using FrostFS.Session; using Google.Protobuf; @@ -13,10 +14,7 @@ public partial class Client { Body = new CreateRequest.Types.Body { - OwnerId = new OwnerID - { - Value = ByteString.CopyFrom(OwnerId.FromKey(_key).ToHash()) - }, + OwnerId = _owner.ToGrpcMessage(), Expiration = expiration, } }; diff --git a/sdk/src/FrostFS.SDK.ModelsV2/Container.cs b/sdk/src/FrostFS.SDK.ModelsV2/Container.cs new file mode 100644 index 0000000..a2fee21 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ModelsV2/Container.cs @@ -0,0 +1,16 @@ +using FrostFS.SDK.ModelsV2.Netmap; + +namespace FrostFS.SDK.ModelsV2; + +public class Container +{ + public Guid Nonce { get; set; } + public PlacementPolicy PlacementPolicy { get; set; } + public Version? Version { get; set; } + + public Container(PlacementPolicy placementPolicy) + { + Nonce = Guid.NewGuid(); + PlacementPolicy = placementPolicy; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ModelsV2/Netmap/PlacementPolicy.cs b/sdk/src/FrostFS.SDK.ModelsV2/Netmap/PlacementPolicy.cs index fc95b1c..d4960d7 100644 --- a/sdk/src/FrostFS.SDK.ModelsV2/Netmap/PlacementPolicy.cs +++ b/sdk/src/FrostFS.SDK.ModelsV2/Netmap/PlacementPolicy.cs @@ -2,6 +2,12 @@ namespace FrostFS.SDK.ModelsV2.Netmap; public class PlacementPolicy { - public List Replicas { get; set; } - public bool Unique { get; set; } + public Replica[] Replicas { get; init; } + public bool Unique { get; init; } + + public PlacementPolicy(bool unique, params Replica[] replicas) + { + Replicas = replicas; + Unique = unique; + } } \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ModelsV2/Netmap/Replica.cs b/sdk/src/FrostFS.SDK.ModelsV2/Netmap/Replica.cs index d58a72b..2b5ee12 100644 --- a/sdk/src/FrostFS.SDK.ModelsV2/Netmap/Replica.cs +++ b/sdk/src/FrostFS.SDK.ModelsV2/Netmap/Replica.cs @@ -3,5 +3,13 @@ namespace FrostFS.SDK.ModelsV2.Netmap; public class Replica { public int Count { get; set; } - public string Selector { get; set; } = String.Empty; + public string Selector { get; set; } + + public Replica(int count, string? selector = null) + { + selector ??= string.Empty; + + Count = count; + Selector = selector; + } } \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ModelsV2/ObjectId.cs b/sdk/src/FrostFS.SDK.ModelsV2/ObjectId.cs new file mode 100644 index 0000000..680e20f --- /dev/null +++ b/sdk/src/FrostFS.SDK.ModelsV2/ObjectId.cs @@ -0,0 +1,32 @@ +using FrostFS.SDK.Cryptography; + +namespace FrostFS.SDK.ModelsV2; + +public class ObjectId +{ + public string Value { get; } + + public ObjectId(string id) + { + Value = id; + } + + public static ObjectId FromHash(byte[] hash) + { + if (hash.Length != Helper.Sha256HashLength) + { + throw new FormatException("ObjectID must be a sha256 hash."); + } + return new ObjectId(Base58.Encode(hash)); + } + + public byte[] ToHash() + { + return Base58.Decode(Value); + } + + public override string ToString() + { + return Value; + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.ProtosV2/object/Extension.Message.cs b/sdk/src/FrostFS.SDK.ProtosV2/object/Extension.Message.cs new file mode 100644 index 0000000..243ab00 --- /dev/null +++ b/sdk/src/FrostFS.SDK.ProtosV2/object/Extension.Message.cs @@ -0,0 +1,396 @@ +using FrostFS.Session; +using Google.Protobuf; + +namespace FrostFS.Object +{ + public partial class GetRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class GetResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class PutRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class PutResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class DeleteRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class DeleteResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class HeadRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class HeadResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + public partial class SearchRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class SearchResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class GetRangeRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class GetRangeResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class GetRangeHashRequest : IRequest + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (RequestMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (RequestVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } + + public partial class GetRangeHashResponse : IResponse + { + IMetaHeader IVerificableMessage.GetMetaHeader() + { + return MetaHeader; + } + + IVerificationHeader IVerificableMessage.GetVerificationHeader() + { + return VerifyHeader; + } + + void IVerificableMessage.SetMetaHeader(IMetaHeader metaHeader) + { + MetaHeader = (ResponseMetaHeader)metaHeader; + } + + void IVerificableMessage.SetVerificationHeader(IVerificationHeader verificationHeader) + { + VerifyHeader = (ResponseVerificationHeader)verificationHeader; + } + + public IMessage GetBody() + { + return Body; + } + } +} \ No newline at end of file diff --git a/sdk/src/FrostFS.SDK.Service/FrostFS.SDK.Service.csproj b/sdk/src/FrostFS.SDK.Service/FrostFS.SDK.Service.csproj new file mode 100644 index 0000000..38e2646 --- /dev/null +++ b/sdk/src/FrostFS.SDK.Service/FrostFS.SDK.Service.csproj @@ -0,0 +1,13 @@ + + + + net6.0 + enable + enable + + + + + + + diff --git a/sdk/src/FrostFS.SDK.Service/Service.cs b/sdk/src/FrostFS.SDK.Service/Service.cs new file mode 100644 index 0000000..b977885 --- /dev/null +++ b/sdk/src/FrostFS.SDK.Service/Service.cs @@ -0,0 +1,45 @@ +using FrostFS.SDK.ClientV2; +using FrostFS.SDK.ClientV2.Mappers.GRPC; +using FrostFS.SDK.ModelsV2; +using Google.Protobuf; + +namespace FrostFS.SDK.Service; + +public class FrostFsService +{ + private readonly IFrostFSClient _client; + + public FrostFsService(IFrostFSClient client) + { + _client = client; + } + + public async Task ListContainersAsync() + { + var containersIds = new List(); + var listContainersResponse = await _client.ListContainersAsync(); + foreach (var cid in listContainersResponse.Body.ContainerIds) + { + containersIds.Add(ContainerId.FromHash(cid.Value.ToByteArray())); + } + + return containersIds.ToArray(); + } + + public async Task CreateContainerAsync(ModelsV2.Container container) + { + var createContainerResponse = await _client.CreateContainerAsync(container.ToGrpcMessage()); + return ContainerId.FromHash(createContainerResponse.Body.ContainerId.Value.ToByteArray()); + } + + public async Task GetContainerAsync(ContainerId containerId) + { + var getContainerResponse = await _client.GetContainerAsync(containerId.ToGrpcMessage()); + return getContainerResponse.Body.Container.ToModel(); + } + + public async Task DeleteContainerAsync(ContainerId containerId) + { + var deleteContainerResponse = await _client.DeleteContainerAsync(containerId.ToGrpcMessage()); + } +} \ No newline at end of file