feat: a lot of reflection work

This commit is contained in:
Timothy Schenk 2023-08-09 20:14:14 +02:00
parent df3aae5d49
commit 2efbbe792c
13 changed files with 182 additions and 59 deletions

View file

@ -192,9 +192,11 @@ public abstract class AesSession : TcpSession
Console.WriteLine("password: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 20, 32)); Console.WriteLine("password: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 20, 32));
Console.WriteLine("Full buffer: " + Encoding.ASCII.GetString(dataBuffer.ToArray())); Console.WriteLine("Full buffer: " + Encoding.ASCII.GetString(dataBuffer.ToArray()));
Packet packet = new Packet((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0], buffer[3], RawPacket rawPacket = new RawPacket((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0],
Id); buffer[3],
Parallel.Invoke(() => _mediator.Send(packet)); Id, this);
Parallel.Invoke(() => _mediator.Send(rawPacket));
_logger.LogInformation("Connection from: {@RemoteEndpoint}", Socket.RemoteEndPoint);
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length); base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
} }
catch (CryptographicException ex) catch (CryptographicException ex)

View file

@ -0,0 +1,13 @@
namespace Server;
public class FieldOffsetAttribute : Attribute
{
public int Offset { get; set; }
public int Size { get; set; }
public FieldOffsetAttribute(int offset, int size)
{
Offset = offset;
Size = size;
}
}

5
Server/IPacket.cs Normal file
View file

@ -0,0 +1,5 @@
namespace Server;
public interface IPacket
{
}

View file

@ -1,6 +1,6 @@
namespace Server; namespace Server;
public interface IPacketHandler public interface IPacketHandler<T> where T: IPacket
{ {
public void Process(Packet packet); public void Handle(T packet);
} }

View file

@ -1,12 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
namespace Server;
[PacketHandler(OperationCode.LoginInfo)]
public class LoginHandler : IPacketHandler
{
public void Process(Packet packet)
{
Console.WriteLine("Login being processed.");
}
}

View file

@ -0,0 +1,18 @@
using Microsoft.Extensions.Logging;
namespace Server;
public class LoginHandler : IPacketHandler<LoginInfoPacket>
{
private readonly ILogger<LoginHandler> _logger;
public LoginHandler(ILogger<LoginHandler> logger)
{
_logger = logger;
}
public void Handle(LoginInfoPacket packet)
{
_logger.LogInformation("Login data: Username {Username} & Password {Password}", packet.Username, packet.Password);
}
}

11
Server/LoginInfoPacket.cs Normal file
View file

@ -0,0 +1,11 @@
using System.Runtime.InteropServices;
namespace Server;
[PacketId(OperationCode.LoginInfo)]
public class LoginInfoPacket : IPacket
{
[FieldOffset(0, 20)] public string Username;
[FieldOffset(20, 31)] public string Password;
}

View file

@ -2,7 +2,7 @@
namespace Server; namespace Server;
public class PacketConsumer : IConsumer<Packet> public class PacketConsumer : IConsumer<RawPacket>
{ {
private readonly PacketDistributorService _distributorService; private readonly PacketDistributorService _distributorService;
@ -11,8 +11,9 @@ public class PacketConsumer : IConsumer<Packet>
_distributorService = distributorService; _distributorService = distributorService;
} }
public Task Consume(ConsumeContext<Packet> context) public Task Consume(ConsumeContext<RawPacket> context)
{ {
return _distributorService.AddPacket(context.Message); _distributorService.AddPacket(context.Message);
return Task.CompletedTask;
} }
} }

View file

@ -1,35 +1,74 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using MassTransit.Internals;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
namespace Server; namespace Server;
public class PacketDistributorService : IHostedService public class PacketDistributorService : IHostedService
{ {
private readonly ConcurrentQueue<Packet> _concurrentQueue; private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
private readonly ILogger<PacketDistributorService> _logger; private readonly ILogger<PacketDistributorService> _logger;
private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly Dictionary<OperationCode, Type> _packetsTypes;
private readonly Dictionary<OperationCode, IPacketHandler> _actions; private readonly Dictionary<OperationCode, Type> _packetHandlers;
private readonly IServiceProvider _serviceProvider;
public PacketDistributorService(ILogger<PacketDistributorService> logger) public PacketDistributorService(ILogger<PacketDistributorService> logger, IServiceProvider serviceProvider)
{ {
_concurrentQueue = new ConcurrentQueue<Packet>(); _concurrentQueue = new ConcurrentQueue<RawPacket>();
_logger = logger; _logger = logger;
_actions = new Dictionary<OperationCode, IPacketHandler>(); _serviceProvider = serviceProvider;
var packetHandlers = Assembly.GetExecutingAssembly().GetTypes().Where(t => _packetHandlers = new Dictionary<OperationCode, Type>();
t.GetCustomAttributes().Any(attribute => attribute.GetType() == typeof(PacketHandler)) && _packetsTypes = new Dictionary<OperationCode, Type>();
t.GetInterfaces().Contains(typeof(IPacketHandler)));
foreach (var type in packetHandlers) 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)
{ {
PacketHandler packetHandler = type.GetCustomAttribute<PacketHandler>()!; _logger.LogCritical("No Packets have been found");
_actions.Add(packetHandler.Code, throw new IncompleteInitialization();
type.GetConstructor( Type.EmptyTypes)
.Invoke(null) as IPacketHandler);
_logger.LogInformation(
"Handler for ID \"{PacketHandlerCode}\" has been added with name \"{PacketHandlerName}\"",
packetHandler.Code, type.Name);
} }
packetsWithId.AsParallel().ForAll(packet =>
{
_logger.LogInformation("Packet with ID: {PacketID} has been added as {PacketName}", packet.Key,
packet.Value.FullName);
});
_packetsTypes = packetsWithId;
var packetHandlersWithId = Assembly.GetEntryAssembly()?.GetTypes().Where(t =>
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.LogInformation("Packet with ID: {PacketID} has been added as {PacketName}", packetHandler.Key,
packetHandler.Value.FullName);
});
_packetHandlers = packetHandlersWithId;
} }
public Task StartAsync(CancellationToken cancellationToken) public Task StartAsync(CancellationToken cancellationToken)
@ -37,27 +76,55 @@ public class PacketDistributorService : IHostedService
return Task.CompletedTask; return Task.CompletedTask;
} }
public Task AddPacket(Packet packet) public void AddPacket(RawPacket rawPacket)
{ {
_logger.LogInformation("Packet with ID: {MessageOperationCode} has been received", _logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
packet.OperationCode); rawPacket.OperationCode);
_concurrentQueue.Enqueue(packet); _concurrentQueue.Enqueue(rawPacket);
return Task.Run(DequeueAndProcessAsync); Parallel.Invoke(DequeueAndProcessAsync);
} }
private async Task DequeueAndProcessAsync() private async void DequeueAndProcessAsync()
{
while (!_cancellationTokenSource.IsCancellationRequested)
{ {
if (_concurrentQueue.TryDequeue(out var item)) if (_concurrentQueue.TryDequeue(out var item))
{ {
Parallel.Invoke(() => Parallel.Invoke(() =>
{ {
var tempId = Guid.NewGuid(); _logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",tempId, item.OperationCode); item.Session.Id, item.OperationCode);
var packetHandler = _actions[item.OperationCode]; var packetType = _packetsTypes[item.OperationCode];
packetHandler.Process(item); var packet = Activator.CreateInstance(packetType);
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished",tempId, item.OperationCode); packetType.GetFields().AsParallel().ForAll(field =>
{
var typeOfField = field.FieldType;
var fieldOffsetAttribute = field.GetCustomAttribute<FieldOffsetAttribute>();
object value;
_logger.LogInformation("Type of field of {fieldName}: {Name}", field.Name, typeOfField.Name);
switch (typeOfField.Name)
{
case nameof(String):
{
value = Encoding.ASCII.GetString(item.MessageBody, fieldOffsetAttribute.Offset,
fieldOffsetAttribute.Size);
break;
}
default:
{
value = 0;
break;
}
}
field.SetValue(packet, value);
});
var packetHandler =
ActivatorUtilities.GetServiceOrCreateInstance(_serviceProvider,
_packetHandlers[item.OperationCode]);
packetHandler.GetType().GetMethod("Handle")?.Invoke(packetHandler, new[] { packet });
_logger.LogInformation("Packet data {PacketData}", JsonConvert.SerializeObject(packet));
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished",
item.Session.Id,
item.OperationCode);
}); });
} }
else else
@ -65,7 +132,6 @@ public class PacketDistributorService : IHostedService
await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs
} }
} }
}
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)
{ {

View file

@ -1,10 +1,11 @@
namespace Server; namespace Server;
public class PacketHandler : Attribute
public class PacketId : Attribute
{ {
public readonly OperationCode Code; public readonly OperationCode Code;
public PacketHandler(OperationCode code) public PacketId(OperationCode code)
{ {
Code = code; Code = code;
} }

View file

@ -3,7 +3,7 @@
namespace Server; namespace Server;
[MessageUrn("packets")] [MessageUrn("packets")]
public class Packet public class RawPacket
{ {
public readonly OperationCode OperationCode; public readonly OperationCode OperationCode;
public readonly byte[] MessageBody; public readonly byte[] MessageBody;
@ -12,12 +12,16 @@ public class Packet
public readonly byte UnknownValue2; public readonly byte UnknownValue2;
public readonly Guid SessionId; public readonly Guid SessionId;
public Packet(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2, byte unknownValue, Guid sessionId) public readonly AesSession Session;
public RawPacket(OperationCode operationCode, byte[] messageBody, uint aliveTime, byte unknownValue2,
byte unknownValue, Guid sessionId, AesSession session)
{ {
MessageBody = messageBody; MessageBody = messageBody;
UnknownValue2 = unknownValue2; UnknownValue2 = unknownValue2;
UnknownValue = unknownValue; UnknownValue = unknownValue;
SessionId = sessionId; SessionId = sessionId;
Session = session;
OperationCode = operationCode; OperationCode = operationCode;
ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime); ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime);
} }

View file

@ -26,6 +26,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
<PackageReference Include="NetCoreServer" Version="7.0.0" /> <PackageReference Include="NetCoreServer" Version="7.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -0,0 +1,13 @@
using System.Text;
namespace Server;
public class TextEncodingAttribute : Attribute
{
public Encoding Encoding { get; set; }
public TextEncodingAttribute(Encoding encoding)
{
Encoding = encoding;
}
}