2023-08-12 21:02:59 +00:00
|
|
|
|
namespace Server.Services;
|
|
|
|
|
|
|
|
|
|
using System.Collections.Concurrent;
|
2023-08-09 14:23:41 +00:00
|
|
|
|
using System.Reflection;
|
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;
|
|
|
|
|
using Newtonsoft.Json;
|
2023-08-12 21:02:59 +00:00
|
|
|
|
using PacketHandlers;
|
|
|
|
|
using Packets;
|
2023-08-13 06:17:20 +00:00
|
|
|
|
using static DotNext.Metaprogramming.CodeGenerator;
|
|
|
|
|
using static DotNext.Linq.Expressions.ExpressionBuilder;
|
2023-08-09 14:23:41 +00:00
|
|
|
|
|
|
|
|
|
public class PacketDistributorService : IHostedService
|
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
private readonly ConcurrentQueue<RawPacket> concurrentQueue;
|
|
|
|
|
private readonly ILogger<PacketDistributorService> logger;
|
|
|
|
|
private readonly Dictionary<OperationCode, Type> packetHandlers;
|
2023-08-13 06:17:20 +00:00
|
|
|
|
private readonly Dictionary<OperationCode, Func<byte[], IPacket>> deserializationMap;
|
2023-08-12 21:02:59 +00:00
|
|
|
|
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
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.concurrentQueue = new ConcurrentQueue<RawPacket>();
|
|
|
|
|
this.logger = logger;
|
|
|
|
|
this.serviceProvider = serviceProvider;
|
|
|
|
|
this.packetHandlers = new Dictionary<OperationCode, Type>();
|
2023-08-13 06:17:20 +00:00
|
|
|
|
this.deserializationMap = new Dictionary<OperationCode, Func<byte[], IPacket>>();
|
2023-08-09 18:14:14 +00:00
|
|
|
|
|
2023-08-11 09:19:43 +00:00
|
|
|
|
var executingAssembly = Assembly.GetExecutingAssembly();
|
2023-08-13 06:17:20 +00:00
|
|
|
|
var packetsTypes = this.GetPacketsWithId(executingAssembly);
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly);
|
2023-08-13 06:17:20 +00:00
|
|
|
|
|
|
|
|
|
foreach (var packetsType in packetsTypes)
|
|
|
|
|
{
|
|
|
|
|
var lambda = Lambda<Func<byte[], IPacket>>(fun =>
|
|
|
|
|
{
|
|
|
|
|
var arg = fun[0];
|
|
|
|
|
var newPacket = packetsType.Value.New();
|
|
|
|
|
|
|
|
|
|
var packetVariable = DeclareVariable(packetsType.Value, "packet");
|
|
|
|
|
Assign(packetVariable, newPacket);
|
2023-08-13 16:29:39 +00:00
|
|
|
|
Call(packetVariable, nameof(IPacket.Deserialize), arg);
|
2023-08-13 06:17:20 +00:00
|
|
|
|
|
|
|
|
|
Return(packetVariable);
|
|
|
|
|
}).Compile();
|
|
|
|
|
logger.LogInformation("Packet creation function created for {Opcode}", packetsType.Key);
|
|
|
|
|
this.deserializationMap.Add(packetsType.Key, lambda);
|
|
|
|
|
}
|
2023-08-11 09:19:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 21:02:59 +00:00
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
|
|
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
|
|
|
|
|
2023-08-11 09:19:43 +00:00
|
|
|
|
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
|
|
|
|
|
{
|
|
|
|
|
var packetsWithId = executingAssembly.GetTypes().AsParallel()
|
2023-08-12 21:02:59 +00:00
|
|
|
|
.Where(type => type.GetCustomAttribute<PacketIdAttribute>() != null && type.HasInterface(typeof(IPacket)) &&
|
2023-08-09 18:14:14 +00:00
|
|
|
|
!type.IsInterface)
|
2023-08-12 21:02:59 +00:00
|
|
|
|
.ToDictionary(packet => packet.GetCustomAttribute<PacketIdAttribute>()!.Code);
|
2023-08-11 09:19:43 +00:00
|
|
|
|
if (packetsWithId is not { Count: 0 })
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-11 09:19:43 +00:00
|
|
|
|
packetsWithId.AsParallel().ForAll(packet =>
|
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogTrace("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key,
|
2023-08-11 09:19:43 +00:00
|
|
|
|
packet.Value.FullName);
|
|
|
|
|
});
|
|
|
|
|
return packetsWithId;
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
2023-08-09 18:14:14 +00:00
|
|
|
|
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogCritical("No Packets have been found");
|
2023-08-11 09:19:43 +00:00
|
|
|
|
throw new IncompleteInitialization();
|
|
|
|
|
}
|
2023-08-09 18:14:14 +00:00
|
|
|
|
|
2023-08-11 09:19:43 +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.IsGenericType && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
|
2023-08-12 21:02:59 +00:00
|
|
|
|
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>().Code);
|
2023-08-09 18:14:14 +00:00
|
|
|
|
|
2023-08-11 09:19:43 +00:00
|
|
|
|
if (packetHandlersWithId is not { Count: 0 })
|
2023-08-09 18:14:14 +00:00
|
|
|
|
{
|
2023-08-11 09:19:43 +00:00
|
|
|
|
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
|
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogTrace("PacketHandler with ID: {PacketID} has been added as {PacketName}",
|
2023-08-11 09:31:30 +00:00
|
|
|
|
packetHandler.Key,
|
2023-08-11 09:19:43 +00:00
|
|
|
|
packetHandler.Value.FullName);
|
|
|
|
|
});
|
|
|
|
|
return packetHandlersWithId;
|
2023-08-09 18:14:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogCritical("No PacketHandlers have been found");
|
2023-08-11 09:19:43 +00:00
|
|
|
|
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
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.concurrentQueue.Enqueue(rawPacket);
|
2023-08-13 20:27:24 +00:00
|
|
|
|
this.DequeueRawPacket();
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
|
2023-08-09 18:14:14 +00:00
|
|
|
|
rawPacket.OperationCode);
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-13 20:27:24 +00:00
|
|
|
|
private void DequeueRawPacket()
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-12 21:02:59 +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-08-11 09:19:43 +00:00
|
|
|
|
{
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
|
2023-08-11 09:19:43 +00:00
|
|
|
|
item.Session.Id, item.OperationCode);
|
2023-08-13 16:29:39 +00:00
|
|
|
|
if (!this.deserializationMap.ContainsKey(item.OperationCode))
|
|
|
|
|
{
|
|
|
|
|
this.logger.LogInformation("Couldn't find Packet type for Id: {Opcode}", item.OperationCode);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var packet = this.deserializationMap[item.OperationCode](item.MessageBody);
|
2023-08-11 09:19:43 +00:00
|
|
|
|
var packetHandler =
|
2023-08-12 21:02:59 +00:00
|
|
|
|
ActivatorUtilities.GetServiceOrCreateInstance(this.serviceProvider,
|
|
|
|
|
this.packetHandlers[item.OperationCode]);
|
2023-08-11 09:19:43 +00:00
|
|
|
|
packetHandler.GetType().GetMethod("HandleAsync")
|
2023-08-11 09:31:30 +00:00
|
|
|
|
?.Invoke(packetHandler, new object[] { packet, item.Session });
|
2023-08-12 21:02:59 +00:00
|
|
|
|
this.logger.LogDebug("Packet data {PacketData}", JsonConvert.SerializeObject(packet));
|
|
|
|
|
this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} has finished",
|
2023-08-11 09:19:43 +00:00
|
|
|
|
item.Session.Id,
|
|
|
|
|
item.OperationCode);
|
|
|
|
|
}
|
2023-08-11 09:31:30 +00:00
|
|
|
|
}
|