using System.Net; using System.Net.Sockets; using System.Text.Json; using Fleck; using WirelessTextSyncer.Windows.Models; namespace WirelessTextSyncer.Windows.Services; public sealed class WebSocketServerService : IDisposable { private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web) { PropertyNameCaseInsensitive = true }; private readonly SyncMessageHandler messageHandler; private readonly List clients = []; private readonly object clientsLock = new(); private WebSocketServer? server; public WebSocketServerService(SyncMessageHandler messageHandler) { this.messageHandler = messageHandler; } public int Port { get; private set; } = 8181; public string LocalIpAddress { get; private set; } = "127.0.0.1"; public bool HasClient { get { lock (clientsLock) { return clients.Count > 0; } } } public event EventHandler? StatusChanged; public void Start(int port) { Port = port; LocalIpAddress = ResolveLocalIpAddress(); server = new WebSocketServer($"ws://0.0.0.0:{Port}"); server.Start(socket => { socket.OnOpen = () => { lock (clientsLock) { clients.Add(socket); } StatusChanged?.Invoke(this, EventArgs.Empty); }; socket.OnClose = () => { lock (clientsLock) { clients.Remove(socket); } StatusChanged?.Invoke(this, EventArgs.Empty); }; socket.OnMessage = HandleRawMessage; }); } public void Dispose() { IWebSocketConnection[] currentClients; lock (clientsLock) { currentClients = clients.ToArray(); clients.Clear(); } foreach (var client in currentClients) { client.Close(); } server?.Dispose(); } private void HandleRawMessage(string rawMessage) { try { var message = JsonSerializer.Deserialize(rawMessage, JsonOptions); if (message is null) { return; } messageHandler.Handle(message); } catch (JsonException) { return; } } private static string ResolveLocalIpAddress() { var host = Dns.GetHostEntry(Dns.GetHostName()); var address = host.AddressList.FirstOrDefault( address => address.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(address)); return address?.ToString() ?? "127.0.0.1"; } }