using System.Security.Cryptography; using Grpc.Net.Client; using FrostFS.SDK.ModelsV2; using System; using System.Threading.Tasks; using Grpc.Core; using System.Diagnostics; namespace FrostFS.SDK.ClientV2; public class ClientEnvironment(ECDsa key, OwnerId owner, GrpcChannel channel, ModelsV2.Version version) : IDisposable { internal OwnerId Owner { get; } = owner; internal GrpcChannel Channel { get; private set; } = channel; internal ECDsa Key { get; } = key; internal ModelsV2.Version Version { get; } = version; internal NetworkSettings? NetworkSettings { get; set; } internal ContainerServiceProvider? ContainerService { get; set; } internal NetmapServiceProvider? NetmapService { get; set; } internal SessionServiceProvider? SessionService { get; set; } internal ObjectServiceProvider? ObjectService { get; set; } internal event EventHandler? GrpcInvokedEvent; internal bool IsEventRequested => GrpcInvokedEvent != null; internal async Task InvokeAsyncWithMetrics(Func> func, string methodName) { if (!IsEventRequested) return await func(); var watch = Stopwatch.StartNew(); bool exitWithException = false; try { return await func(); } catch { exitWithException = true; throw; } finally { watch.Stop(); GrpcInvokedEvent?.Invoke(this, new GrpcCallInfo(methodName, watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency, exitWithException)); } } internal T InvokeWithMetrics(Func func, string methodName) { if (!IsEventRequested) return func(); var watch = Stopwatch.StartNew(); bool exitWithException = false; try { return func(); } catch { exitWithException = true; throw; } finally { watch.Stop(); GrpcInvokedEvent?.Invoke(this, new GrpcCallInfo(methodName, watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency, exitWithException)); } } internal async Task InvokeAsyncUnaryWithMetrics(Func> func, string methodName) { if (!IsEventRequested) return await func(); var watch = Stopwatch.StartNew(); bool exitWithException = false; try { return await func(); } catch { exitWithException = true; throw; } finally { watch.Stop(); GrpcInvokedEvent?.Invoke(this, new GrpcCallInfo(methodName, watch.ElapsedTicks * 1_000_000 / Stopwatch.Frequency, exitWithException)); } } internal bool Initialized => ContainerService != null && NetmapService != null && SessionService != null && ObjectService != null; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (disposing) { Channel.Dispose(); } } }