TigerEmu/Networking/Game/WebSocketServer.cs

104 lines
3.3 KiB
C#
Raw Normal View History

2023-09-23 11:11:07 +00:00
using System.Net;
using System.Net.WebSockets;
using Tiger.Communication.Messages;
using Tiger.Communication.Messages.Types;
using Tiger.Networking.Game.Sessions;
using Tiger.Utils;
namespace Tiger.Networking.Game;
public class WebSocketServer : IWebSocketServer
{
private readonly HttpListener _httpListener = new();
private readonly IGameSessionManager _gameSessionManager;
private readonly IMessageHandler _messageHandler;
public WebSocketServer(IGameSessionManager gameSessionManager, IMessageHandler messageHandler)
{
_gameSessionManager = gameSessionManager;
_messageHandler = messageHandler;
}
public async Task Start(string uriPrefix)
{
_httpListener.Prefixes.Add(uriPrefix);
_httpListener.Start();
Console.WriteLine($"Listening on {uriPrefix}...");
while (true)
{
var context = await _httpListener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
ProcessRequestAsync(context);
}
else
{
context.Response.StatusCode = 400;
context.Response.Close();
}
}
}
private async void ProcessRequestAsync(HttpListenerContext context)
{
WebSocket? webSocket = null;
try
{
var webSocketContext = await context.AcceptWebSocketAsync(null);
webSocket = webSocketContext.WebSocket;
var session = _gameSessionManager.AddSession(webSocket);
Console.WriteLine($"WebSocket Session {session.SessionId} has connected.");
await ReceiveMessageAsync(session.SessionId);
}
catch (Exception e)
{
Console.WriteLine($"WebSocket Session Error: {e.Message}");
}
finally
{
if (webSocket != null)
{
_gameSessionManager.RemoveSession(webSocket);
webSocket.Dispose();
}
}
}
private async Task ReceiveMessageAsync(string sessionId)
{
var buffer = new byte[1024 * 4];
while (_gameSessionManager.GetSession(sessionId) is { WebSocket.State: WebSocketState.Open } gameSession)
{
var result = await gameSession.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
var offset = 0;
while (result.MessageType == WebSocketMessageType.Binary && offset + 4 <= result.Count)
{
var length = ByteUtils.GetInt32(new[]
{
buffer[offset], buffer[offset + 1], buffer[offset + 2], buffer[offset + 3]
});
offset += 4;
if (offset + length > result.Count) break;
var packet = new byte[result.Count];
Array.Copy(buffer, offset, packet, 0, length);
offset += length;
_messageHandler.TryHandleAsync(gameSession, new ClientMessage(packet));
}
if (result.MessageType == WebSocketMessageType.Close)
{
await gameSession.WebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
}
}
}
}