diff --git a/Server/AesSession.cs b/Server/AesSession.cs index 3b40a28..2aa37c0 100644 --- a/Server/AesSession.cs +++ b/Server/AesSession.cs @@ -192,9 +192,11 @@ public abstract class AesSession : TcpSession Console.WriteLine("password: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 20, 32)); Console.WriteLine("Full buffer: " + Encoding.ASCII.GetString(dataBuffer.ToArray())); - Packet packet = new Packet((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0], buffer[3], - Id); - Parallel.Invoke(() => _mediator.Send(packet)); + RawPacket rawPacket = new RawPacket((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0], + buffer[3], + Id, this); + Parallel.Invoke(() => _mediator.Send(rawPacket)); + _logger.LogInformation("Connection from: {@RemoteEndpoint}", Socket.RemoteEndPoint); base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length); } catch (CryptographicException ex) diff --git a/Server/FieldOffsetAttribute.cs b/Server/FieldOffsetAttribute.cs new file mode 100644 index 0000000..cfad9d7 --- /dev/null +++ b/Server/FieldOffsetAttribute.cs @@ -0,0 +1,13 @@ +namespace Server; + +public class FieldOffsetAttribute : Attribute +{ + public int Offset { get; set; } + public int Size { get; set; } + + public FieldOffsetAttribute(int offset, int size) + { + Offset = offset; + Size = size; + } +} \ No newline at end of file diff --git a/Server/IPacket.cs b/Server/IPacket.cs new file mode 100644 index 0000000..8ac9909 --- /dev/null +++ b/Server/IPacket.cs @@ -0,0 +1,5 @@ +namespace Server; + +public interface IPacket +{ +} diff --git a/Server/IPacketHandler.cs b/Server/IPacketHandler.cs index 6068aa3..f11243a 100644 --- a/Server/IPacketHandler.cs +++ b/Server/IPacketHandler.cs @@ -1,6 +1,6 @@ namespace Server; -public interface IPacketHandler +public interface IPacketHandler where T: IPacket { - public void Process(Packet packet); + public void Handle(T packet); } \ No newline at end of file diff --git a/Server/LoginHandler.cs b/Server/LoginHandler.cs deleted file mode 100644 index a6f5465..0000000 --- a/Server/LoginHandler.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; - -namespace Server; - -[PacketHandler(OperationCode.LoginInfo)] -public class LoginHandler : IPacketHandler -{ - public void Process(Packet packet) - { - Console.WriteLine("Login being processed."); - } -} \ No newline at end of file diff --git a/Server/LoginInfoHandler.cs b/Server/LoginInfoHandler.cs new file mode 100644 index 0000000..014786f --- /dev/null +++ b/Server/LoginInfoHandler.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.Logging; + +namespace Server; + +public class LoginHandler : IPacketHandler +{ + private readonly ILogger _logger; + + public LoginHandler(ILogger logger) + { + _logger = logger; + } + + public void Handle(LoginInfoPacket packet) + { + _logger.LogInformation("Login data: Username {Username} & Password {Password}", packet.Username, packet.Password); + } +} \ No newline at end of file diff --git a/Server/LoginInfoPacket.cs b/Server/LoginInfoPacket.cs new file mode 100644 index 0000000..3fb9c4e --- /dev/null +++ b/Server/LoginInfoPacket.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace Server; + +[PacketId(OperationCode.LoginInfo)] +public class LoginInfoPacket : IPacket +{ + [FieldOffset(0, 20)] public string Username; + + [FieldOffset(20, 31)] public string Password; +} \ No newline at end of file diff --git a/Server/PacketConsumer.cs b/Server/PacketConsumer.cs index 7def403..c9282d6 100644 --- a/Server/PacketConsumer.cs +++ b/Server/PacketConsumer.cs @@ -2,7 +2,7 @@ namespace Server; -public class PacketConsumer : IConsumer +public class PacketConsumer : IConsumer { private readonly PacketDistributorService _distributorService; @@ -11,8 +11,9 @@ public class PacketConsumer : IConsumer _distributorService = distributorService; } - public Task Consume(ConsumeContext context) + public Task Consume(ConsumeContext context) { - return _distributorService.AddPacket(context.Message); + _distributorService.AddPacket(context.Message); + return Task.CompletedTask; } } \ No newline at end of file diff --git a/Server/PacketDistributorService.cs b/Server/PacketDistributorService.cs index efafac9..6b9fb48 100644 --- a/Server/PacketDistributorService.cs +++ b/Server/PacketDistributorService.cs @@ -1,35 +1,74 @@ using System.Collections.Concurrent; using System.Reflection; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using MassTransit.Internals; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; +using Microsoft.VisualBasic.CompilerServices; +using Newtonsoft.Json; namespace Server; public class PacketDistributorService : IHostedService { - private readonly ConcurrentQueue _concurrentQueue; + private readonly ConcurrentQueue _concurrentQueue; private readonly ILogger _logger; - private readonly CancellationTokenSource _cancellationTokenSource = new(); - private readonly Dictionary _actions; + private readonly Dictionary _packetsTypes; + private readonly Dictionary _packetHandlers; + private readonly IServiceProvider _serviceProvider; - public PacketDistributorService(ILogger logger) + public PacketDistributorService(ILogger logger, IServiceProvider serviceProvider) { - _concurrentQueue = new ConcurrentQueue(); + _concurrentQueue = new ConcurrentQueue(); _logger = logger; - _actions = new Dictionary(); - var packetHandlers = Assembly.GetExecutingAssembly().GetTypes().Where(t => - t.GetCustomAttributes().Any(attribute => attribute.GetType() == typeof(PacketHandler)) && - t.GetInterfaces().Contains(typeof(IPacketHandler))); - foreach (var type in packetHandlers) + _serviceProvider = serviceProvider; + _packetHandlers = new Dictionary(); + _packetsTypes = new Dictionary(); + + var packetsWithId = Assembly.GetEntryAssembly()?.GetTypes().AsParallel() + .Where(type => type.GetCustomAttribute() != null && type.HasInterface(typeof(IPacket)) && + !type.IsInterface) + //.Select(Activator.CreateInstance).Cast() + .ToDictionary(packet => packet.GetCustomAttribute()!.Code); + + if (packetsWithId == null || packetsWithId.Count == 0) { - PacketHandler packetHandler = type.GetCustomAttribute()!; - _actions.Add(packetHandler.Code, - type.GetConstructor( Type.EmptyTypes) - .Invoke(null) as IPacketHandler); - _logger.LogInformation( - "Handler for ID \"{PacketHandlerCode}\" has been added with name \"{PacketHandlerName}\"", - packetHandler.Code, type.Name); + _logger.LogCritical("No Packets have been found"); + throw new IncompleteInitialization(); } + + packetsWithId.AsParallel().ForAll(packet => + { + _logger.LogInformation("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key, + packet.Value.FullName); + }); + _packetsTypes = packetsWithId; + + + var packetHandlersWithId = Assembly.GetEntryAssembly()?.GetTypes().Where(t => + t is { IsClass: true, IsAbstract: false } && t + .GetInterfaces().Any(i => + i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>))).ToDictionary(type => + type.GetInterfaces().First(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>)) + .GetGenericArguments()[0].GetCustomAttribute().Code); + + + if (packetHandlersWithId == null || packetHandlersWithId.Count == 0) + { + _logger.LogCritical("No PacketHandlers have been found"); + throw new IncompleteInitialization(); + } + + packetHandlersWithId.AsParallel().ForAll(packetHandler => + { + _logger.LogInformation("Packet with ID: {PacketID} has been added as {PacketName}", packetHandler.Key, + packetHandler.Value.FullName); + }); + + _packetHandlers = packetHandlersWithId; } public Task StartAsync(CancellationToken cancellationToken) @@ -37,33 +76,60 @@ public class PacketDistributorService : IHostedService return Task.CompletedTask; } - public Task AddPacket(Packet packet) + public void AddPacket(RawPacket rawPacket) { _logger.LogInformation("Packet with ID: {MessageOperationCode} has been received", - packet.OperationCode); - _concurrentQueue.Enqueue(packet); - return Task.Run(DequeueAndProcessAsync); + rawPacket.OperationCode); + _concurrentQueue.Enqueue(rawPacket); + Parallel.Invoke(DequeueAndProcessAsync); } - private async Task DequeueAndProcessAsync() + private async void DequeueAndProcessAsync() { - while (!_cancellationTokenSource.IsCancellationRequested) + if (_concurrentQueue.TryDequeue(out var item)) { - if (_concurrentQueue.TryDequeue(out var item)) + Parallel.Invoke(() => { - Parallel.Invoke(() => + _logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued", + item.Session.Id, item.OperationCode); + var packetType = _packetsTypes[item.OperationCode]; + var packet = Activator.CreateInstance(packetType); + packetType.GetFields().AsParallel().ForAll(field => { - var tempId = Guid.NewGuid(); - _logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",tempId, item.OperationCode); - var packetHandler = _actions[item.OperationCode]; - packetHandler.Process(item); - _logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished",tempId, item.OperationCode); + var typeOfField = field.FieldType; + var fieldOffsetAttribute = field.GetCustomAttribute(); + object value; + _logger.LogInformation("Type of field of {fieldName}: {Name}", field.Name, typeOfField.Name); + switch (typeOfField.Name) + { + case nameof(String): + { + value = Encoding.ASCII.GetString(item.MessageBody, fieldOffsetAttribute.Offset, + fieldOffsetAttribute.Size); + break; + } + default: + { + value = 0; + break; + } + } + + field.SetValue(packet, value); }); - } - else - { - await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs - } + var packetHandler = + ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider, + _packetHandlers[item.OperationCode]); + packetHandler.GetType().GetMethod("Handle")?.Invoke(packetHandler, new[] { packet }); + _logger.LogInformation("Packet data {PacketData}", JsonConvert.SerializeObject(packet)); + _logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished", + item.Session.Id, + item.OperationCode); + }); + } + else + { + await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs } } diff --git a/Server/PacketHandler.cs b/Server/PacketHandler.cs index 5d8dedd..36f7538 100644 --- a/Server/PacketHandler.cs +++ b/Server/PacketHandler.cs @@ -1,10 +1,11 @@ namespace Server; -public class PacketHandler : Attribute + +public class PacketId : Attribute { public readonly OperationCode Code; - public PacketHandler(OperationCode code) + public PacketId(OperationCode code) { Code = code; } diff --git a/Server/Packet.cs b/Server/RawPacket.cs similarity index 68% rename from Server/Packet.cs rename to Server/RawPacket.cs index c3795e9..d98e783 100644 --- a/Server/Packet.cs +++ b/Server/RawPacket.cs @@ -3,7 +3,7 @@ namespace Server; [MessageUrn("packets")] -public class Packet +public class RawPacket { public readonly OperationCode OperationCode; public readonly byte[] MessageBody; @@ -12,12 +12,16 @@ public class Packet public readonly byte UnknownValue2; public readonly Guid SessionId; - public Packet(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2, byte unknownValue, Guid sessionId) + public readonly AesSession Session; + + public RawPacket(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2, + byte unknownValue, Guid sessionId, AesSession session) { MessageBody = messageBody; UnknownValue2 = unknownValue2; UnknownValue = unknownValue; SessionId = sessionId; + Session = session; OperationCode = operationCode; ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime); } diff --git a/Server/Server.csproj b/Server/Server.csproj index b1ca7ed..b566037 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -26,6 +26,7 @@ + diff --git a/Server/TextEncodingAttribute.cs b/Server/TextEncodingAttribute.cs new file mode 100644 index 0000000..e606b20 --- /dev/null +++ b/Server/TextEncodingAttribute.cs @@ -0,0 +1,13 @@ +using System.Text; + +namespace Server; + +public class TextEncodingAttribute : Attribute +{ + public Encoding Encoding { get; set; } + + public TextEncodingAttribute(Encoding encoding) + { + Encoding = encoding; + } +} \ No newline at end of file