using Microsoft.AspNetCore.SignalR; namespace AmtScanner.Api.Hubs; /// /// 屏幕流信令 Hub - 用于控制设备推流质量和状态 /// public class StreamSignalingHub : Hub { private readonly ILogger _logger; private static readonly Dictionary> _deviceWatchers = new(); private static readonly object _lock = new(); public StreamSignalingHub(ILogger logger) { _logger = logger; } /// /// 教师端开始监控(进入监控墙页面) /// public async Task StartMonitoring(List deviceUuids) { var connectionId = Context.ConnectionId; _logger.LogInformation("教师端 {ConnectionId} 开始监控 {Count} 台设备", connectionId, deviceUuids.Count); lock (_lock) { foreach (var uuid in deviceUuids) { if (!_deviceWatchers.ContainsKey(uuid)) { _deviceWatchers[uuid] = new HashSet(); } _deviceWatchers[uuid].Add(connectionId); } } // 通知所有设备开始低质量推流 await Clients.All.SendAsync("DevicesNeedStream", deviceUuids, "low"); } /// /// 教师端停止监控(离开监控墙页面) /// public async Task StopMonitoring() { var connectionId = Context.ConnectionId; _logger.LogInformation("教师端 {ConnectionId} 停止监控", connectionId); List devicesToStop = new(); lock (_lock) { // 移除该连接对所有设备的监控 foreach (var (uuid, watchers) in _deviceWatchers) { if (watchers.Remove(connectionId) && watchers.Count == 0) { devicesToStop.Add(uuid); } } // 清理空的监控记录 foreach (var uuid in devicesToStop) { _deviceWatchers.Remove(uuid); } } // 通知设备停止推流 if (devicesToStop.Count > 0) { await Clients.All.SendAsync("DevicesStopStream", devicesToStop); } } /// /// 教师端选中某台设备(切换到高质量) /// public async Task SelectDevice(string deviceUuid) { _logger.LogInformation("教师端 {ConnectionId} 选中设备 {DeviceUuid}", Context.ConnectionId, deviceUuid); // 通知该设备切换到高质量 await Clients.All.SendAsync("DeviceQualityChange", deviceUuid, "high"); } /// /// 教师端取消选中设备(切换回低质量) /// public async Task DeselectDevice(string deviceUuid) { _logger.LogInformation("教师端 {ConnectionId} 取消选中设备 {DeviceUuid}", Context.ConnectionId, deviceUuid); // 通知该设备切换回低质量 await Clients.All.SendAsync("DeviceQualityChange", deviceUuid, "low"); } /// /// 设备端注册(Agent 启动时调用) /// public async Task RegisterDevice(string deviceUuid) { _logger.LogInformation("设备 {DeviceUuid} 注册到 SignalR Hub", deviceUuid); // 加入设备专属组 await Groups.AddToGroupAsync(Context.ConnectionId, $"device_{deviceUuid}"); // 检查是否有人正在监控该设备 bool isBeingWatched; lock (_lock) { isBeingWatched = _deviceWatchers.ContainsKey(deviceUuid) && _deviceWatchers[deviceUuid].Count > 0; } // 如果有人监控,通知设备开始推流 if (isBeingWatched) { await Clients.Caller.SendAsync("StartStream", "low"); } } /// /// 设备端取消注册(Agent 关闭时调用) /// public async Task UnregisterDevice(string deviceUuid) { _logger.LogInformation("设备 {DeviceUuid} 从 SignalR Hub 取消注册", deviceUuid); await Groups.RemoveFromGroupAsync(Context.ConnectionId, $"device_{deviceUuid}"); } /// /// 连接断开时清理 /// public override async Task OnDisconnectedAsync(Exception? exception) { var connectionId = Context.ConnectionId; _logger.LogInformation("连接 {ConnectionId} 断开", connectionId); // 清理监控记录 List devicesToStop = new(); lock (_lock) { foreach (var (uuid, watchers) in _deviceWatchers) { if (watchers.Remove(connectionId) && watchers.Count == 0) { devicesToStop.Add(uuid); } } foreach (var uuid in devicesToStop) { _deviceWatchers.Remove(uuid); } } // 通知设备停止推流 if (devicesToStop.Count > 0) { await Clients.All.SendAsync("DevicesStopStream", devicesToStop); } await base.OnDisconnectedAsync(exception); } /// /// 获取当前监控状态(调试用) /// public Dictionary GetMonitoringStatus() { lock (_lock) { return _deviceWatchers.ToDictionary( kvp => kvp.Key, kvp => kvp.Value.Count ); } } }