using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
namespace RobotNet10.RobotApp.Hubs;
///
/// SignalR Hub for streaming XLOC pose data in realtime
/// AND controlling SLAM operations manually (start/stop localization/mapping)
///
public class XlocPoseHub : Hub
{
private readonly ILogger _logger;
private readonly Xloc.XlocIntegrationService? _xlocService;
public XlocPoseHub(ILogger logger, Xloc.XlocIntegrationService? xlocService = null)
{
_logger = logger;
_xlocService = xlocService;
}
public override async Task OnConnectedAsync()
{
_logger.LogInformation("Client connected to XlocPoseHub: {ConnectionId}", Context.ConnectionId);
await base.OnConnectedAsync();
}
public override async Task OnDisconnectedAsync(Exception? exception)
{
_logger.LogInformation("Client disconnected from XlocPoseHub: {ConnectionId}", Context.ConnectionId);
await base.OnDisconnectedAsync(exception);
}
///
/// Client requests current pose (on-demand)
///
public async Task RequestCurrentPose()
{
_logger.LogDebug("Client {ConnectionId} requested current pose", Context.ConnectionId);
await Task.CompletedTask;
}
#region Manual SLAM Control Methods
///
/// Activate a map for localization
///
public async Task ActivateMap(string mapFilePath)
{
if (_xlocService == null)
{
_logger.LogWarning("XlocIntegrationService not available");
return false;
}
_logger.LogInformation("Client {ConnectionId} activating map: {MapPath}", Context.ConnectionId, mapFilePath);
return _xlocService.ActivateMap(mapFilePath);
}
///
/// Start localization mode
///
public async Task StartLocalization()
{
if (_xlocService == null)
{
_logger.LogWarning("XlocIntegrationService not available");
return false;
}
_logger.LogInformation("Client {ConnectionId} starting localization", Context.ConnectionId);
return _xlocService.StartLocalization();
}
///
/// Stop localization mode
///
public async Task StopLocalization()
{
if (_xlocService == null)
{
_logger.LogWarning("XlocIntegrationService not available");
return false;
}
_logger.LogInformation("Client {ConnectionId} stopping localization", Context.ConnectionId);
return _xlocService.StopLocalization();
}
///
/// Start mapping mode
///
public async Task StartMapping()
{
if (_xlocService == null)
{
_logger.LogWarning("XlocIntegrationService not available");
return false;
}
_logger.LogInformation("Client {ConnectionId} starting mapping", Context.ConnectionId);
return _xlocService.StartMapping();
}
///
/// Stop mapping and save to file
///
public async Task StopMapping(string saveMapFilePath)
{
if (_xlocService == null)
{
_logger.LogWarning("XlocIntegrationService not available");
return false;
}
_logger.LogInformation("Client {ConnectionId} stopping mapping, saving to: {MapPath}",
Context.ConnectionId, saveMapFilePath);
return _xlocService.StopMapping(saveMapFilePath);
}
///
/// Get current 2D pose (x, y, yaw)
///
public async Task