frostfs-sdk-csharp/src/FrostFS.SDK.Client/Tools/ObjectTools.cs
Pavel Gross 87fe8db674
All checks were successful
DCO / DCO (pull_request) Successful in 21s
lint-build / dotnet8.0 (pull_request) Successful in 35s
lint-build / dotnet8.0 (push) Successful in 34s
/ Publish NuGet packages (push) Successful in 48s
[#43] Client: Memory optimization
Signed-off-by: Pavel Gross <p.gross@yadro.com>
2025-03-31 11:40:04 +03:00

171 lines
4.7 KiB
C#

using System;
using System.Linq;
using System.Security.Cryptography;
using FrostFS.Object;
using FrostFS.Refs;
using FrostFS.SDK.Client.Mappers.GRPC;
using FrostFS.SDK.Cryptography;
using Google.Protobuf;
namespace FrostFS.SDK.Client;
public static class ObjectTools
{
public static FrostFsObjectId CalculateObjectId(
FrostFsObjectHeader header,
ReadOnlyMemory<byte> 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);
using var sha256 = SHA256.Create();
using HashStream stream = new(sha256);
grpcHeader.WriteTo(stream);
return new FrostFsObjectId(Base58.Encode(stream.Hash()));
}
internal static Object.Object CreateSingleObject(FrostFsObject @object, ClientContext ctx)
{
@object.Header.OwnerId ??= ctx.Owner;
@object.Header.Version ??= ctx.Version;
var grpcHeader = @object.Header.GetHeader();
grpcHeader.PayloadLength = (ulong)@object.SingleObjectPayload.Length;
if (@object.PayloadHash != null)
{
grpcHeader.PayloadHash = ChecksumFromSha256(@object.PayloadHash);
}
else
{
grpcHeader.PayloadHash = Sha256Checksum(@object.SingleObjectPayload);
}
var split = @object.Header.Split;
if (split != null)
{
SetSplitValues(grpcHeader, split, ctx.Owner, ctx.Version, ctx.Key);
}
var obj = new Object.Object
{
Header = grpcHeader,
ObjectId = new ObjectID { Value = UnsafeByteOperations.UnsafeWrap(grpcHeader.Sha256()) },
Payload = UnsafeByteOperations.UnsafeWrap(@object.SingleObjectPayload)
};
obj.Signature = new Signature
{
Key = ctx.Key.PublicKeyProto,
Sign = ctx.Key.ECDsaKey.SignData(obj.ObjectId.ToByteArray()),
};
return obj;
}
internal static void SetSplitValues(
Header grpcHeader,
FrostFsSplit split,
FrostFsOwner owner,
FrostFsVersion version,
ClientKey key)
{
if (split == null)
{
return;
}
if (key == null)
{
throw new FrostFsInvalidObjectException(nameof(key));
}
grpcHeader.Split = new Header.Types.Split
{
SplitId = split.SplitId?.GetSplitId()
};
if (split.Children != null && split.Children.Count != 0)
{
grpcHeader.Split.Children.AddRange(split.Children.Select(id => id.ToMessage()));
}
if (split.ParentHeader is not null)
{
var grpcParentHeader = CreateHeader(split.ParentHeader, DataHasher.Sha256([]), owner, version);
grpcHeader.Split.Parent = new ObjectID { Value = UnsafeByteOperations.UnsafeWrap(grpcParentHeader.Sha256()) };
grpcHeader.Split.ParentHeader = grpcParentHeader;
grpcHeader.Split.ParentSignature = new Signature
{
Key = key.PublicKeyProto,
Sign = key.ECDsaKey.SignData(grpcHeader.Split.Parent.ToByteArray()),
};
}
grpcHeader.Split.Previous = split.Previous?.ToMessage();
}
internal static Header CreateHeader(
FrostFsObjectHeader header,
ReadOnlyMemory<byte> payloadChecksum,
FrostFsOwner owner,
FrostFsVersion version)
{
header.OwnerId ??= owner;
header.Version ??= version;
var grpcHeader = header.GetHeader();
grpcHeader.PayloadHash = ChecksumFromSha256(payloadChecksum);
return grpcHeader;
}
internal static Checksum Sha256Checksum(ReadOnlyMemory<byte> data)
{
return new Checksum
{
Type = ChecksumType.Sha256,
Sum = UnsafeByteOperations.UnsafeWrap(DataHasher.Sha256(data))
};
}
internal static Checksum ChecksumFromSha256(ReadOnlyMemory<byte> dataHash)
{
return new Checksum
{
Type = ChecksumType.Sha256,
Sum = UnsafeByteOperations.UnsafeWrap(dataHash)
};
}
}