feat: a lot of reflection work
This commit is contained in:
parent
df3aae5d49
commit
2efbbe792c
13 changed files with 182 additions and 59 deletions
|
@ -192,9 +192,11 @@ public abstract class AesSession : TcpSession
|
|||
Console.WriteLine("password: " + Encoding.ASCII.GetString(dataBuffer.ToArray(), 20, 32));
|
||||
Console.WriteLine("Full buffer: " + Encoding.ASCII.GetString(dataBuffer.ToArray()));
|
||||
|
||||
Packet packet = new Packet((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0], buffer[3],
|
||||
Id);
|
||||
Parallel.Invoke(() => _mediator.Send(packet));
|
||||
RawPacket rawPacket = new RawPacket((OperationCode)opCode, dataBuffer, clientAliveTime, buffer[0],
|
||||
buffer[3],
|
||||
Id, this);
|
||||
Parallel.Invoke(() => _mediator.Send(rawPacket));
|
||||
_logger.LogInformation("Connection from: {@RemoteEndpoint}", Socket.RemoteEndPoint);
|
||||
base.OnReceived(decryptedBuffer.ToArray(), offset, decryptedBuffer.Length);
|
||||
}
|
||||
catch (CryptographicException ex)
|
||||
|
|
13
Server/FieldOffsetAttribute.cs
Normal file
13
Server/FieldOffsetAttribute.cs
Normal 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
5
Server/IPacket.cs
Normal file
|
@ -0,0 +1,5 @@
|
|||
namespace Server;
|
||||
|
||||
public interface IPacket
|
||||
{
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
namespace Server;
|
||||
|
||||
public interface IPacketHandler
|
||||
public interface IPacketHandler<T> where T: IPacket
|
||||
{
|
||||
public void Process(Packet packet);
|
||||
public void Handle(T packet);
|
||||
}
|
|
@ -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.");
|
||||
}
|
||||
}
|
18
Server/LoginInfoHandler.cs
Normal file
18
Server/LoginInfoHandler.cs
Normal 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
11
Server/LoginInfoPacket.cs
Normal 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;
|
||||
}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Server;
|
||||
|
||||
public class PacketConsumer : IConsumer<Packet>
|
||||
public class PacketConsumer : IConsumer<RawPacket>
|
||||
{
|
||||
private readonly PacketDistributorService _distributorService;
|
||||
|
||||
|
@ -11,8 +11,9 @@ public class PacketConsumer : IConsumer<Packet>
|
|||
_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;
|
||||
}
|
||||
}
|
|
@ -1,35 +1,74 @@
|
|||
using System.Collections.Concurrent;
|
||||
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.Logging;
|
||||
using Microsoft.VisualBasic.CompilerServices;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Server;
|
||||
|
||||
public class PacketDistributorService : IHostedService
|
||||
{
|
||||
private readonly ConcurrentQueue<Packet> _concurrentQueue;
|
||||
private readonly ConcurrentQueue<RawPacket> _concurrentQueue;
|
||||
private readonly ILogger<PacketDistributorService> _logger;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource = new();
|
||||
private readonly Dictionary<OperationCode, IPacketHandler> _actions;
|
||||
private readonly Dictionary<OperationCode, Type> _packetsTypes;
|
||||
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;
|
||||
_actions = new Dictionary<OperationCode, IPacketHandler>();
|
||||
var packetHandlers = Assembly.GetExecutingAssembly().GetTypes().Where(t =>
|
||||
t.GetCustomAttributes().Any(attribute => attribute.GetType() == typeof(PacketHandler)) &&
|
||||
t.GetInterfaces().Contains(typeof(IPacketHandler)));
|
||||
foreach (var type in packetHandlers)
|
||||
_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)
|
||||
{
|
||||
PacketHandler packetHandler = type.GetCustomAttribute<PacketHandler>()!;
|
||||
_actions.Add(packetHandler.Code,
|
||||
type.GetConstructor( Type.EmptyTypes)
|
||||
.Invoke(null) as IPacketHandler);
|
||||
_logger.LogInformation(
|
||||
"Handler for ID \"{PacketHandlerCode}\" has been added with name \"{PacketHandlerName}\"",
|
||||
packetHandler.Code, type.Name);
|
||||
_logger.LogCritical("No Packets have been found");
|
||||
throw new IncompleteInitialization();
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -37,27 +76,55 @@ public class PacketDistributorService : IHostedService
|
|||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task AddPacket(Packet packet)
|
||||
public void AddPacket(RawPacket rawPacket)
|
||||
{
|
||||
_logger.LogInformation("Packet with ID: {MessageOperationCode} has been received",
|
||||
packet.OperationCode);
|
||||
_concurrentQueue.Enqueue(packet);
|
||||
return Task.Run(DequeueAndProcessAsync);
|
||||
rawPacket.OperationCode);
|
||||
_concurrentQueue.Enqueue(rawPacket);
|
||||
Parallel.Invoke(DequeueAndProcessAsync);
|
||||
}
|
||||
|
||||
private async Task DequeueAndProcessAsync()
|
||||
{
|
||||
while (!_cancellationTokenSource.IsCancellationRequested)
|
||||
private async void DequeueAndProcessAsync()
|
||||
{
|
||||
if (_concurrentQueue.TryDequeue(out var item))
|
||||
{
|
||||
Parallel.Invoke(() =>
|
||||
{
|
||||
var tempId = Guid.NewGuid();
|
||||
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",tempId, item.OperationCode);
|
||||
var packetHandler = _actions[item.OperationCode];
|
||||
packetHandler.Process(item);
|
||||
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} has finished",tempId, item.OperationCode);
|
||||
_logger.LogInformation("[{TempId}] Packet with ID: {MessageOperationCode} is being dequeued",
|
||||
item.Session.Id, item.OperationCode);
|
||||
var packetType = _packetsTypes[item.OperationCode];
|
||||
var packet = Activator.CreateInstance(packetType);
|
||||
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
|
||||
|
@ -65,7 +132,6 @@ public class PacketDistributorService : IHostedService
|
|||
await Task.Delay(100); // Delay to prevent busy-waiting, can be adjusted based on needs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
namespace Server;
|
||||
|
||||
public class PacketHandler : Attribute
|
||||
|
||||
public class PacketId : Attribute
|
||||
{
|
||||
public readonly OperationCode Code;
|
||||
|
||||
public PacketHandler(OperationCode code)
|
||||
public PacketId(OperationCode code)
|
||||
{
|
||||
Code = code;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
namespace Server;
|
||||
|
||||
[MessageUrn("packets")]
|
||||
public class Packet
|
||||
public class RawPacket
|
||||
{
|
||||
public readonly OperationCode OperationCode;
|
||||
public readonly byte[] MessageBody;
|
||||
|
@ -12,12 +12,16 @@ public class Packet
|
|||
public readonly byte UnknownValue2;
|
||||
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;
|
||||
UnknownValue2 = unknownValue2;
|
||||
UnknownValue = unknownValue;
|
||||
SessionId = sessionId;
|
||||
Session = session;
|
||||
OperationCode = operationCode;
|
||||
ClientAliveTime = TimeSpan.FromSeconds(5 * aliveTime);
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="7.0.0" />
|
||||
<PackageReference Include="NetCoreServer" Version="7.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
13
Server/TextEncodingAttribute.cs
Normal file
13
Server/TextEncodingAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue