using Microsoft.AspNetCore.SignalR.Client; namespace RobotNet.Clients; public abstract class HubClient { public event Action? ConnectionStateChanged; public bool IsConnected => Connection.State == HubConnectionState.Connected; protected HubConnection Connection { get; } protected HubClient(Uri url, Func> accessTokenProvider) { Connection = new HubConnectionBuilder() .WithUrl(url, options => { options.AccessTokenProvider = accessTokenProvider; }) .WithAutomaticReconnect(new HubClientRepeatRetryPolicy(TimeSpan.FromSeconds(3))) .Build(); Connection.Closed += Connection_Closed; Connection.Reconnected += Connection_Reconnected; } private Task Connection_Closed(Exception? arg) { ConnectionStateChanged?.Invoke(Connection.State); return Task.CompletedTask; } private Task Connection_Reconnected(string? arg) { ConnectionStateChanged?.Invoke(Connection.State); return Task.CompletedTask; } public virtual async Task StartAsync() { if (Connection.State == HubConnectionState.Disconnected) { await Connection.StartAsync(); ConnectionStateChanged?.Invoke(Connection.State); } } 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; } }