73 lines
2.7 KiB
C#
73 lines
2.7 KiB
C#
using System.Collections.Immutable;
|
|
using System.Linq.Expressions;
|
|
using System.Reflection;
|
|
using Google.Protobuf;
|
|
using Microsoft.Extensions.Logging;
|
|
using RPG.Network.Proto;
|
|
using RPG.Services.Core.Network.Attributes;
|
|
|
|
namespace RPG.Services.Core.Network.Command;
|
|
public abstract class ServiceCommandHandler
|
|
{
|
|
private delegate Task HandlerDelegate(ServiceCommand command);
|
|
private readonly ImmutableDictionary<ServiceCommandType, HandlerDelegate> _handlers;
|
|
|
|
private readonly ILogger _logger;
|
|
private readonly ServiceBox _services;
|
|
|
|
public ServiceCommandHandler(ILogger<ServiceCommandHandler> logger, ServiceBox services)
|
|
{
|
|
_logger = logger;
|
|
_services = services;
|
|
_handlers = MapHandlers();
|
|
}
|
|
|
|
public async Task HandleAsync(ServiceCommand command)
|
|
{
|
|
if (_handlers.TryGetValue(command.CommandType, out HandlerDelegate? handler))
|
|
{
|
|
try
|
|
{
|
|
await handler(command);
|
|
}
|
|
catch (Exception handlingException)
|
|
{
|
|
_logger.LogError("Exception occurred while handling ServiceCommand of type {type}, trace:\n{exception}", command.CommandType, handlingException);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_logger.LogWarning("Handler for service command of type {type} not found!", command.CommandType);
|
|
}
|
|
}
|
|
|
|
protected void Send<TBody>(ServiceCommandType commandType, TBody body, RPGServiceType target) where TBody : IMessage<TBody>
|
|
{
|
|
ServiceCommand command = new(_services.CurrentType, commandType, body.ToByteArray());
|
|
|
|
byte[] buffer = GC.AllocateUninitializedArray<byte>(command.Body.Length + 7);
|
|
ServiceCommandEncoder.EncodeCommand(command, buffer);
|
|
|
|
_services.SendToService(target, buffer);
|
|
}
|
|
|
|
private ImmutableDictionary<ServiceCommandType, HandlerDelegate> MapHandlers()
|
|
{
|
|
var builder = ImmutableDictionary.CreateBuilder<ServiceCommandType, HandlerDelegate>();
|
|
|
|
IEnumerable<MethodInfo> methods = GetType().GetMethods().Where(m => m.GetCustomAttribute<ServiceCommandAttribute>() != null);
|
|
foreach (MethodInfo method in methods)
|
|
{
|
|
ServiceCommandAttribute attribute = method.GetCustomAttribute<ServiceCommandAttribute>()!;
|
|
|
|
Expression self = Expression.Convert(Expression.Constant(this), GetType());
|
|
ParameterExpression commandParameter = Expression.Parameter(typeof(ServiceCommand));
|
|
MethodCallExpression call = Expression.Call(self, method, commandParameter);
|
|
|
|
Expression<HandlerDelegate> lambda = Expression.Lambda<HandlerDelegate>(call, commandParameter);
|
|
builder.Add(attribute.CommandType, lambda.Compile());
|
|
}
|
|
|
|
return builder.ToImmutable();
|
|
}
|
|
}
|