127 lines
3.7 KiB
C#
127 lines
3.7 KiB
C#
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<string>? RawMessageReceived;
|
|
public event Action<SocketChannelList>? ChannelListReceived;
|
|
public event Action<SocketEncryptedMessage>? EncryptedChatReceived;
|
|
public event Action<SocketRtcSignalMessage>? EncryptedRtcSignalReceived;
|
|
public event Action<string>? ServerPublicKeyReceived;
|
|
public event Action<string>? Log;
|
|
|
|
public RelaySocketClient(string username, string url = "ws://localhost:1337/")
|
|
{
|
|
_username = username;
|
|
_socket = new WebSocket(url);
|
|
_socket.OnMessage += OnMessage;
|
|
}
|
|
|
|
public void Connect()
|
|
{
|
|
_socket.Connect();
|
|
|
|
var publicKey = KeyStorage.LoadPublicKey(_username);
|
|
|
|
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>(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<SocketChannelList>(e.Data);
|
|
if (channelList is not null)
|
|
ChannelListReceived?.Invoke(channelList);
|
|
|
|
return;
|
|
}
|
|
|
|
case SignalType.ServerPublicKey:
|
|
{
|
|
var serverKeyMessage = JsonSerializer.Deserialize<ServerPublicKeyMessage>(e.Data);
|
|
if (serverKeyMessage is not null)
|
|
{
|
|
ServerPublicKey = serverKeyMessage.PublicKey;
|
|
ServerPublicKeyReceived?.Invoke(serverKeyMessage.PublicKey);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
case SignalType.EncryptedSignal:
|
|
{
|
|
var payload = JsonSerializer.Deserialize<SocketRtcSignalMessage>(e.Data);
|
|
if (payload is not null)
|
|
EncryptedRtcSignalReceived?.Invoke(payload);
|
|
|
|
return;
|
|
}
|
|
|
|
case SignalType.EncryptedChat:
|
|
{
|
|
var payload = JsonSerializer.Deserialize<SocketEncryptedMessage>(e.Data);
|
|
if (payload is not null)
|
|
EncryptedChatReceived?.Invoke(payload);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Log?.Invoke($"[{_username}] failed to process websocket message: {ex.Message}");
|
|
}
|
|
}
|
|
} |