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-09 18:14:14 +00:00
|
|
|
|
_concurrentQueue = new ConcurrentQueue<RawPacket>();
|
2023-08-09 14:23:41 +00:00
|
|
|
|
_logger = logger;
|
2023-08-09 18:14:14 +00:00
|
|
|
|
_serviceProvider = serviceProvider;
|
|
|
|
|
_packetHandlers = new Dictionary<OperationCode, Type>();
|
|
|
|
|
_packetsTypes = new Dictionary<OperationCode, Type>();
|
|
|
|
|
|
|
|
|
|
var packetsWithId = Assembly.GetEntryAssembly()?.GetTypes().AsParallel()
|
|
|
|
|
.Where(type => type.GetCustomAttribute<PacketId>() != null && type.HasInterface(typeof(IPacket)) &&
|
|
|
|
|
!type.IsInterface)
|
|
|
|
|
//.Select(Activator.CreateInstance).Cast<IPacket>()
|
|
|
|
|
.ToDictionary(packet => packet.GetCustomAttribute<PacketId>()!.Code);
|
|
|
|
|
|
|
|
|
|
if (packetsWithId == null || packetsWithId.Count == 0)
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-09 18:14:14 +00:00
|
|
|
|
_logger.LogCritical("No Packets have been found");
|
|
|
|
|
throw new IncompleteInitialization();
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
2023-08-09 18:14:14 +00:00
|
|
|
|
|
|
|
|
|
packetsWithId.AsParallel().ForAll(packet =>
|
|
|
|
|
{
|
2023-08-09 20:04:10 +00:00
|
|
|
|
_logger.LogTrace("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key,
|
2023-08-09 18:14:14 +00:00
|
|
|
|
packet.Value.FullName);
|
|
|
|
|
});
|
|
|
|
|
_packetsTypes = packetsWithId;
|
|
|
|
|
|
|
|
|
|
|
2023-08-09 20:04:10 +00:00
|
|
|
|
var packetHandlersWithId = Assembly.GetEntryAssembly()?.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 == null || packetHandlersWithId.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
_logger.LogCritical("No PacketHandlers have been found");
|
|
|
|
|
throw new IncompleteInitialization();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
packetHandlersWithId.AsParallel().ForAll(packetHandler =>
|
|
|
|
|
{
|
2023-08-09 20:04:10 +00:00
|
|
|
|
_logger.LogTrace("Packet with ID: {PacketID} has been added as {PacketName}", packetHandler.Key,
|
2023-08-09 18:14:14 +00:00
|
|
|
|
packetHandler.Value.FullName);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_packetHandlers = packetHandlersWithId;
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task StartAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 18:14:14 +00:00
|
|
|
|
public void AddPacket(RawPacket rawPacket)
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
|
|
|
|
_logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
|
2023-08-09 18:14:14 +00:00
|
|
|
|
rawPacket.OperationCode);
|
|
|
|
|
_concurrentQueue.Enqueue(rawPacket);
|
|
|
|
|
Parallel.Invoke(DequeueAndProcessAsync);
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-08-09 18:14:14 +00:00
|
|
|
|
private async void DequeueAndProcessAsync()
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-09 18:14:14 +00:00
|
|
|
|
if (_concurrentQueue.TryDequeue(out var item))
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-09 18:14:14 +00:00
|
|
|
|
Parallel.Invoke(() =>
|
2023-08-09 14:23:41 +00:00
|
|
|
|
{
|
2023-08-09 20:04:10 +00:00
|
|
|
|
_logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
|
2023-08-09 18:14:14 +00:00
|
|
|
|
item.Session.Id, item.OperationCode);
|
|
|
|
|
var packetType = _packetsTypes[item.OperationCode];
|
2023-08-10 20:07:58 +00:00
|
|
|
|
var packet = (IPacket)Activator.CreateInstance(packetType)!;
|
|
|
|
|
packet.Deserialize(item.MessageBody);
|
2023-08-09 18:14:14 +00:00
|
|
|
|
var packetHandler =
|
|
|
|
|
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
|
|
|
|
|
_packetHandlers[item.OperationCode]);
|
|
|
|
|
packetHandler.GetType().GetMethod("Handle")?.Invoke(packetHandler, new[] { packet });
|
2023-08-09 20:04:10 +00:00
|
|
|
|
_logger.LogDebug("Packet data {PacketData}", JsonConvert.SerializeObject(packet));
|
|
|
|
|
_logger.LogTrace("[{TempId}] Packet with ID: {MessageOperationCode} has finished",
|
2023-08-09 18:14:14 +00:00
|
|
|
|
item.Session.Id,
|
|
|
|
|
item.OperationCode);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs
|
2023-08-09 14:23:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Task StopAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
}
|