using Server.LoggerMessages; using Wonderking.Packets; namespace Server.Services; using System.Collections.Concurrent; using System.Collections.Immutable; using System.Reflection; using DotNext.Collections.Generic; using MassTransit.Internals; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.VisualBasic.CompilerServices; using Newtonsoft.Json; using PacketHandlers; using Packets; using static DotNext.Linq.Expressions.ExpressionBuilder; using static DotNext.Metaprogramming.CodeGenerator; public class PacketDistributorService : IHostedService { private readonly ConcurrentQueue _concurrentQueue; private readonly ImmutableDictionary> _deserializationMap; private readonly ILogger _logger; private readonly ConcurrentDictionary _packetHandlersInstantiation; private readonly IServiceProvider _serviceProvider; public PacketDistributorService(ILogger logger, IServiceProvider serviceProvider) { this._concurrentQueue = new ConcurrentQueue(); this._logger = logger; this._serviceProvider = serviceProvider; var tempDeserializationMap = new Dictionary>(); var executingAssembly = Assembly.GetExecutingAssembly(); var packetsTypes = this.GetPacketsWithId(executingAssembly); var packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly); this._packetHandlersInstantiation = new ConcurrentDictionary(); packetHandlers.ForEach(x => { var packetHandler = ActivatorUtilities.GetServiceOrCreateInstance(this._serviceProvider, x.Value); this._packetHandlersInstantiation.TryAdd(x.Key, packetHandler); }); foreach (var packetsType in packetsTypes) { var lambda = Lambda>(fun => { var argPacketData = fun[0]; var newPacket = packetsType.Value.New(); var packetVariable = DeclareVariable(packetsType.Value, "packet"); Assign(packetVariable, newPacket); Call(packetVariable, nameof(IPacket.Deserialize), argPacketData); Return(packetVariable); }).Compile(); logger.PacketCreationFunctionCreated(packetsType.Key); tempDeserializationMap.Add(packetsType.Key, lambda); } this._deserializationMap = tempDeserializationMap.ToImmutableDictionary(); } public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; private Dictionary GetPacketsWithId(Assembly executingAssembly) { // ! : We are filtering if types that don't have an instance of the required Attribute var packetsWithId = executingAssembly.GetTypes().AsParallel() .Where(type => type.HasInterface(typeof(IPacket)) && type is { IsInterface: false, IsAbstract: false }) .Select(type => new { Type = type, Attribute = type.GetCustomAttribute() }) .Where(item => item.Attribute is not null) .ToDictionary(item => item.Attribute!.Code, item => item.Type); if (packetsWithId is not { Count: 0 }) { packetsWithId.AsParallel() .ForAll(packet => this._logger.PacketWithIdAdded(packet.Key, packet.Value.FullName)); return packetsWithId; } LoggerMessages.PacketLoggerMessages.NoPacketsFound(this._logger); throw new IncompleteInitialization(); } private Dictionary GetAllPacketHandlersWithId(Assembly assembly) { var packetHandlersWithId = assembly.GetTypes().AsParallel().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 is { IsGenericType: true } && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>)) .GetGenericArguments().First().GetCustomAttribute().Code); if (packetHandlersWithId is not { Count: 0 }) { packetHandlersWithId.AsParallel().ForAll(packetHandler => this._logger.PacketHandlerWithIdAdded(packetHandler.Key, packetHandler.Value.FullName)); return packetHandlersWithId; } LoggerMessages.PacketLoggerMessages.NoPacketHandlersFound(this._logger); throw new IncompleteInitialization(); } public void AddPacket(RawPacket rawPacket) { this._concurrentQueue.Enqueue(rawPacket); this.DequeueRawPacket(); this._logger.PacketReceived(rawPacket.OperationCode); } private void DequeueRawPacket() { if (this._concurrentQueue.TryDequeue(out var item)) { ThreadPool.QueueUserWorkItem(this.InvokePacketHandler, item, true); } } private void InvokePacketHandler(RawPacket item) { this._logger.PacketDequeued(item.Session.Id, item.OperationCode); if (!this._deserializationMap.TryGetValue(item.OperationCode, out var value)) { this._logger.PacketTypeNotFound(item.OperationCode); return; } var packet = value(item.MessageBody); LoggerMessages.PacketLoggerMessages.PacketData(this._logger, JsonConvert.SerializeObject(packet)); this._packetHandlersInstantiation[item.OperationCode].GetType() .GetMethod(nameof(IPacketHandler.HandleAsync)) ?.Invoke(this._packetHandlersInstantiation[item.OperationCode], new object[] { packet, item.Session }); this._logger.PacketFinished(item.Session.Id, item.OperationCode); } }