feat: dynamic packet init function creation with deserialization.

This commit is contained in:
Timothy Schenk 2023-08-13 08:17:20 +02:00
parent c6341cb487
commit 0b3f543c69
3 changed files with 30 additions and 7 deletions

View file

@ -18,7 +18,7 @@ public enum LoginResponseReason : byte
NoMoreTries, NoMoreTries,
XMLError12, XMLError12,
XMLRPCError, XMLRPCError,
FileLoadFail, // Maybe more data :) FileLoadFail, // arbitrary file load error (maybe we're able to load custom files)
ThisIsNotAServiceArea, ThisIsNotAServiceArea,
None None
} }

View file

@ -19,6 +19,9 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="CouchDB.NET" Version="3.4.0"/> <PackageReference Include="CouchDB.NET" Version="3.4.0"/>
<PackageReference Include="CouchDB.NET.DependencyInjection" Version="3.4.0"/> <PackageReference Include="CouchDB.NET.DependencyInjection" Version="3.4.0"/>
<PackageReference Include="DotNext" Version="4.13.1" />
<PackageReference Include="DotNext.Metaprogramming" Version="4.13.1" />
<PackageReference Include="DotNext.Reflection" Version="4.9.0" />
<PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2"> <PackageReference Include="ErrorProne.NET.CoreAnalyzers" Version="0.1.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

View file

@ -1,7 +1,10 @@
namespace Server.Services; namespace Server.Services;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection; using System.Reflection;
using DotNext;
using DotNext.Metaprogramming;
using MassTransit.Internals; using MassTransit.Internals;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -10,13 +13,15 @@ using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json; using Newtonsoft.Json;
using PacketHandlers; using PacketHandlers;
using Packets; using Packets;
using static DotNext.Metaprogramming.CodeGenerator;
using static DotNext.Linq.Expressions.ExpressionBuilder;
public class PacketDistributorService : IHostedService public class PacketDistributorService : IHostedService
{ {
private readonly ConcurrentQueue<RawPacket> concurrentQueue; private readonly ConcurrentQueue<RawPacket> concurrentQueue;
private readonly ILogger<PacketDistributorService> logger; private readonly ILogger<PacketDistributorService> logger;
private readonly Dictionary<OperationCode, Type> packetHandlers; private readonly Dictionary<OperationCode, Type> packetHandlers;
private readonly Dictionary<OperationCode, Type> packetsTypes; private readonly Dictionary<OperationCode, Func<byte[], IPacket>> deserializationMap;
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider) public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
@ -25,11 +30,28 @@ public class PacketDistributorService : IHostedService
this.logger = logger; this.logger = logger;
this.serviceProvider = serviceProvider; this.serviceProvider = serviceProvider;
this.packetHandlers = new Dictionary<OperationCode, Type>(); this.packetHandlers = new Dictionary<OperationCode, Type>();
this.packetsTypes = new Dictionary<OperationCode, Type>(); this.deserializationMap = new Dictionary<OperationCode, Func<byte[], IPacket>>();
var executingAssembly = Assembly.GetExecutingAssembly(); var executingAssembly = Assembly.GetExecutingAssembly();
this.packetsTypes = this.GetPacketsWithId(executingAssembly); var packetsTypes = this.GetPacketsWithId(executingAssembly);
this.packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly); this.packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly);
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);
Call(packetVariable, packetsType.Value.GetMethod("Deserialize"), arg);
Return(packetVariable);
}).Compile();
logger.LogInformation("Packet creation function created for {Opcode}", packetsType.Key);
this.deserializationMap.Add(packetsType.Key, lambda);
}
} }
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask; public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
@ -104,9 +126,7 @@ public class PacketDistributorService : IHostedService
{ {
this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued", this.logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
item.Session.Id, item.OperationCode); item.Session.Id, item.OperationCode);
var packetType = this.packetsTypes[item.OperationCode]; var packet = this.deserializationMap[item.OperationCode].Invoke(item.MessageBody);
var packet = (IPacket)Activator.CreateInstance(packetType)!;
packet.Deserialize(item.MessageBody);
var packetHandler = var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(this.serviceProvider, ActivatorUtilities.GetServiceOrCreateInstance(this.serviceProvider,
this.packetHandlers[item.OperationCode]); this.packetHandlers[item.OperationCode]);