TigerEmu/Networking/Game/WebSocketServer.cs

118 lines
3.8 KiB
C#
Raw Normal View History

2023-09-23 11:11:07 +00:00
using System.Net;
using System.Net.WebSockets;
using Microsoft.Extensions.Logging;
2023-09-23 11:11:07 +00:00
using Tiger.Communication.Messages;
using Tiger.Communication.Messages.Types;
using Tiger.Game.Habbos;
2023-09-23 11:11:07 +00:00
using Tiger.Networking.Game.Sessions;
using Tiger.Storage;
2023-09-23 11:11:07 +00:00
using Tiger.Utils;
namespace Tiger.Networking.Game;
public class WebSocketServer : IWebSocketServer
{
private readonly HttpListener _httpListener = new();
private readonly IGameSessionManager _gameSessionManager;
private readonly IMessageHandler _messageHandler;
private readonly IRepository<Habbo> _habboRepository;
private readonly ILogger<IWebSocketServer> _logger;
2023-09-23 11:11:07 +00:00
public WebSocketServer(IGameSessionManager gameSessionManager, IMessageHandler messageHandler, IRepository<Habbo> habboRepository, ILogger<IWebSocketServer> logger)
2023-09-23 11:11:07 +00:00
{
_gameSessionManager = gameSessionManager;
_messageHandler = messageHandler;
_habboRepository = habboRepository;
_logger = logger;
2023-09-23 11:11:07 +00:00
}
public async Task Start(string uriPrefix)
{
_httpListener.Prefixes.Add(uriPrefix);
_httpListener.Start();
_logger.LogInformation("WebSocket server running on {uriPrefix}...", uriPrefix);
2023-09-23 11:11:07 +00:00
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);
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];
GameSession? gameSession;
while ((gameSession = _gameSessionManager.GetSession(sessionId)) is { WebSocket.State: WebSocketState.Open })
2023-09-23 11:11:07 +00:00
{
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);
}
}
if (gameSession is { Habbo: not null })
{
gameSession.Habbo.Online = false;
await _habboRepository.SaveAsync(gameSession.Habbo);
_logger.LogInformation("{User} logged out", gameSession.Habbo.Username);
}
2023-09-23 11:11:07 +00:00
}
}