using System.Threading.Tasks; using FrostFS.SDK.ClientV2.Mappers.GRPC.Netmap; using FrostFS.Container; using FrostFS.SDK.ClientV2.Mappers.GRPC; using FrostFS.SDK.Cryptography; using System.Collections.Generic; using FrostFS.SDK.ModelsV2; using FrostFS.Refs; using System; using FrostFS.SDK.ClientV2.Parameters; using System.Collections.Specialized; namespace FrostFS.SDK.ClientV2; internal class ContainerServiceProvider : ContextAccessor { private readonly ContainerService.ContainerServiceClient containerServiceClient; internal ContainerServiceProvider(ContainerService.ContainerServiceClient service, ClientEnvironment context) : base(context) { containerServiceClient = service; } internal async Task GetContainerAsync(PrmContainerGet args) { GetRequest request = GetContainerRequest(args.ContainerId.ToGrpcMessage(), args.XHeaders); var response = await containerServiceClient.GetAsync(request, null, args.Context!.Deadline, args.Context.CancellationToken); Verifier.CheckResponse(response); return response.Body.Container.ToModel(); } internal async IAsyncEnumerable ListContainersAsync(PrmContainerGetAll args) { var ctx = args.Context!; var request = new ListRequest { Body = new ListRequest.Types.Body { OwnerId = Context.Owner.ToGrpcMessage() } }; request.AddMetaHeader(args.XHeaders); request.Sign(Context.Key); var response = await containerServiceClient.ListAsync(request, null, ctx.Deadline, ctx.CancellationToken); Verifier.CheckResponse(response); foreach (var cid in response.Body.ContainerIds) { yield return new ContainerId(Base58.Encode(cid.Value.ToByteArray())); } } internal async Task CreateContainerAsync(PrmContainerCreate args) { var ctx = args.Context!; var grpcContainer = args.Container.ToGrpcMessage(); grpcContainer.OwnerId = Context.Owner.ToGrpcMessage(); grpcContainer.Version = Context.Version.ToGrpcMessage(); var request = new PutRequest { Body = new PutRequest.Types.Body { Container = grpcContainer, Signature = Context.Key.SignRFC6979(grpcContainer) } }; request.AddMetaHeader(args.XHeaders); request.Sign(Context.Key); var response = await containerServiceClient.PutAsync(request, null, ctx.Deadline, ctx.CancellationToken); Verifier.CheckResponse(response); await WaitForContainer(WaitExpects.Exists, response.Body.ContainerId, args.WaitParams, ctx); return new ContainerId(Base58.Encode(response.Body.ContainerId.Value.ToByteArray())); } internal async Task DeleteContainerAsync(PrmContainerDelete args) { var ctx = args.Context!; var request = new DeleteRequest { Body = new DeleteRequest.Types.Body { ContainerId = args.ContainerId.ToGrpcMessage(), Signature = Context.Key.SignRFC6979(args.ContainerId.ToGrpcMessage().Value) } }; request.AddMetaHeader(args.XHeaders); request.Sign(Context.Key); var response = await containerServiceClient.DeleteAsync(request, null, ctx.Deadline, ctx.CancellationToken); await WaitForContainer(WaitExpects.Removed, request.Body.ContainerId, args.WaitParams, ctx); Verifier.CheckResponse(response); } private GetRequest GetContainerRequest(ContainerID id, NameValueCollection? xHeaders) { var request = new GetRequest { Body = new GetRequest.Types.Body { ContainerId = id } }; request.AddMetaHeader(xHeaders); request.Sign(Context.Key); return request; } private enum WaitExpects { Exists, Removed } private async Task WaitForContainer(WaitExpects expect, ContainerID id, PrmWait? waitParams, Context ctx) { var request = GetContainerRequest(id, null); async Task action() { var response = await containerServiceClient.GetAsync(request, null, ctx.Deadline, ctx.CancellationToken); Verifier.CheckResponse(response); } await WaitFor(action, expect, waitParams); } private static async Task WaitFor( Func action, WaitExpects expect, PrmWait? waitParams) { waitParams ??= PrmWait.DefaultParams; var deadLine = waitParams.GetDeadline(); while (true) { try { await action(); if (expect == WaitExpects.Exists) return; await Task.Delay(waitParams.PollInterval); } catch (ResponseException ex) { if (DateTime.UtcNow >= deadLine) throw new TimeoutException(); if (ex.Status.Code != ModelsV2.Enums.StatusCode.ContainerNotFound) throw; if (expect == WaitExpects.Removed) return; await Task.Delay(waitParams.PollInterval); } } } }