continuity/Server/Services/PacketDistributorService.cs

143 lines
6.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 System.Text;
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;
using FieldAccessException = System.FieldAccessException;
2023-08-09 14:23:41 +00:00
namespace Server;
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 =>
{
_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;
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 =>
{
_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
{
_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];
var packet = Activator.CreateInstance(packetType);
packetType.GetFields().AsParallel().ForAll(field =>
2023-08-09 14:23:41 +00:00
{
2023-08-09 18:14:14 +00:00
var typeOfField = field.FieldType;
var fieldOffsetAttribute = field.GetCustomAttribute<FieldOffsetAttribute>();
if (fieldOffsetAttribute == null)
throw new FieldAccessException();
2023-08-09 18:14:14 +00:00
object value;
_logger.LogDebug("Type of field of {fieldName}: {Name}", field.Name, typeOfField.Name);
value = typeOfField.Name switch
2023-08-09 18:14:14 +00:00
{
nameof(String) => Encoding.ASCII.GetString(item.MessageBody, fieldOffsetAttribute.Offset,
fieldOffsetAttribute.Size),
"Byte[]" => new ArraySegment<byte>(item.MessageBody, fieldOffsetAttribute.Offset,
fieldOffsetAttribute.Size).ToArray(),
nameof(Boolean) => BitConverter.ToBoolean(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(Byte) => item.MessageBody[fieldOffsetAttribute.Offset],
nameof(Int16) => BitConverter.ToInt16(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(UInt16) => BitConverter.ToUInt16(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(Int32) => BitConverter.ToInt32(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(UInt32) => BitConverter.ToUInt32(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(Double) => BitConverter.ToDouble(item.MessageBody, fieldOffsetAttribute.Offset),
nameof(Single) => BitConverter.ToSingle(item.MessageBody, fieldOffsetAttribute.Offset),
_ => throw new InvalidOperationException()
};
2023-08-09 18:14:14 +00:00
field.SetValue(packet, value);
2023-08-09 14:23:41 +00:00
});
2023-08-09 18:14:14 +00:00
var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
_packetHandlers[item.OperationCode]);
packetHandler.GetType().GetMethod("Handle")?.Invoke(packetHandler, new[] { packet });
_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;
}
}