2024-06-24 18:21:59 -04:00
using System.Net.WebSockets ;
using System.Text ;
using System.Text.Json ;
2024-08-10 15:36:32 -04:00
using CommonSocketLibrary.Common ;
2024-06-24 18:21:59 -04:00
using HermesSocketLibrary.Socket.Data ;
using HermesSocketServer.Socket ;
using ILogger = Serilog . ILogger ;
namespace HermesSocketLibrary
{
public class Server
{
private readonly HermesSocketManager _sockets ;
private readonly SocketHandlerManager _handlers ;
private readonly JsonSerializerOptions _options ;
private readonly ILogger _logger ;
public Server (
HermesSocketManager sockets ,
SocketHandlerManager handlers ,
JsonSerializerOptions options ,
ILogger logger
)
{
_sockets = sockets ;
_handlers = handlers ;
_options = options ;
_logger = logger ;
}
public async Task Handle ( WebSocketUser socket , HttpContext context )
{
2024-08-10 15:36:32 -04:00
_logger . Information ( $"Socket connected [ip: {socket.IPAddress}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
_sockets . Add ( socket ) ;
var buffer = new byte [ 1024 * 8 ] ;
while ( socket . State = = WebSocketState . Open )
{
try
{
var result = await socket . Receive ( new ArraySegment < byte > ( buffer ) ) ;
if ( result = = null | | result . MessageType = = WebSocketMessageType . Close | | ! socket . Connected )
break ;
string message = Encoding . UTF8 . GetString ( buffer , 0 , result . Count ) . TrimEnd ( '\0' ) ;
2024-08-10 15:36:32 -04:00
var obj = JsonSerializer . Deserialize < WebSocketMessage > ( message , _options ) ;
if ( obj = = null )
2024-06-24 18:21:59 -04:00
continue ;
if ( obj . OpCode ! = 0 )
2024-08-10 15:36:32 -04:00
_logger . Information ( $"rxm: {message} [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
2024-10-17 23:21:16 -04:00
int [ ] nonProtectedOps = { 0 , 1 } ;
if ( string . IsNullOrEmpty ( socket . Id ) & & ! nonProtectedOps . Contains ( obj . OpCode ) )
{
_logger . Warning ( $"An attempt was made to use protected routes while not logged in [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
return ;
}
int [ ] protectedOps = { 0 , 3 , 5 , 6 , 7 , 8 } ;
if ( ! string . IsNullOrEmpty ( socket . Id ) & & ! protectedOps . Contains ( obj . OpCode ) )
{
_logger . Warning ( $"An attempt was made to use non-protected routes while logged in [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
return ;
}
2024-06-24 18:21:59 -04:00
/ * *
* 0 : Heartbeat
* 1 : Login RX
* 2 : Login Ack TX
* 3 : Request RX
* 4 : Request Ack TX
2024-08-10 15:36:32 -04:00
* 5 : Logging RX / TX
2024-06-24 18:21:59 -04:00
* /
if ( obj . Data = = null )
{
2024-08-10 15:36:32 -04:00
await socket . Send ( 5 , new LoggingMessage ( "Received no data in the message." , HermesLoggingLevel . Warn ) ) ;
2024-06-24 18:21:59 -04:00
continue ;
}
else if ( obj . OpCode = = 0 )
obj . Data = JsonSerializer . Deserialize < HeartbeatMessage > ( obj . Data . ToString ( ) , _options ) ;
else if ( obj . OpCode = = 1 )
obj . Data = JsonSerializer . Deserialize < HermesLoginMessage > ( obj . Data . ToString ( ) , _options ) ;
else if ( obj . OpCode = = 3 )
obj . Data = JsonSerializer . Deserialize < RequestMessage > ( obj . Data . ToString ( ) , _options ) ;
else if ( obj . OpCode = = 5 )
2024-08-10 15:36:32 -04:00
obj . Data = JsonSerializer . Deserialize < LoggingMessage > ( obj . Data . ToString ( ) , _options ) ;
2024-06-24 18:21:59 -04:00
else if ( obj . OpCode = = 6 )
obj . Data = JsonSerializer . Deserialize < ChatterMessage > ( obj . Data . ToString ( ) , _options ) ;
else if ( obj . OpCode = = 7 )
obj . Data = JsonSerializer . Deserialize < EmoteDetailsMessage > ( obj . Data . ToString ( ) , _options ) ;
else if ( obj . OpCode = = 8 )
obj . Data = JsonSerializer . Deserialize < EmoteUsageMessage > ( obj . Data . ToString ( ) , _options ) ;
else
{
2024-08-10 15:36:32 -04:00
await socket . Send ( 5 , new LoggingMessage ( "Received an invalid message: " + message , HermesLoggingLevel . Error ) ) ;
2024-06-24 18:21:59 -04:00
continue ;
}
2024-08-10 15:36:32 -04:00
await _handlers . Execute ( socket , obj . OpCode , obj . Data ) ;
}
catch ( WebSocketException wse )
{
_logger . Error ( wse , $"Error trying to process a socket message [code: {wse.ErrorCode}][ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
}
catch ( Exception e )
{
2024-08-10 15:36:32 -04:00
_logger . Error ( e , $"Error trying to process a socket message [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
}
}
try
{
if ( socket . Connected )
2024-08-10 15:36:32 -04:00
await socket . Close ( socket . CloseStatus ? ? WebSocketCloseStatus . NormalClosure , "" , CancellationToken . None ) ;
}
catch ( Exception e )
{
_logger . Information ( e , $"Client failed to disconnect [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
}
2024-08-10 15:36:32 -04:00
finally
2024-06-24 18:21:59 -04:00
{
2024-08-10 15:36:32 -04:00
socket . Dispose ( ) ;
2024-06-24 18:21:59 -04:00
_sockets . Remove ( socket ) ;
}
2024-08-10 15:36:32 -04:00
_logger . Information ( $"Client disconnected [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]" ) ;
2024-06-24 18:21:59 -04:00
}
}
}