58 lines
1.9 KiB
C#
58 lines
1.9 KiB
C#
using System.Net.WebSockets;
|
|
using System.Text.Json;
|
|
|
|
namespace Ngino.Protocol;
|
|
|
|
public static class WebSocketMessageTransport
|
|
{
|
|
private const int BufferSize = 64 * 1024;
|
|
private const int MaxMessageSize = 128 * 1024 * 1024;
|
|
|
|
private static readonly JsonSerializerOptions JsonOptions = new(JsonSerializerDefaults.Web);
|
|
|
|
public static async Task SendAsync(WebSocket socket, TunnelMessage message, CancellationToken cancellationToken)
|
|
{
|
|
var payload = JsonSerializer.SerializeToUtf8Bytes(message, JsonOptions);
|
|
await socket.SendAsync(payload, WebSocketMessageType.Text, true, cancellationToken);
|
|
}
|
|
|
|
public static async Task<TunnelMessage?> ReceiveAsync(WebSocket socket, CancellationToken cancellationToken)
|
|
{
|
|
var buffer = new byte[BufferSize];
|
|
using var payload = new MemoryStream();
|
|
|
|
while (true)
|
|
{
|
|
var result = await socket.ReceiveAsync(buffer, cancellationToken);
|
|
if (result.MessageType == WebSocketMessageType.Close)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (result.MessageType != WebSocketMessageType.Text)
|
|
{
|
|
throw new InvalidOperationException("Only text WebSocket messages are supported.");
|
|
}
|
|
|
|
if (result.Count > 0)
|
|
{
|
|
payload.Write(buffer.AsSpan(0, result.Count));
|
|
}
|
|
|
|
if (payload.Length > MaxMessageSize)
|
|
{
|
|
throw new InvalidOperationException($"Tunnel message exceeded {MaxMessageSize} bytes.");
|
|
}
|
|
|
|
if (result.EndOfMessage)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
payload.Position = 0;
|
|
var message = await JsonSerializer.DeserializeAsync<TunnelMessage>(payload, JsonOptions, cancellationToken);
|
|
return message ?? throw new InvalidOperationException("Received an empty tunnel message.");
|
|
}
|
|
}
|