2021-08-27 15:03:47 +00:00
|
|
|
using System;
|
2021-04-29 09:10:19 +00:00
|
|
|
using System.Buffers;
|
|
|
|
using System.IO;
|
|
|
|
using System.Net.WebSockets;
|
|
|
|
using System.Text.Json;
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
namespace Myriad.Gateway
|
|
|
|
{
|
|
|
|
public class ShardPacketSerializer
|
|
|
|
{
|
|
|
|
private const int BufferSize = 64 * 1024;
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-04-29 09:10:19 +00:00
|
|
|
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);
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-04-29 09:10:19 +00:00
|
|
|
var res = await socket.ReceiveAsync(buf.Memory, default);
|
|
|
|
if (res.MessageType == WebSocketMessageType.Close)
|
|
|
|
return (res.MessageType, null);
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-04-29 09:10:19 +00:00
|
|
|
if (res.EndOfMessage)
|
|
|
|
// Entire packet fits within one buffer, deserialize directly
|
|
|
|
return DeserializeSingleBuffer(buf, res);
|
2021-08-27 15:03:47 +00:00
|
|
|
|
2021-04-29 09:10:19 +00:00
|
|
|
// 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));
|
|
|
|
}
|
|
|
|
|
2021-08-27 15:03:47 +00:00
|
|
|
return DeserializeObject(res, stream.GetBuffer().AsSpan(0, (int)stream.Length));
|
2021-04-29 09:10:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|