servicepoint-tanks/tanks-backend/TanksServer/Interactivity/WebsocketServer.cs

77 lines
2.4 KiB
C#
Raw Normal View History

2024-04-21 23:00:44 +02:00
using Microsoft.Extensions.Hosting;
namespace TanksServer.Interactivity;
internal abstract class WebsocketServer<T>(
2024-04-21 23:00:44 +02:00
ILogger logger
) : IHostedLifecycleService, IDisposable
where T : WebsocketServerConnection
2024-04-21 23:00:44 +02:00
{
private readonly SemaphoreSlim _mutex = new(1, 1);
private bool _closing;
private readonly HashSet<T> _connections = [];
public async Task StoppingAsync(CancellationToken cancellationToken)
{
logger.LogInformation("closing connections");
2024-04-28 15:34:32 +02:00
await LockedAsync(async () =>
2024-04-21 23:00:44 +02:00
{
_closing = true;
await Task.WhenAll(_connections.Select(c => c.CloseAsync()));
}, cancellationToken);
logger.LogInformation("closed connections");
}
2024-04-28 15:34:32 +02:00
protected ValueTask ParallelForEachConnectionAsync(Func<T, Task> body) =>
LockedAsync(async () => await Task.WhenAll(_connections.Select(body)), CancellationToken.None);
2024-04-21 23:00:44 +02:00
2024-04-28 15:34:32 +02:00
private ValueTask AddConnectionAsync(T connection) => LockedAsync(async () =>
2024-04-21 23:00:44 +02:00
{
if (_closing)
{
logger.LogWarning("refusing connection because server is shutting down");
2024-04-28 15:34:32 +02:00
await connection.CloseAsync();
2024-04-21 23:00:44 +02:00
}
_connections.Add(connection);
}, CancellationToken.None);
2024-04-28 15:34:32 +02:00
private ValueTask RemoveConnectionAsync(T connection) => LockedAsync(() =>
2024-04-21 23:00:44 +02:00
{
_connections.Remove(connection);
2024-04-28 15:34:32 +02:00
return ValueTask.CompletedTask;
2024-04-21 23:00:44 +02:00
}, CancellationToken.None);
protected async Task HandleClientAsync(T connection)
{
2024-04-22 19:03:07 +02:00
await AddConnectionAsync(connection);
await connection.ReceiveAsync();
2024-04-22 19:03:07 +02:00
await RemoveConnectionAsync(connection);
2024-04-21 23:00:44 +02:00
}
2024-04-28 15:34:32 +02:00
private async ValueTask LockedAsync(Func<ValueTask> action, CancellationToken cancellationToken)
2024-04-21 23:00:44 +02:00
{
await _mutex.WaitAsync(cancellationToken);
try
{
await action();
}
finally
{
_mutex.Release();
}
}
public void Dispose() => _mutex.Dispose();
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StartedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StartingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}