diff --git a/src/FrostFS.SDK.Client/Models/Object/FrostFsSplitInfo.cs b/src/FrostFS.SDK.Client/Models/Object/FrostFsSplitInfo.cs index 5030410..d8f8783 100644 --- a/src/FrostFS.SDK.Client/Models/Object/FrostFsSplitInfo.cs +++ b/src/FrostFS.SDK.Client/Models/Object/FrostFsSplitInfo.cs @@ -20,7 +20,9 @@ public class FrostFsSplitInfo public SplitId SplitId => _splitId ??= new SplitId(_splitInfo.SplitId.ToUuid()); - public FrostFsObjectId Link => _link ??= FrostFsObjectId.FromHash(_splitInfo.Link.Value.Span); + public FrostFsObjectId? Link => _link ??= _splitInfo.Link == null + ? null : FrostFsObjectId.FromHash(_splitInfo.Link.Value.Span); - public FrostFsObjectId LastPart => _lastPart ??= FrostFsObjectId.FromHash(_splitInfo.LastPart.Value.Span); + public FrostFsObjectId? LastPart => _lastPart ??= _splitInfo.LastPart == null + ? null : FrostFsObjectId.FromHash(_splitInfo.LastPart.Value.Span); } diff --git a/src/FrostFS.SDK.Client/Pool/Pool.cs b/src/FrostFS.SDK.Client/Pool/Pool.cs index b4bb357..3abfe60 100644 --- a/src/FrostFS.SDK.Client/Pool/Pool.cs +++ b/src/FrostFS.SDK.Client/Pool/Pool.cs @@ -39,6 +39,8 @@ public partial class Pool : IFrostFSClient private OwnerID? _ownerId; + private FrostFsVersion _version; + private FrostFsOwner? _owner; private FrostFsOwner Owner @@ -94,6 +96,8 @@ public partial class Pool : IFrostFSClient throw new ArgumentException($"Missed required parameter {nameof(options.Key)}"); } + _version = new FrostFsVersion(2, 13); + var nodesParams = AdjustNodeParams(options.NodeParams); var cache = new SessionCache(options.SessionExpirationDuration); diff --git a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs index 8561b50..246c3eb 100644 --- a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs +++ b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs @@ -268,7 +268,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl internal async Task PutSingleObjectAsync(PrmSingleObjectPut args, CallContext ctx) { - var grpcObject = ObjectTools.CreateObject(args.FrostFsObject, ClientContext); + var grpcObject = ObjectTools.CreateSingleObject(args.FrostFsObject, ClientContext); var request = new PutSingleRequest { @@ -565,7 +565,7 @@ internal sealed class ObjectServiceProvider(ObjectService.ObjectServiceClient cl if (header.Split != null) { - ObjectTools.SetSplitValues(grpcHeader, header.Split, ClientContext); + ObjectTools.SetSplitValues(grpcHeader, header.Split, ClientContext.Owner, ClientContext.Version, ClientContext.Key); } var oid = new ObjectID { Value = grpcHeader.Sha256() }; diff --git a/src/FrostFS.SDK.Client/Tools/ObjectTools.cs b/src/FrostFS.SDK.Client/Tools/ObjectTools.cs index 58f9f30..36a22a1 100644 --- a/src/FrostFS.SDK.Client/Tools/ObjectTools.cs +++ b/src/FrostFS.SDK.Client/Tools/ObjectTools.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using FrostFS.Object; @@ -9,9 +10,44 @@ using Google.Protobuf; namespace FrostFS.SDK.Client; -internal static class ObjectTools +public static class ObjectTools { - internal static Object.Object CreateObject(FrostFsObject @object, ClientContext ctx) + public static FrostFsObjectId CalculateObjectId( + FrostFsObjectHeader header, + ReadOnlyMemory payloadHash, + FrostFsOwner owner, + FrostFsVersion version, + ClientKey key) + { + if (header is null) + { + throw new ArgumentNullException(nameof(header)); + } + + if (owner is null) + { + throw new ArgumentNullException(nameof(owner)); + } + + if (version is null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (key is null) + { + throw new ArgumentNullException(nameof(key)); + } + + var grpcHeader = CreateHeader(header, payloadHash, owner, version); + + if (header.Split != null) + SetSplitValues(grpcHeader, header.Split, owner, version, key); + + return new ObjectID { Value = grpcHeader.Sha256() }.ToModel(); + } + + internal static Object.Object CreateSingleObject(FrostFsObject @object, ClientContext ctx) { @object.Header.OwnerId ??= ctx.Owner; @object.Header.Version ??= ctx.Version; @@ -24,7 +60,7 @@ internal static class ObjectTools var split = @object.Header.Split; if (split != null) { - SetSplitValues(grpcHeader, split, ctx); + SetSplitValues(grpcHeader, split, ctx.Owner, ctx.Version, ctx.Key); } var obj = new Object.Object @@ -43,13 +79,18 @@ internal static class ObjectTools return obj; } - internal static void SetSplitValues(Header grpcHeader, FrostFsSplit split, ClientContext ctx) + internal static void SetSplitValues( + Header grpcHeader, + FrostFsSplit split, + FrostFsOwner owner, + FrostFsVersion version, + ClientKey key) { if (split == null) return; - if (ctx.Key == null) - throw new FrostFsInvalidObjectException(nameof(ctx.Key)); + if (key == null) + throw new FrostFsInvalidObjectException(nameof(key)); grpcHeader.Split = new Header.Types.Split { @@ -61,30 +102,33 @@ internal static class ObjectTools if (split.ParentHeader is not null) { - var grpcParentHeader = CreateHeader(split.ParentHeader, [], ctx); + var grpcParentHeader = CreateHeader(split.ParentHeader, Array.Empty().Sha256(), owner, version); grpcHeader.Split.Parent = new ObjectID { Value = grpcParentHeader.Sha256() }; grpcHeader.Split.ParentHeader = grpcParentHeader; grpcHeader.Split.ParentSignature = new Signature { - Key = ctx.Key.PublicKeyProto, - Sign = ctx.Key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray()), + Key = key.PublicKeyProto, + Sign = key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray()), }; } grpcHeader.Split.Previous = split.Previous?.ToMessage(); } - internal static Header CreateHeader(FrostFsObjectHeader header, byte[]? payload, ClientContext ctx) + internal static Header CreateHeader( + FrostFsObjectHeader header, + ReadOnlyMemory payloadChecksum, + FrostFsOwner owner, + FrostFsVersion version) { - header.OwnerId ??= ctx.Owner; - header.Version ??= ctx.Version; + header.OwnerId ??= owner; + header.Version ??= version; var grpcHeader = header.GetHeader(); - if (payload != null) // && payload.Length > 0 - grpcHeader.PayloadHash = Sha256Checksum(payload); - + grpcHeader.PayloadHash = ChecksumFromSha256(payloadChecksum); + return grpcHeader; } @@ -96,4 +140,13 @@ internal static class ObjectTools Sum = ByteString.CopyFrom(data.Sha256()) }; } + + internal static Checksum ChecksumFromSha256(ReadOnlyMemory dataHash) + { + return new Checksum + { + Type = ChecksumType.Sha256, + Sum = UnsafeByteOperations.UnsafeWrap(dataHash) + }; + } } \ No newline at end of file