continuity/Server/Services/PacketDistributorService.cs

121 lines
5 KiB
C#
Raw Normal View History

2023-08-09 14:23:41 +00:00
using System.Collections.Concurrent;
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-10 08:47:35 +00:00
using Server.PacketHandlers;
using Server.Packets;
2023-08-09 14:23:41 +00:00
2023-08-10 08:47:35 +00:00
namespace Server.Services;
2023-08-09 14:23:41 +00:00
public class PacketDistributorService : IHostedService
{
2023-08-09 18:14:14 +00:00
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
2023-08-09 14:23:41 +00:00
private readonly ILogger<PacketDistributorService> _logger;
2023-08-09 18:14:14 +00:00
private readonly Dictionary<OperationCode, Type> _packetsTypes;
private readonly Dictionary<OperationCode, Type> _packetHandlers;
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-11 09:31:30 +00:00
this._concurrentQueue = new ConcurrentQueue<RawPacket>();
this._logger = logger;
this._serviceProvider = serviceProvider;
this._packetHandlers = new Dictionary<OperationCode, Type>();
this._packetsTypes = new Dictionary<OperationCode, Type>();
2023-08-09 18:14:14 +00:00
var executingAssembly = Assembly.GetExecutingAssembly();
2023-08-11 09:31:30 +00:00
this._packetsTypes = this.GetPacketsWithId(executingAssembly);
this._packetHandlers = this.GetAllPacketHandlersWithId(executingAssembly);
}
private Dictionary<OperationCode, Type> GetPacketsWithId(Assembly executingAssembly)
{
var packetsWithId = executingAssembly.GetTypes().AsParallel()
2023-08-09 18:14:14 +00:00
.Where(type => type.GetCustomAttribute<PacketId>() != null && type.HasInterface(typeof(IPacket)) &&
!type.IsInterface)
.ToDictionary(packet => packet.GetCustomAttribute<PacketId>()!.Code);
if (packetsWithId is not { Count: 0 })
2023-08-09 14:23:41 +00:00
{
packetsWithId.AsParallel().ForAll(packet =>
{
2023-08-11 09:31:30 +00:00
this._logger.LogTrace("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key,
packet.Value.FullName);
});
return packetsWithId;
2023-08-09 14:23:41 +00:00
}
2023-08-09 18:14:14 +00:00
2023-08-11 09:31:30 +00:00
this._logger.LogCritical("No Packets have been found");
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.IsGenericType && t.GetGenericTypeDefinition() == typeof(IPacketHandler<>))
.GetGenericArguments()[0].GetCustomAttribute<PacketId>().Code);
if (packetHandlersWithId is not { Count: 0 })
2023-08-09 18:14:14 +00:00
{
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
{
2023-08-11 09:31:30 +00:00
this._logger.LogTrace("PacketHandler with ID: {PacketID} has been added as {PacketName}",
packetHandler.Key,
packetHandler.Value.FullName);
});
return packetHandlersWithId;
2023-08-09 18:14:14 +00:00
}
2023-08-11 09:31:30 +00:00
this._logger.LogCritical("No PacketHandlers have been found");
throw new IncompleteInitialization();
2023-08-09 14:23:41 +00:00
}
2023-08-11 09:31:30 +00:00
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
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-11 09:31:30 +00:00
this._concurrentQueue.Enqueue(rawPacket);
Task.Run(() => this.DequeueRawPacketAsync());
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
}
private async Task DequeueRawPacketAsync()
2023-08-09 14:23:41 +00:00
{
2023-08-11 09:31:30 +00:00
if (this._concurrentQueue.TryDequeue(out var item))
2023-08-09 14:23:41 +00:00
{
2023-08-11 09:31:30 +00:00
Task.Run(() => { this.InvokePacketHandler(item); });
2023-08-09 18:14:14 +00:00
}
else
{
await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs
2023-08-09 14:23:41 +00:00
}
}
private void InvokePacketHandler(RawPacket? item)
{
2023-08-11 09:31:30 +00:00
this._logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
item.Session.Id, item.OperationCode);
2023-08-11 09:31:30 +00:00
var packetType = this._packetsTypes[item.OperationCode];
var packet = (IPacket)Activator.CreateInstance(packetType)!;
packet.Deserialize(item.MessageBody);
var packetHandler =
2023-08-11 09:31:30 +00:00
ActivatorUtilities.GetServiceOrCreateInstance(this._serviceProvider,
this._packetHandlers[item.OperationCode]);
packetHandler.GetType().GetMethod("HandleAsync")
2023-08-11 09:31:30 +00:00
?.Invoke(packetHandler, new object[] { packet, item.Session });
this._logger.LogDebug("Packet data {PacketData}", JsonConvert.SerializeObject(packet));
this._logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} has finished",
item.Session.Id,
item.OperationCode);
}
2023-08-11 09:31:30 +00:00
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}