using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; using dotnetCampus.Ipc.IpcRouteds.DirectRouteds; using dotnetCampus.Ipc.Pipes; namespace LanMountainDesktop.Shared.IPC; public sealed class LanMountainDesktopIpcClient : IDisposable { private const int ConnectRetryCount = 3; private const int ConnectRetryBaseDelayMs = 500; private bool _started; private bool _disposed; public LanMountainDesktopIpcClient(string? clientPipeName = null) { Provider = string.IsNullOrWhiteSpace(clientPipeName) ? new IpcProvider() : new IpcProvider(clientPipeName); RoutedProvider = new JsonIpcDirectRoutedProvider(Provider); } public IpcProvider Provider { get; } public JsonIpcDirectRoutedProvider RoutedProvider { get; } public PeerProxy? Peer { get; private set; } public bool IsConnected => Peer is not null && Peer.IsConnectedFinished; public async Task ConnectAsync(string pipeName = IpcConstants.DefaultPipeName) { EnsureStarted(); for (var attempt = 1; attempt <= ConnectRetryCount; attempt++) { try { Peer = await Provider.GetAndConnectToPeerAsync(pipeName).ConfigureAwait(false); return; } catch (Exception ex) when (attempt < ConnectRetryCount) { var delay = ConnectRetryBaseDelayMs * attempt + Random.Shared.Next(0, 200); await Task.Delay(delay).ConfigureAwait(false); } } Peer = await Provider.GetAndConnectToPeerAsync(pipeName).ConfigureAwait(false); } public void RegisterNotifyHandler(string notifyId, Action handler) where TPayload : class { ArgumentException.ThrowIfNullOrWhiteSpace(notifyId); ArgumentNullException.ThrowIfNull(handler); RoutedProvider.AddNotifyHandler(notifyId, handler); } public void RegisterNotifyHandler(string notifyId, Func handler) where TPayload : class { ArgumentException.ThrowIfNullOrWhiteSpace(notifyId); ArgumentNullException.ThrowIfNull(handler); RoutedProvider.AddNotifyHandler(notifyId, handler); } public TContract CreateProxy(string? objectId = null) where TContract : class { var peer = Peer ?? throw new InvalidOperationException("IPC client is not connected."); return Provider.CreateIpcProxy(peer, objectId); } public async Task GetCatalogAsync() { var client = await GetRoutedClientAsync().ConfigureAwait(false); return await client.GetResponseAsync(IpcConstants.Routes.CatalogGet) .ConfigureAwait(false); } public async Task GetSessionInfoAsync() { var client = await GetRoutedClientAsync().ConfigureAwait(false); return await client.GetResponseAsync(IpcConstants.Routes.SessionGetInfo) .ConfigureAwait(false); } private async Task GetRoutedClientAsync() { if (Peer is null) { throw new InvalidOperationException("IPC client is not connected."); } await Task.CompletedTask; return new JsonIpcDirectRoutedClientProxy(Peer); } private void EnsureStarted() { if (_started) { return; } RoutedProvider.StartServer(); _started = true; } public void Dispose() { if (_disposed) { return; } _disposed = true; Peer = null; Provider.Dispose(); } }