continuity/Server/Services/PacketDistributorService.cs

146 lines
5.9 KiB
C#
Raw Normal View History

2023-10-12 07:15:34 +00:00
namespace Server.Services;
using System.Collections.Concurrent;
using System.Collections.Immutable;
2023-08-09 14:23:41 +00:00
using System.Reflection;
using DotNext.Collections.Generic;
2023-08-09 18:14:14 +00:00
using MassTransit.Internals;
using Microsoft.Extensions.DependencyInjection;
2023-08-09 14:23:41 +00:00
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
2023-08-09 18:14:14 +00:00
using Microsoft.VisualBasic.CompilerServices;
2023-08-14 20:30:35 +00:00
using Newtonsoft.Json;
using PacketHandlers;
using Packets;
using static DotNext.Linq.Expressions.ExpressionBuilder;
2023-10-12 07:15:34 +00:00
using static DotNext.Metaprogramming.CodeGenerator;
2023-08-09 14:23:41 +00:00
public class PacketDistributorService : IHostedService
{
private readonly ConcurrentQueue<RawPacket> concurrentQueue;
private readonly
ImmutableDictionary<OperationCode,
Func<byte[], IPacket>> deserializationMap;
2023-08-14 19:30:32 +00:00
private readonly ILogger<PacketDistributorService> logger;
private readonly ConcurrentDictionary<OperationCode, object> packetHandlersInstantiation;
private readonly IServiceProvider serviceProvider;
2023-08-09 14:23:41 +00:00
2023-08-09 18:14:14 +00:00
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
2023-08-09 14:23:41 +00:00
{
this.concurrentQueue = new ConcurrentQueue<RawPacket>();
this.logger = logger;
this.serviceProvider = serviceProvider;
var tempDeserializationMap =
new Dictionary<OperationCode, Func<byte[], IPacket>>();
2023-08-09 18:14:14 +00:00
var executingAssembly = Assembly.GetExecutingAssembly();
var packetsTypes = this.GetPacketsWithId(executingAssembly);
var packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly);
this.packetHandlersInstantiation = new ConcurrentDictionary<OperationCode, object>();
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<Func<byte[], IPacket>>(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();
2023-10-27 15:40:58 +00:00
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<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
{
2023-10-27 15:40:58 +00:00
// ! : We are filtering if types that don't have an instance of the required Attribute
var packetsWithId = executingAssembly.GetTypes().AsParallel()
2023-10-27 15:40:58 +00:00
.Where(type => type.HasInterface(typeof(IPacket)) && type is { IsInterface: false, IsAbstract: false })
.Select(type => new { Type = type, Attribute = type.GetCustomAttribute<PacketIdAttribute>() })
.Where(item => item.Attribute is not null)
.ToDictionary(item => item.Attribute!.Code, item => item.Type);
if (packetsWithId is not { Count: 0 })
2023-08-09 14:23:41 +00:00
{
2023-10-27 15:40:58 +00:00
packetsWithId.AsParallel()
.ForAll(packet => this.logger.PacketWithIdAdded(packet.Key, packet.Value.FullName));
return packetsWithId;
2023-08-09 14:23:41 +00:00
}
2023-08-09 18:14:14 +00:00
2023-10-27 15:40:58 +00:00
this.logger.NoPacketsFound();
throw new IncompleteInitialization();
}
2023-08-09 18:14:14 +00:00
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
{
var packetHandlersWithId = assembly.GetTypes().AsParallel().Where(t =>
2023-08-09 18:14:14 +00:00
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<>))
2023-10-12 07:15:34 +00:00
.GetGenericArguments().First().GetCustomAttribute<PacketIdAttribute>().Code);
2023-08-09 18:14:14 +00:00
if (packetHandlersWithId is not { Count: 0 })
2023-08-09 18:14:14 +00:00
{
2023-10-27 15:40:58 +00:00
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
this.logger.PacketHandlerWithIdAdded(packetHandler.Key, packetHandler.Value.FullName));
return packetHandlersWithId;
2023-08-09 18:14:14 +00:00
}
2023-10-27 15:40:58 +00:00
this.logger.NoPacketHandlersFound();
throw new IncompleteInitialization();
2023-08-09 14:23:41 +00:00
}
2023-08-09 18:14:14 +00:00
public void AddPacket(RawPacket rawPacket)
2023-08-09 14:23:41 +00:00
{
this.concurrentQueue.Enqueue(rawPacket);
this.DequeueRawPacket();
2023-10-27 15:40:58 +00:00
this.logger.PacketReceived(rawPacket.OperationCode);
2023-08-09 14:23:41 +00:00
}
private void DequeueRawPacket()
2023-08-09 14:23:41 +00:00
{
if (this.concurrentQueue.TryDequeue(out var item))
2023-08-09 14:23:41 +00:00
{
2023-08-13 12:22:34 +00:00
ThreadPool.QueueUserWorkItem(this.InvokePacketHandler, item, true);
2023-08-09 18:14:14 +00:00
}
2023-08-09 14:23:41 +00:00
}
2023-08-13 16:29:39 +00:00
private void InvokePacketHandler(RawPacket item)
{
2023-10-27 15:40:58 +00:00
this.logger.PacketDequeued(item.Session.Id, item.OperationCode);
2023-08-13 16:29:39 +00:00
if (!this.deserializationMap.ContainsKey(item.OperationCode))
{
2023-10-27 15:40:58 +00:00
this.logger.PacketTypeNotFound(item.OperationCode);
2023-08-13 16:29:39 +00:00
return;
}
var packet = this.deserializationMap[item.OperationCode](item.MessageBody);
2023-10-27 15:40:58 +00:00
this.logger.PacketData(JsonConvert.SerializeObject(packet));
this.packetHandlersInstantiation[item.OperationCode].GetType().GetMethod(nameof(IPacketHandler<IPacket>.HandleAsync))
?.Invoke(this.packetHandlersInstantiation[item.OperationCode], new object[] { packet, item.Session });
2023-10-27 15:40:58 +00:00
this.logger.PacketFinished(item.Session.Id, item.OperationCode);
}
2023-08-11 09:31:30 +00:00
}