tank movement (without collision)
This commit is contained in:
parent
a3bd582b2e
commit
54b840da3e
18 changed files with 321 additions and 254 deletions
90
TanksServer/Helpers/ByteChannelWebSocket.cs
Normal file
90
TanksServer/Helpers/ByteChannelWebSocket.cs
Normal file
|
@ -0,0 +1,90 @@
|
|||
using System.Diagnostics;
|
||||
using System.Net.WebSockets;
|
||||
using System.Threading.Channels;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace TanksServer.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Hacky class for easier semantics
|
||||
/// </summary>
|
||||
internal sealed class ByteChannelWebSocket : Channel<byte[]>
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly WebSocket _socket;
|
||||
private readonly Task _backgroundDone;
|
||||
private readonly byte[] _buffer;
|
||||
|
||||
private readonly Channel<byte[]> _outgoing = Channel.CreateUnbounded<byte[]>();
|
||||
private readonly Channel<byte[]> _incoming = Channel.CreateUnbounded<byte[]>();
|
||||
|
||||
public ByteChannelWebSocket(WebSocket socket, ILogger logger, int messageSize)
|
||||
{
|
||||
_socket = socket;
|
||||
_logger = logger;
|
||||
_buffer = new byte[messageSize];
|
||||
_backgroundDone = Task.WhenAll(ReadLoopAsync(), WriteLoopAsync());
|
||||
|
||||
Reader = _incoming.Reader;
|
||||
Writer = _outgoing.Writer;
|
||||
}
|
||||
|
||||
private async Task ReadLoopAsync()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (_socket.State is not (WebSocketState.Open or WebSocketState.CloseSent))
|
||||
break;
|
||||
|
||||
var response = await _socket.ReceiveAsync(_buffer, CancellationToken.None);
|
||||
if (response.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
if (_socket.State == WebSocketState.CloseReceived)
|
||||
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty,
|
||||
CancellationToken.None);
|
||||
break;
|
||||
}
|
||||
|
||||
if (response.Count != _buffer.Length)
|
||||
{
|
||||
await _socket.CloseAsync(
|
||||
WebSocketCloseStatus.InvalidPayloadData,
|
||||
"response has unexpected size",
|
||||
CancellationToken.None);
|
||||
break;
|
||||
}
|
||||
|
||||
await _incoming.Writer.WriteAsync(_buffer.ToArray());
|
||||
}
|
||||
|
||||
if (_socket.State != WebSocketState.Closed)
|
||||
Debugger.Break();
|
||||
|
||||
_incoming.Writer.Complete();
|
||||
}
|
||||
|
||||
private async Task WriteLoopAsync()
|
||||
{
|
||||
await foreach (var data in _outgoing.Reader.ReadAllAsync())
|
||||
{
|
||||
_logger.LogTrace("sending {} bytes of data", data.Length);
|
||||
try
|
||||
{
|
||||
await _socket.SendAsync(data, WebSocketMessageType.Binary, true, CancellationToken.None);
|
||||
}
|
||||
catch (WebSocketException wsEx)
|
||||
{
|
||||
_logger.LogDebug(wsEx, "send failed");
|
||||
}
|
||||
}
|
||||
|
||||
await _socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||
}
|
||||
|
||||
public async Task CloseAsync()
|
||||
{
|
||||
_logger.LogDebug("closing socket");
|
||||
_outgoing.Writer.Complete();
|
||||
await _backgroundDone;
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
using System.Net.WebSockets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace TanksServer.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Hacky class for easier semantics
|
||||
/// </summary>
|
||||
internal abstract class EasyWebSocket
|
||||
{
|
||||
private readonly TaskCompletionSource _completionSource = new();
|
||||
|
||||
protected readonly ILogger Logger;
|
||||
private readonly WebSocket _socket;
|
||||
private readonly Task _readLoop;
|
||||
private readonly ArraySegment<byte> _buffer;
|
||||
private int _closed;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
protected abstract Task ReceiveAsync(ArraySegment<byte> buffer);
|
||||
protected abstract Task ClosingAsync();
|
||||
|
||||
protected async Task TrySendAsync(byte[] data)
|
||||
{
|
||||
if (_socket.State != WebSocketState.Open)
|
||||
await CloseAsync();
|
||||
|
||||
Logger.LogTrace("sending {} bytes of data", _buffer.Count);
|
||||
|
||||
try
|
||||
{
|
||||
await _socket.SendAsync(data, WebSocketMessageType.Binary, true, CancellationToken.None);
|
||||
}
|
||||
catch (WebSocketException wsEx)
|
||||
{
|
||||
Logger.LogDebug(wsEx, "send failed");
|
||||
}
|
||||
}
|
||||
|
||||
public async Task CloseAsync(
|
||||
WebSocketCloseStatus status = WebSocketCloseStatus.NormalClosure,
|
||||
string? description = null
|
||||
)
|
||||
{
|
||||
if (Interlocked.Exchange(ref _closed, 1) == 1)
|
||||
return;
|
||||
Logger.LogDebug("closing socket");
|
||||
await _socket.CloseAsync(status, description, CancellationToken.None);
|
||||
await _readLoop;
|
||||
await ClosingAsync();
|
||||
_completionSource.SetResult();
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue