using Gameboard.ShogiUI.Sockets.Extensions; using Gameboard.ShogiUI.Sockets.ServiceModels.Socket; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.WebSockets; using System.Threading.Tasks; namespace Gameboard.ShogiUI.Sockets.Managers { public interface ISocketConnectionManager { Task BroadcastToAll(IResponse response); void Subscribe(WebSocket socket, string playerName); void Unsubscribe(string playerName); Task BroadcastToPlayers(IResponse response, params string?[] playerNames); } /// /// Retains all active socket connections and provides convenient methods for sending messages to clients. /// public class SocketConnectionManager : ISocketConnectionManager { /// Dictionary key is player name. private readonly ConcurrentDictionary connections; /// Dictionary key is game name. private readonly ILogger logger; public SocketConnectionManager(ILogger logger) { this.logger = logger; connections = new ConcurrentDictionary(); } public void Subscribe(WebSocket socket, string playerName) { connections.TryRemove(playerName, out var _); connections.TryAdd(playerName, socket); } public void Unsubscribe(string playerName) { connections.TryRemove(playerName, out _); } public async Task BroadcastToPlayers(IResponse response, params string?[] playerNames) { var tasks = new List(playerNames.Length); foreach (var name in playerNames) { if (!string.IsNullOrEmpty(name) && connections.TryGetValue(name, out var socket)) { var serialized = JsonConvert.SerializeObject(response); logger.LogInformation("Response to {0} \n{1}\n", name, serialized); tasks.Add(socket.SendTextAsync(serialized)); } } await Task.WhenAll(tasks); } public Task BroadcastToAll(IResponse response) { var message = JsonConvert.SerializeObject(response); logger.LogInformation($"Broadcasting\n{0}", message); var tasks = new List(connections.Count); foreach (var kvp in connections) { var socket = kvp.Value; try { tasks.Add(socket.SendTextAsync(message)); } catch (WebSocketException) { logger.LogInformation("Tried sending a message to socket connection for user [{user}], but found the connection has closed.", kvp.Key); Unsubscribe(kvp.Key); } catch { logger.LogInformation("Tried sending a message to socket connection for user [{user}], but found the connection has closed.", kvp.Key); Unsubscribe(kvp.Key); } } try { var task = Task.WhenAll(tasks); return task; } catch { Console.WriteLine("Yo"); } return Task.FromResult(0); } } }