diff --git a/src/FrostFS.SDK.Client/FrostFSClient.cs b/src/FrostFS.SDK.Client/FrostFSClient.cs index eea24fc..9135f27 100644 --- a/src/FrostFS.SDK.Client/FrostFSClient.cs +++ b/src/FrostFS.SDK.Client/FrostFSClient.cs @@ -290,6 +290,14 @@ public class FrostFSClient : IFrostFSClient { return GetObjectService().SearchObjectsAsync(args, ctx); } + + public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header) + { + if (header == null) + throw new ArgumentNullException(nameof(header)); + + return ObjectTools.CalculateObjectId(header, ClientCtx.Owner, ClientCtx.Version, ClientCtx.Key); + } #endregion #region Session Implementation diff --git a/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs b/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs index cce7364..160e4e0 100644 --- a/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs +++ b/src/FrostFS.SDK.Client/Interfaces/IFrostFSClient.cs @@ -65,4 +65,6 @@ public interface IFrostFSClient #endregion public Task Dial(CallContext ctx); + + FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header); } 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..56ac3bf 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); @@ -642,6 +646,14 @@ public partial class Pool : IFrostFSClient return client.Client!.SearchObjectsAsync(args, ctx); } + public FrostFsObjectId CalculateObjectId(FrostFsObjectHeader header) + { + if (header == null) + throw new ArgumentNullException(nameof(header)); + + return ObjectTools.CalculateObjectId(header, Owner, _version, Key); + } + public async Task GetBalanceAsync(CallContext ctx) { var client = Connection(); diff --git a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs index 8561b50..133d2e3 100644 --- a/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs +++ b/src/FrostFS.SDK.Client/Services/ObjectServiceProvider.cs @@ -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..fdc9a23 100644 --- a/src/FrostFS.SDK.Client/Tools/ObjectTools.cs +++ b/src/FrostFS.SDK.Client/Tools/ObjectTools.cs @@ -11,6 +11,20 @@ namespace FrostFS.SDK.Client; internal static class ObjectTools { + internal static FrostFsObjectId CalculateObjectId( + FrostFsObjectHeader header, + FrostFsOwner owner, + FrostFsVersion version, + ClientKey key) + { + var grpcHeader = CreateHeader(header, [], owner, version); + + if (header.Split != null) + SetSplitValues(grpcHeader, header.Split, owner, version, key); + + return new ObjectID { Value = grpcHeader.Sha256() }.ToModel(); + } + internal static Object.Object CreateObject(FrostFsObject @object, ClientContext ctx) { @object.Header.OwnerId ??= ctx.Owner; @@ -24,7 +38,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 +57,17 @@ 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,24 +79,24 @@ internal static class ObjectTools if (split.ParentHeader is not null) { - var grpcParentHeader = CreateHeader(split.ParentHeader, [], ctx); + var grpcParentHeader = CreateHeader(split.ParentHeader, [], 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, byte[]? payload, FrostFsOwner owner, FrostFsVersion version) { - header.OwnerId ??= ctx.Owner; - header.Version ??= ctx.Version; + header.OwnerId ??= owner; + header.Version ??= version; var grpcHeader = header.GetHeader();