90 lines
3.2 KiB
C#
90 lines
3.2 KiB
C#
using Microsoft.AspNetCore.SignalR;
|
|
|
|
namespace RobotNet10.FleetManager.Hubs;
|
|
|
|
/// <summary>
|
|
/// SignalR Hub for real-time robot state and visualization updates.
|
|
/// Manages client subscriptions to robot groups for receiving VDA5050 messages.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Clients subscribe to specific robots using SubscribeToRobot method.
|
|
/// Messages are broadcast to groups named "robot:{robotId}".
|
|
/// </remarks>
|
|
public class RobotStateHub(
|
|
Services.Logger<RobotStateHub> logger,
|
|
RobotStateHubContext hubContext) : Hub
|
|
{
|
|
private readonly Services.Logger<RobotStateHub> _logger = logger;
|
|
private readonly RobotStateHubContext _hubContext = hubContext;
|
|
|
|
/// <summary>
|
|
/// Subscribe to receive updates for a specific robot
|
|
/// </summary>
|
|
/// <param name="robotId">Robot identifier (serialNumber)</param>
|
|
public async Task SubscribeToRobot(string robotId)
|
|
{
|
|
var groupName = GetGroupName(robotId);
|
|
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribe from updates for a specific robot
|
|
/// </summary>
|
|
/// <param name="robotId">Robot identifier (serialNumber)</param>
|
|
public async Task UnsubscribeFromRobot(string robotId)
|
|
{
|
|
var groupName = GetGroupName(robotId);
|
|
await Groups.RemoveFromGroupAsync(Context.ConnectionId, groupName);
|
|
}
|
|
|
|
private static string GetGroupName(string robotId)
|
|
{
|
|
return $"robot:{robotId}";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subscribe to receive monitor updates for a specific levelId
|
|
/// Each connection can only subscribe to one levelId at a time.
|
|
/// Maximum 5 connections per levelId (FIFO).
|
|
/// </summary>
|
|
/// <param name="levelId">Level identifier (LayoutLevel.Id)</param>
|
|
public async Task SubscribeToLevelForMonitor(Guid levelId)
|
|
{
|
|
var evictedConnectionId = _hubContext.SubscribeToLevel(Context.ConnectionId, levelId);
|
|
|
|
// If a connection was evicted, notify it
|
|
if (evictedConnectionId != null)
|
|
{
|
|
_logger.Info($"Connection {evictedConnectionId} evicted from level {levelId} (max 5 connections reached)");
|
|
await Clients.Client(evictedConnectionId).SendAsync("OnMonitorDeactivated");
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Unsubscribe from monitor updates for the current level
|
|
/// </summary>
|
|
public async Task UnsubscribeFromLevelForMonitor()
|
|
{
|
|
var removed = _hubContext.UnsubscribeFromLevel(Context.ConnectionId);
|
|
if (removed)
|
|
{
|
|
_logger.Info($"Client {Context.ConnectionId} unsubscribed from level for monitor");
|
|
}
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
public override async Task OnDisconnectedAsync(Exception? exception)
|
|
{
|
|
// Remove connection from subscription manager
|
|
_hubContext.RemoveConnection(Context.ConnectionId);
|
|
|
|
if (exception != null)
|
|
{
|
|
_logger.Warning($"Client {Context.ConnectionId} disconnected with error: {exception.Message}");
|
|
}
|
|
await base.OnDisconnectedAsync(exception);
|
|
}
|
|
}
|