using Microsoft.AspNetCore.SignalR.Client; namespace RobotNet10.Components.Clients; public abstract class HubClient { public event Func? ConnectionStateChanged; public bool IsConnected => Connection.State == HubConnectionState.Connected; protected HubConnection Connection { get; } private readonly ManualResetEvent connectedWaitHandler = new(false); protected HubClient(Uri url) { Connection = new HubConnectionBuilder() .WithUrl(url) .WithAutomaticReconnect(new HubClientRepeatRetryPolicy(TimeSpan.FromSeconds(3))) .Build(); Connection.Closed += Connection_Closed; Connection.Reconnected += Connection_Reconnected; } private Task Connection_Closed(Exception? arg) { return ConnectionStateChanged?.Invoke(Connection.State) ?? Task.CompletedTask; } private Task Connection_Reconnected(string? arg) { return ConnectionStateChanged?.Invoke(Connection.State) ?? Task.CompletedTask; } public virtual async Task StartAsync() { if (Connection.State == HubConnectionState.Disconnected) { await Connection.StartAsync(); ConnectionStateChanged?.Invoke(Connection.State); connectedWaitHandler.Set(); } } public void WaitForConnected() => connectedWaitHandler.WaitOne(); public virtual async Task StopAsync() { if (Connection.State != HubConnectionState.Disconnected) { await Connection.StopAsync(); ConnectionStateChanged?.Invoke(Connection.State); } } public class HubClientRepeatRetryPolicy(TimeSpan repeatSpan) : IRetryPolicy { private readonly TimeSpan RepeatTimeSpan = repeatSpan; public TimeSpan? NextRetryDelay(RetryContext retryContext) => RepeatTimeSpan; } }