Snowflake/RPG.Services.Gateserver/Network/Tcp/TcpGateway.cs

87 lines
2.5 KiB
C#

using System.Net;
using System.Net.Sockets;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using RPG.Services.Core.Session;
using RPG.Services.Gateserver.Options;
using RPG.Services.Gateserver.Session;
namespace RPG.Services.Gateserver.Network.Tcp;
internal class TcpGateway
{
private readonly IOptions<GatewayOptions> _options;
private readonly SessionManager _sessionManager;
private readonly ILogger _logger;
private Socket? _socket;
private CancellationTokenSource? _acceptCancellation;
private Task? _acceptTask;
private ulong _sessionIdCounter;
public TcpGateway(IOptions<GatewayOptions> options, SessionManager sessionManager, ILogger<TcpGateway> logger)
{
_options = options;
_sessionManager = sessionManager;
_logger = logger;
}
public void Start()
{
IPEndPoint bindEndPoint = _options.Value.BindEndPoint;
_socket = new(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(bindEndPoint);
_socket.Listen(100);
_acceptCancellation = new();
_acceptTask = RunAcceptLoopAsync(_acceptCancellation.Token);
_logger.LogInformation("Listening at tcp://{endPoint}", bindEndPoint);
}
public async Task StopAsync()
{
if (_acceptCancellation != null && _acceptTask != null)
{
await _acceptCancellation.CancelAsync();
await _acceptTask;
}
_socket?.Close();
}
private async Task RunAcceptLoopAsync(CancellationToken cancellationToken)
{
try
{
while (!cancellationToken.IsCancellationRequested)
{
Socket clientSocket = await _socket!.AcceptAsync(cancellationToken);
_ = RunSessionAsync(clientSocket);
}
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
throw;
}
}
private async Task RunSessionAsync(Socket socket)
{
try
{
NetworkSession? session = _sessionManager.Create<NetworkSession>(Interlocked.Increment(ref _sessionIdCounter));
if (session == null) return;
session.Socket = socket;
await session.RunAsync();
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
_logger.LogError("Unhandled exception occurred: {exception}", exception);
}
}
}