using System.Text.Json; using RelayClient.Crypto; using RelayShared.Services; using WebSocketSharp; namespace RelayClient.Services; public sealed class RelaySocketClient { private readonly string _username; private readonly WebSocket _socket; public string? ServerPublicKey { get; private set; } public event Action? RawMessageReceived; public event Action? ChannelListReceived; public event Action? EncryptedChatReceived; public event Action? EncryptedRtcSignalReceived; public event Action? ServerPublicKeyReceived; public event Action? Log; public RelaySocketClient(string username, string url = "ws://192.168.1.85:5001/") { _username = username; _socket = new WebSocket(url); _socket.OnMessage += OnMessage; } public void Connect() { _socket.Connect(); var publicKey = KeyStorage.LoadPublicKey(_username); SendRaw($"AUTHENTICATE_USER|{_username}|{MainPage._userToken}"); SendRaw($"REGISTER_KEY|{_username}|{publicKey}"); SendRaw("GET_SERVER_KEY"); SendRaw("GET_CHANNELS"); } public void SendRaw(string message) { if (_socket.ReadyState == WebSocketState.Open) _socket.Send(message); } public void SendJson(T payload) { SendRaw(JsonSerializer.Serialize(payload)); } public void Disconnect() { _socket.OnMessage -= OnMessage; if (_socket.ReadyState == WebSocketState.Open) _socket.Close(); } private void OnMessage(object? sender, MessageEventArgs e) { if (e.Data.StartsWith("SERVER:REGISTERED_KEY:")) { Log?.Invoke(e.Data); return; } RawMessageReceived?.Invoke(e.Data); Log?.Invoke($"[{_username}] RAW WS DATA: {e.Data}"); try { using var doc = JsonDocument.Parse(e.Data); var root = doc.RootElement; if (!root.TryGetProperty("Type", out var typeElement)) return; var type = (SignalType)typeElement.GetInt32(); switch (type) { case SignalType.ChannelList: { var channelList = JsonSerializer.Deserialize(e.Data); if (channelList is not null) ChannelListReceived?.Invoke(channelList); return; } case SignalType.ServerPublicKey: { var serverKeyMessage = JsonSerializer.Deserialize(e.Data); if (serverKeyMessage is not null) { ServerPublicKey = serverKeyMessage.PublicKey; ServerPublicKeyReceived?.Invoke(serverKeyMessage.PublicKey); } return; } case SignalType.EncryptedSignal: { var payload = JsonSerializer.Deserialize(e.Data); if (payload is not null) EncryptedRtcSignalReceived?.Invoke(payload); return; } case SignalType.EncryptedChat: { var payload = JsonSerializer.Deserialize(e.Data); if (payload is not null) EncryptedChatReceived?.Invoke(payload); return; } } } catch (Exception ex) { Log?.Invoke($"[{_username}] failed to process websocket message: {ex.Message}"); } } }