Timothy Schenk
85aaec2371
All checks were successful
Build, Package and Push Images / preprocess (push) Successful in 2s
Build, Package and Push Images / build (push) Successful in 32s
Build, Package and Push Images / sbom-scan (push) Successful in 1m2s
Build, Package and Push Images / container-sbom-scan (push) Successful in 40s
Build, Package and Push Images / container-build (push) Successful in 2m2s
Build, Package and Push Images / sonarqube (push) Successful in 2m5s
fix: incorrect command fix: incorrect command fix: incorrect command fix: export tools path chore: test dir fix: test build script fix: missing semicolon fix: missing semicolon fix: missing buildscript fix: missing buildscript chore: update build to .net7 ci: set root dir ci: set root dir revert: .net 8 support for benchmarks ci: disable docker for ci ci: disable docker for ci ci: disable docker for ci ci: trigger ci: i stg ci: let's hope its the correct one ci: i stg ci: further sonarscanner setup ci: add tools ci: rearrange ci: verbose output ci: hardcoded project key ci: test env ci: test more env ci: env test again ci: test env ci: shit ci: final setup ci: final setup ci: final setup ci: adjust buildscript ci: nuke ci: install java ci: install java refactor: loggermessages to own namespace chore: switch to dotnet foundation editorconfig preset ci: switch to basic gitea ci ci: steps ci: add missing runs-on ci: remove unnecessary actions ci: test attempt? ci: add missing name for step ci: fix missing project name reference ci: lets try again ci: again ci: again.. ci: idk at this point ci: append path prematurely ci: add path to bash cli: I really don't know ci: again.... ci: idk ci: again.... ci: another one ci: fix incorrect path add-path ci: add dependency track support ci: fix upload ci: forgot to adjust data for action ci: incorrect path? ci: add version tag ci: idk ci: fix incorrect path for bom ci: fix version tag ci: disable github license resolution for now ci: does this work ci: another one bites the dust chore: .net 8 and extended pipeline support ci: again chore: dockerignore added chore(deps): update dependency benchmarkdotnet to v0.13.10 Signed-off-by: noreply@rainote.dev ci: dependency track can run on any branch ci: first attempt docker image ci: again ci: some fixes ci: idk ci: does this help ci: idk ci: another one ci: forgot ci: downgrade qemu setup ci: downgrade.. ci: v1 includes docker ci: rearrange ci: idk what to do with this ci: let's try cat ci: alt ci: depressing ci: yikes ci: ah come on ci: let's try new version again ci: again ci: another one ci: another one ci: confusion ci: try single ci: aaaa ci: one more time ci: again main (#69) Reviewed-on: #69 Co-authored-by: Timothy Schenk <admin@rainote.dev> Co-committed-by: Timothy Schenk <admin@rainote.dev> chore: ci jobs expanded & .net 8 support ci: branch name sanitization for docker ci: another attempt ci: forgot actor chore: remove nuke remnants chore(deps): update dependency dotnet-sdk to v7.0.403 Signed-off-by: noreply@rainote.dev refactor: shared data into library refactor: rewrite for packethandler/id map chore: logging chore: Sonar Warnings chore: upgrade to .net8 image chore: fetch all required information for characters chore: upgrade to .net 8 ci: install .net 7.0 alongside 8.0 for sbom fix: incorrect job ci: let's try arm64 again ci: adjust project for .net 8 support chore: adjustments to composefile chore: analyzer setup chore: analyzer and project settings updated chore: ci jobs expanded & .net 8 support
157 lines
6.2 KiB
C#
157 lines
6.2 KiB
C#
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<RawPacket> _concurrentQueue;
|
|
|
|
private readonly
|
|
ImmutableDictionary<OperationCode,
|
|
Func<byte[], IPacket>> _deserializationMap;
|
|
|
|
private readonly ILogger<PacketDistributorService> _logger;
|
|
private readonly ConcurrentDictionary<OperationCode, object> _packetHandlersInstantiation;
|
|
|
|
public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
|
|
{
|
|
this._concurrentQueue = new ConcurrentQueue<RawPacket>();
|
|
this._logger = logger;
|
|
var tempDeserializationMap =
|
|
new Dictionary<OperationCode, Func<byte[], IPacket>>();
|
|
|
|
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(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();
|
|
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)
|
|
{
|
|
// ! : 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<PacketIdAttribute>() })
|
|
.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;
|
|
}
|
|
|
|
this._logger.NoPacketsFound();
|
|
throw new IncompleteInitialization();
|
|
}
|
|
|
|
private Dictionary<OperationCode, Type> GetAllPacketHandlersWithId(Assembly assembly)
|
|
{
|
|
// ! : We are filtering if types that don't have an instance of the required Attribute
|
|
var packetHandlersWithId = assembly.GetTypes().AsParallel()
|
|
.Where(t =>
|
|
t is { IsClass: true, IsAbstract: false } && Array.Exists(t
|
|
.GetInterfaces(), i =>
|
|
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketHandler<>)))
|
|
.Select(type => new
|
|
{
|
|
Type = type,
|
|
PacketId = type
|
|
.GetInterfaces().First(t1 =>
|
|
t1 is { IsGenericType: true } && t1.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
|
|
.GetGenericArguments()[0].GetCustomAttribute<PacketIdAttribute>()?.Code
|
|
})
|
|
.Where(x => x.PacketId is not null)
|
|
.ToDictionary(
|
|
x => x.PacketId!.Value, x => x.Type
|
|
);
|
|
|
|
if (packetHandlersWithId is not { Count: 0 })
|
|
{
|
|
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
|
|
this._logger.PacketHandlerWithIdAdded(packetHandler.Key, packetHandler.Value.FullName));
|
|
return packetHandlersWithId;
|
|
}
|
|
|
|
this._logger.NoPacketHandlersFound();
|
|
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);
|
|
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 });
|
|
|
|
this._logger.PacketFinished(item.Session.Id, item.OperationCode);
|
|
}
|
|
}
|