diff --git a/Program.cs b/Program.cs index f72cfca..0840334 100644 --- a/Program.cs +++ b/Program.cs @@ -1,220 +1,338 @@ -using System.Diagnostics; +using System; +using System.Collections; +using System.Collections.ObjectModel; +using System.Drawing; +using System.IO; -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; +using Frostfs.V2.Ape; -try +using FrostFS.Refs; +using FrostFS.SDK; +using FrostFS.SDK.Client; +using FrostFS.SDK.Client.Interfaces; + +using Grpc.Core; +using Grpc.Net.Client; + +using Microsoft.Extensions.Options; + +using Org.BouncyCastle.Utilities; + +using static FrostFS.Object.PatchRequest.Types.Body.Types; + + +class Demo { - var fsClient = Client.GetInstance("KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq", "http://172.29.238.97:8080"); + private const string Key = "KzPXA6669m2pf18XmUdoR8MnP1pi1PMmefiFujStVFnv7WR5SRmK"; + private const string Host = "http://172.23.32.4:8080"; - await FetchAndRemoveContainers(fsClient); - - ContainerId containerId = await CreateContainer(fsClient); - - ShowFileInExplorer(); - - var fileName = "cat.jpg"; - //var fileName = "fat_cat.bmp"; - - var objectId = await PutObject(fsClient, containerId, fileName); - //var objectId = await PutSingleObject(fsClient, containerId, fileName); - //var objectId = await PutObjectClientCut(fsClient, containerId, fileName); - - var filter = new ObjectFilter(ObjectMatchType.Equals, "fileName", fileName); - await foreach (var objId in fsClient.SearchObjectsAsync(containerId, filter)) + static void Main(string[] args) { - await GetObjectInfo(fsClient, containerId, objId); - } - - var @object = await fsClient.GetObjectAsync(containerId, objectId!); - - File.WriteAllBytes(GetBroFileName(fileName), @object.Payload); - await foreach (var cid in fsClient.ListContainersAsync()) - { - Console.WriteLine($"ContainerId: {cid} (removing...)"); - await fsClient.DeleteContainerAsync(cid); } - await Task.Delay(500); - - await foreach (var cid in fsClient.ListContainersAsync()) + #region Network + public static async Task GetNetmapSnapshotAsync() { - Console.WriteLine($"Container {cid} still alive!"); - } -} -catch (Exception ex) -{ - Console.WriteLine($"Error: {ex.Message}"); -} + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); -static async Task FetchAndRemoveContainers(IFrostFSClient fsClient) -{ - Console.WriteLine("Existing containers:"); + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); - await foreach (var cid in fsClient.ListContainersAsync()) - { - await fsClient.DeleteContainerAsync(cid); - Console.WriteLine($"Removed container: {cid}"); - } -} - -static async Task CreateContainer(IFrostFSClient fsClient) -{ - var placementPolicy = new PlacementPolicy(true, new Replica(1)); - - var containerId = await fsClient.CreateContainerAsync(new Container(BasicAcl.PublicRW, placementPolicy)); - Console.WriteLine($"Created container: {containerId}"); - - Container? container = null; - while (container is null) - { - try - { - await Task.Delay(1000); - container = await fsClient.GetContainerAsync(containerId); - } - catch - { - Console.WriteLine("Waiting for the container is ready. Some time is required"); - } + return await client.GetNetmapSnapshotAsync(default); } - return containerId; -} - -static async Task PutObject(IFrostFSClient fsClient, ContainerId containerId, string fileName) -{ - var fileStream = File.OpenRead(fileName); - - var header = new ObjectHeader( - containerId: containerId, - type: ObjectType.Regular, - new ObjectAttribute("fileName", fileName) - ); - - return await fsClient.PutObjectAsync(header, fileStream); -} - -static async Task PutSingleObject(IFrostFSClient fsClient, ContainerId containerId, string fileName) -{ - var bytes = File.ReadAllBytes(fileName); - - var obj = new FrostFS.SDK.ModelsV2.Object(containerId, bytes) - .AddAttribute("Filename", fileName); - - var objectId = await fsClient.PutSingleObjectAsync(obj); - - return objectId; -} - -static async Task GetObjectInfo(IFrostFSClient fsClient, ContainerId containerId, ObjectId objectId) -{ - Console.WriteLine("--------------------------------------------------"); - Console.WriteLine($"Object ID: {objectId}"); - - var objHeader = await fsClient.GetObjectHeadAsync(containerId, objectId); - - Console.WriteLine($"size: {objHeader.PayloadLength}"); - - if (objHeader.Split?.SplitId != null) - Console.WriteLine($"splitID: { objHeader.Split?.SplitId}"); - - if (objHeader.Split?.Parent != null) - Console.WriteLine($"parent: {objHeader.Split?.Parent}"); - - if (objHeader.Split?.Previous != null) - Console.WriteLine($"previous: {objHeader.Split?.Previous}"); - - Console.WriteLine($"Attributes:"); - foreach (var attribute in objHeader.Attributes) + public static async Task GetNodeInfoAsync() { - Console.WriteLine($"\t{attribute.Key} = {attribute.Value}"); + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + return await client.GetNodeInfoAsync(default); } - if (objHeader.Split?.Children?.FirstOrDefault() != null) + + public static async Task GetNetworkSettingsAsync() { - Console.WriteLine($"Children:"); - objHeader.Split?.Children.ForEach(x => Console.WriteLine(x.Value)); + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + return await client.GetNetworkSettingsAsync(default); } -} + #endregion -static async Task PutObjectClientCut(IFrostFSClient fsClient, ContainerId containerId, string fileName) -{ - List sentObjectIds = []; - FrostFS.SDK.ModelsV2.Object? currentObject; - - var partSize = 1024 * 1024; - var buffer = new byte[partSize]; - - 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) + #region Session + public static async Task GetSessionTokenAsync() { - var bytesCount = await stream.ReadAsync(buffer.AsMemory(0, partSize)); + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); - split.Previous = sentObjectIds.LastOrDefault(); + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); - largeObject.AppendBlock(buffer, bytesCount); - currentObject = new FrostFS.SDK.ModelsV2.Object(containerId, bytesCount < partSize ? buffer.Take(bytesCount).ToArray() : buffer) - .AddAttribute(fileNameAttribute) - .AddAttribute("type", $"part_{sentObjectIds.Count}") - .SetSplit(split); - - if (largeObject.PayloadLength == fullLength) - break; - - var objectId = await fsClient.PutSingleObjectAsync(currentObject); - sentObjectIds.Add(objectId); + return await client.CreateSessionAsync(new PrmSessionCreate(int.MaxValue), default); } + #endregion - if (sentObjectIds.Any()) + #region Chain + public static async Task> AddChainAsync(string targetString, string name, byte[] raw) { - largeObject.CalculateHash() - .AddAttribute("type", $"ParentObject") - .AddAttribute(fileNameAttribute); + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); - currentObject.SetParent(largeObject); - - var objectId = await fsClient.PutSingleObjectAsync(currentObject); - sentObjectIds.Add(objectId); + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); - var linkObject = new LinkObject(containerId, split.SplitId, largeObject) - .AddChildren(sentObjectIds) - .AddAttribute(fileNameAttribute) - .AddAttribute("type", $"LinkedObject"); + var target = new FrostFsChainTarget(Enum.Parse(targetString), name); - _ = await fsClient.PutSingleObjectAsync(linkObject); + var chain = new FrostFsChain(raw); - //return fsClient.CalculateObjectId(largeObject.Header); + var args = new PrmApeChainAdd(target, chain); - return currentObject.GetParentId(); + return await client.AddChainAsync(args, default); } - return await fsClient.PutSingleObjectAsync(currentObject); + public static async Task RemoveChainAsync(string targetString, string name, byte[] raw) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var target = new FrostFsChainTarget(Enum.Parse(targetString), name); + + var chain = new FrostFsChain(raw); + + var args = new PrmApeChainRemove(target, chain); + + await client.RemoveChainAsync(args, default); + } + + + public static async Task RemoveChainAsync(string targetString, string name) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var target = new FrostFsChainTarget(Enum.Parse(targetString), name); + + var args = new PrmApeChainList(target); + + await client.ListChainAsync(args, default); + } + #endregion + + #region Container + public static async Task CreateContainerAsync() + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var createContainerParam = new PrmContainerCreate( + new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1))), + PrmWait.DefaultParams); + + return await client.CreateContainerAsync(createContainerParam, default); + } + + public static async Task GetContainerAsync() + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var createContainerParam = new PrmContainerCreate( + new FrostFsContainerInfo(new FrostFsPlacementPolicy(true, new FrostFsReplica(1))), + PrmWait.DefaultParams); + + return await client.CreateContainerAsync(createContainerParam, default); + } + + public static async Task DeleteContainerAsync(FrostFsContainerId containerId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmContainerDelete(containerId, new PrmWait(60, 5)); + + await client.DeleteContainerAsync(args, default); + } + + public static async Task> ListContainersAsync(FrostFsContainerId containerId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmContainerGetAll(); + + Collection containers = []; + await foreach (var cid in client.ListContainersAsync(args, default)) + { + containers.Add(cid); + } + + return containers; + } + #endregion + + #region Object + public static async Task GetObjectHeadAsync(FrostFsContainerId containerId, FrostFsObjectId objectId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmObjectHeadGet(containerId, objectId); + + return await client.GetObjectHeadAsync(args, default); + } + + public static async Task GetObjectAsync(FrostFsContainerId containerId, FrostFsObjectId objectId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmObjectGet(containerId, objectId); + + return await client.GetObjectAsync(args, default); + } + + public static async Task GetRangeAsync(FrostFsContainerId containerId, FrostFsObjectId objectId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmRangeGet(containerId, objectId, new FrostFsRange(64, 128)); + + var rangeReader = await client.GetRangeAsync(args, default); + + var downloadedBytes = new byte[128]; + MemoryStream ms = new(downloadedBytes); + + ReadOnlyMemory? chunk; + while ((chunk = await rangeReader!.ReadChunk()) != null) + { + ms.Write(chunk.Value.Span); + } + + return downloadedBytes; + } + + public static async Task[]> GetRangeHashAsync(FrostFsContainerId containerId, FrostFsObjectId objectId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + Random rnd = new(); + var salt = new byte[32]; + rnd.NextBytes(salt); + + var args = new PrmRangeHashGet(containerId, objectId, [new FrostFsRange(100, 64)], salt); + + return await client.GetRangeHashAsync(args, default); + } + + public static async Task PutObjectAsync(FrostFsContainerId containerId, byte[] bytes) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmObjectPut( + new FrostFsObjectHeader( + containerId: containerId, + type: FrostFsObjectType.Regular, + [new FrostFsAttributePair("fileName", "test")])); + + var stream = await client.PutObjectAsync(args, default); + + await stream.WriteAsync(bytes.AsMemory()); + var objectId = await stream.CompleteAsync(); + + return objectId; + } + + public static async Task PutSingleObjectAsync(FrostFsObject obj) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmSingleObjectPut(obj); + + return await client.PutSingleObjectAsync(args, default); + } + + public static async Task PatchObjectAsync(FrostFsContainerId containerId, FrostFsObjectId objectId, byte[] patch) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var range = new FrostFsRange(64, (ulong)patch.Length); + + var args = new PrmObjectPatch( + new FrostFsAddress(containerId, objectId), + payload: new MemoryStream(patch), + maxChunkLength: 256, + range: range); + + return await client.PatchObjectAsync(args, default); + } + + public static async Task DeleteObjectAsync(FrostFsContainerId containerId, FrostFsObjectId objectId, byte[] patch) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var args = new PrmObjectDelete(containerId, objectId); + + await client.DeleteObjectAsync(args, default); + } + + public static async Task> SearchObjectsAsync(FrostFsContainerId containerId) + { + var clientOptions = Options.Create(new ClientSettings { Key = Key, Host = Host }); + Func grpcChannel = (url) => GrpcChannel.ForAddress(new Uri(url)); + + var client = FrostFSClient.GetInstance(clientOptions, grpcChannel); + + var filter = new FilterByAttributePair(FrostFsMatchType.Equals, "fileName", "test"); + + var args = new PrmObjectSearch(containerId, null, [], filter); + + Collection objects = []; + await foreach (var objId in client.SearchObjectsAsync(args, default)) + { + objects.Add(objId); + } + + return objects; + } + #endregion } -static void ShowFileInExplorer() -{ - Directory.SetCurrentDirectory(@"C:\Users\p.gross\Pictures\samples"); - var currentDir = Directory.GetCurrentDirectory(); - Process.Start("explorer.exe", currentDir); -} -static string GetBroFileName(string path) -{ - var newName = Path.GetFileNameWithoutExtension(path) + "_bro" + Path.GetExtension(path); - return newName; -} \ No newline at end of file diff --git a/client.csproj b/client.csproj index afc4e32..551acc1 100644 --- a/client.csproj +++ b/client.csproj @@ -9,16 +9,9 @@ - - netstandard2.0\FrostFS.SDK.ClientV2.dll - - - - netstandard2.0\FrostFS.SDK.ModelsV2.dll - - - - + + + @@ -26,4 +19,13 @@ + + + ..\frostfs-sdk-csharp\src\FrostFS.SDK.Client\bin\Debug\netstandard2.0\FrostFS.SDK.Client.dll + + + ..\frostfs-sdk-csharp\src\FrostFS.SDK.Client\bin\Debug\netstandard2.0\FrostFS.SDK.Protos.dll + + + \ No newline at end of file