VanguardReMaster/server/src/Vanguard.Server/Realtime/ProtocolFrameReader.cs

65 lines
1.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Net.WebSockets;
using Vanguard.Shared.Protocol;
namespace Vanguard.Server.Realtime;
/// <summary>Чтение одного кадра протокола из бинарных сообщений WebSocket.</summary>
internal static class ProtocolFrameReader
{
public static async Task<ClientFrame?> ReadAsync(WebSocket socket, CancellationToken cancellationToken)
{
var buffer = new byte[16 * 1024];
using var stream = new MemoryStream();
while (true)
{
var result = await socket.ReceiveAsync(buffer.AsMemory(), cancellationToken);
if (result.MessageType == WebSocketMessageType.Close)
return null;
if (result.MessageType != WebSocketMessageType.Binary)
throw new ProtocolFormatException("Ожидался бинарный кадр.");
stream.Write(buffer, 0, result.Count);
if (stream.Length > ProtocolConstants.MaxFrameBytes)
throw new ProtocolFormatException(
$"Кадр больше {ProtocolConstants.MaxFrameBytes} байт.");
if (result.EndOfMessage)
break;
}
return ProtocolSerializer.DecodeClient(stream.ToArray());
}
}
/// <summary>Не больше N интентов в секунду с одного соединения.</summary>
internal sealed class IntentRateLimiter
{
private readonly int _limit;
private readonly TimeProvider _time;
private DateTimeOffset _windowStart;
private int _count;
public IntentRateLimiter(int limit, TimeProvider time)
{
_limit = limit;
_time = time;
_windowStart = time.GetUtcNow();
}
public bool TryAcquire()
{
var now = _time.GetUtcNow();
if (now - _windowStart >= TimeSpan.FromSeconds(1))
{
_windowStart = now;
_count = 0;
}
return ++_count <= _limit;
}
}