68 lines
2.4 KiB
C#
68 lines
2.4 KiB
C#
using System.Buffers;
|
|
using System.Net.WebSockets;
|
|
using System.Text.Json;
|
|
|
|
namespace Myriad.Gateway;
|
|
|
|
public class ShardPacketSerializer
|
|
{
|
|
private const int BufferSize = 64 * 1024;
|
|
|
|
private readonly JsonSerializerOptions _jsonSerializerOptions;
|
|
|
|
public ShardPacketSerializer(JsonSerializerOptions jsonSerializerOptions)
|
|
{
|
|
_jsonSerializerOptions = jsonSerializerOptions;
|
|
}
|
|
|
|
public async ValueTask<(WebSocketMessageType type, GatewayPacket? packet)> ReadPacket(ClientWebSocket socket)
|
|
{
|
|
using var buf = MemoryPool<byte>.Shared.Rent(BufferSize);
|
|
|
|
var res = await socket.ReceiveAsync(buf.Memory, default);
|
|
if (res.MessageType == WebSocketMessageType.Close)
|
|
return (res.MessageType, null);
|
|
|
|
if (res.EndOfMessage)
|
|
// Entire packet fits within one buffer, deserialize directly
|
|
return DeserializeSingleBuffer(buf, res);
|
|
|
|
// Otherwise copy to stream buffer and deserialize from there
|
|
return await DeserializeMultipleBuffer(socket, buf, res);
|
|
}
|
|
|
|
public async Task WritePacket(ClientWebSocket socket, GatewayPacket packet)
|
|
{
|
|
var bytes = JsonSerializer.SerializeToUtf8Bytes(packet, _jsonSerializerOptions);
|
|
await socket.SendAsync(bytes.AsMemory(), WebSocketMessageType.Text, true, default);
|
|
}
|
|
|
|
private async Task<(WebSocketMessageType type, GatewayPacket packet)> DeserializeMultipleBuffer(
|
|
ClientWebSocket socket, IMemoryOwner<byte> buf, ValueWebSocketReceiveResult res)
|
|
{
|
|
await using var stream = new MemoryStream(BufferSize * 4);
|
|
stream.Write(buf.Memory.Span.Slice(0, res.Count));
|
|
|
|
while (!res.EndOfMessage)
|
|
{
|
|
res = await socket.ReceiveAsync(buf.Memory, default);
|
|
stream.Write(buf.Memory.Span.Slice(0, res.Count));
|
|
}
|
|
|
|
return DeserializeObject(res, stream.GetBuffer().AsSpan(0, (int)stream.Length));
|
|
}
|
|
|
|
private (WebSocketMessageType type, GatewayPacket packet) DeserializeSingleBuffer(
|
|
IMemoryOwner<byte> buf, ValueWebSocketReceiveResult res)
|
|
{
|
|
var span = buf.Memory.Span.Slice(0, res.Count);
|
|
return DeserializeObject(res, span);
|
|
}
|
|
|
|
private (WebSocketMessageType type, GatewayPacket packet) DeserializeObject(
|
|
ValueWebSocketReceiveResult res, Span<byte> span)
|
|
{
|
|
var packet = JsonSerializer.Deserialize<GatewayPacket>(span, _jsonSerializerOptions)!;
|
|
return (res.MessageType, packet);
|
|
}
|
|
} |