using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using RobotNet10.NavigationTune.Shared.Hubs;
using RobotNet10.NavigationTune.Shared.Interfaces;
namespace RobotNet10.NavigationTuneUI.Clients;
///
/// SignalR client for Tuning Hub
///
public class TuningHubClient : IAsyncDisposable
{
private readonly HubConnection _hubConnection;
private bool _disposed;
public bool IsConnected => _hubConnection.State == HubConnectionState.Connected;
public HubConnectionState ConnectionState => _hubConnection.State;
// Events
public event Action? TelemetryUpdated;
public event Action? TestStatusUpdated;
public event Action? SafetyEventReceived;
public event Action? TestResultReceived;
public event Action? ConnectionStateChanged;
public TuningHubClient(NavigationManager navigationManager)
{
var hubUrl = navigationManager.ToAbsoluteUri("/tuninghub");
_hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.AddJsonProtocol(options =>
{
options.PayloadSerializerOptions.NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals;
})
.WithAutomaticReconnect()
.Build();
// Subscribe to server messages
_hubConnection.On("ReceiveTelemetry", dto => TelemetryUpdated?.Invoke(dto));
_hubConnection.On("ReceiveTestStatus", dto => TestStatusUpdated?.Invoke(dto));
_hubConnection.On("ReceiveSafetyEvent", dto => SafetyEventReceived?.Invoke(dto));
_hubConnection.On("ReceiveTestResult", result => TestResultReceived?.Invoke(result));
_hubConnection.Reconnecting += async (ex) =>
{
ConnectionStateChanged?.Invoke(_hubConnection.State);
await Task.CompletedTask;
};
_hubConnection.Reconnected += async (id) =>
{
ConnectionStateChanged?.Invoke(_hubConnection.State);
await Task.CompletedTask;
};
_hubConnection.Closed += async (ex) =>
{
ConnectionStateChanged?.Invoke(_hubConnection.State);
await Task.CompletedTask;
};
}
public async Task StartAsync()
{
if (_hubConnection.State == HubConnectionState.Disconnected)
{
await _hubConnection.StartAsync();
}
}
public async Task StopAsync()
{
if (_hubConnection.State != HubConnectionState.Disconnected)
{
await _hubConnection.StopAsync();
}
}
public async Task JoinTestSessionAsync(string testRunId)
{
await _hubConnection.InvokeAsync("JoinTestSession", testRunId);
}
public async Task LeaveTestSessionAsync(string testRunId)
{
await _hubConnection.InvokeAsync("LeaveTestSession", testRunId);
}
public async ValueTask DisposeAsync()
{
if (_disposed) return;
await StopAsync();
await _hubConnection.DisposeAsync();
_disposed = true;
}
}