servicepoint-tanks/TanksServer/EasyWebSocket.cs

72 lines
2 KiB
C#
Raw Normal View History

2024-04-06 20:32:54 +02:00
using System.Net.WebSockets;
using System.Threading;
using Microsoft.Extensions.Logging;
namespace TanksServer;
internal abstract class EasyWebSocket
{
private readonly TaskCompletionSource _completionSource = new();
private readonly ILogger _logger;
private readonly WebSocket _socket;
private readonly Task _readLoop;
private readonly ArraySegment<byte> _buffer;
2024-04-06 21:15:26 +02:00
private int _closed;
2024-04-06 20:32:54 +02:00
protected EasyWebSocket(WebSocket socket, ILogger logger, ArraySegment<byte> buffer)
{
_socket = socket;
_logger = logger;
_buffer = buffer;
_readLoop = ReadLoopAsync();
}
public Task Done => _completionSource.Task;
private async Task ReadLoopAsync()
{
do
{
var response = await _socket.ReceiveAsync(_buffer, CancellationToken.None);
if (response.CloseStatus.HasValue)
break;
await ReceiveAsync(_buffer[..response.Count]);
} while (_socket.State == WebSocketState.Open);
2024-04-06 21:15:26 +02:00
await CloseAsync();
2024-04-06 20:32:54 +02:00
}
protected abstract Task ReceiveAsync(ArraySegment<byte> buffer);
2024-04-06 21:15:26 +02:00
protected abstract Task ClosingAsync();
2024-04-06 20:32:54 +02:00
2024-04-06 21:15:26 +02:00
protected async Task TrySendAsync(byte[] data)
2024-04-06 20:32:54 +02:00
{
2024-04-06 21:15:26 +02:00
if (_socket.State != WebSocketState.Open)
await CloseAsync();
2024-04-06 20:32:54 +02:00
_logger.LogTrace("sending {} bytes of data", _buffer.Count);
2024-04-06 21:15:26 +02:00
try
{
await _socket.SendAsync(data, WebSocketMessageType.Binary, true, CancellationToken.None);
}
catch (WebSocketException wsEx)
{
_logger.LogDebug(wsEx, "send failed");
}
2024-04-06 20:32:54 +02:00
}
public async Task CloseAsync()
{
2024-04-06 21:15:26 +02:00
if (Interlocked.Exchange(ref _closed, 1) == 1)
return;
2024-04-06 20:32:54 +02:00
_logger.LogDebug("closing socket");
await _socket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, CancellationToken.None);
await _readLoop;
2024-04-06 21:15:26 +02:00
await ClosingAsync();
2024-04-06 20:32:54 +02:00
_completionSource.SetResult();
}
}