using System.Collections.Concurrent; namespace Prospect.Server.Api.Hubs; // Maps players to their live SignalR connection so server-initiated messages (e.g. the // matchmaking-success "travel to match" signal) can target a single player instead of being // broadcast to everyone. The client's SignalR URL carries a `uid` query param (added by // GetSignalRConnection); CycleHub records it on connect. public class SignalRConnectionRegistry { private readonly ConcurrentDictionary _userToConn = new(); private readonly ConcurrentDictionary _connToUser = new(); public void Add(string userId, string connectionId) { if (string.IsNullOrEmpty(userId)) return; _userToConn[userId] = connectionId; _connToUser[connectionId] = userId; } public void Remove(string connectionId) { if (_connToUser.TryRemove(connectionId, out var userId)) _userToConn.TryRemove(userId, out _); } public string? GetConnection(string userId) => _userToConn.TryGetValue(userId, out var c) ? c : null; }