Files
Kayori_Medusa.net/Core/Server/Services/HandlerService.cs
T
2025-07-31 00:07:12 +02:00

153 lines
5.6 KiB
C#

using Server.Attributes;
using System.Xml.Linq;
using Abstractions.Handlers;
using Abstractions.Services;
namespace Server.Services;
public class HandlerService(IServiceScopeFactory serviceScopeFactory, ILogger<HandlerService> logger, IXmlLogService xmlLogService) : IHandlerService
{
private readonly IServiceScopeFactory _serviceScopeFactory = serviceScopeFactory;
private readonly ILogger<HandlerService> _logger = logger;
public List<Type> Handlers { get; set; } = [];
public async Task<XDocument> Handle(string model, string module, string method, XDocument body)
{
foreach(var handler in Handlers)
{
//Module and service are on the attribute
var handlerAttribute = handler.CustomAttributes.FirstOrDefault(x => x.AttributeType == typeof(HandlerAttribute));
if(handlerAttribute is null)
{
var response = await HandleInheritanceClass(handler, model, module, method, body);
if(response is not null)
{
return response;
}
continue;
}
var attributeModule = handlerAttribute.ConstructorArguments[0].Value!.ToString();
var attributeMethod = handlerAttribute.ConstructorArguments[1].Value!.ToString();
if (attributeModule != module || attributeMethod != method) continue;
await using var scope = _serviceScopeFactory.CreateAsyncScope();
// Body param is optional, so check for it
var requiresXDocumentConstructor = handler.GetConstructors()
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
var handlerInstance = requiresXDocumentConstructor
? (IHandler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler, body)
: (IHandler)ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler);
var document = await handlerInstance.HandleAsync(model);
return document;
}
//If no handler is found return an empty document
_logger.LogWarning("No handler found for {model}/{module}/{method}", model, module, method);
return new XDocument();
}
private async Task<XDocument?> HandleInheritanceClass(Type handler, string model, string module, string method, XDocument body)
{
await using var scope = _serviceScopeFactory.CreateAsyncScope();
var requiredXdocumentConstructor = handler.GetConstructors()
.Any(c => c.GetParameters().Any(p => p.ParameterType == typeof(XDocument)));
if (handler.IsAbstract)
{
throw new InvalidOperationException($"Cannot create instance of abstract class: {handler.FullName}");
}
var handlerInstance = (requiredXdocumentConstructor
? ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler, body)
: ActivatorUtilities.CreateInstance(scope.ServiceProvider, handler)) as Handler;
try
{
var configureMethod = handler.GetMethod("Configure");
configureMethod?.Invoke(handlerInstance, null);
}
catch(NotImplementedException e)
{
_logger.LogError(e, "Configure method not implemented for {Handler}", handler.Name);
return null;
}
var modelParts = model.Split(':');
var handlerModule = handlerInstance.HandlerModule;
var handlerMethod = handlerInstance.HandlerMethod;
var handlerGameCode = handlerInstance.HandlerGameCode;
var handlerMinVer = handlerInstance.HandlerMinVer;
var handlerMaxVer = handlerInstance.HandlerMaxVer;
if(string.IsNullOrEmpty(handlerModule))
{
_logger.LogError("Module not set for {Handler}", handler.Name);
return null;
}
if(string.IsNullOrEmpty(handlerMethod))
{
_logger.LogError("Method not set for {Handler}", handler.Name);
return null;
}
if(!string.IsNullOrEmpty(handlerGameCode))
{
if(handlerGameCode != modelParts[0])
return null;
}
var version = string.Join(string.Empty, modelParts.Skip(4));
if(!string.IsNullOrEmpty(handlerMinVer))
{
var parsedVersion = int.Parse(version);
var parsedMinVer = int.Parse(handlerMinVer);
if(parsedVersion < parsedMinVer)
return null;
}
if(!string.IsNullOrEmpty(handlerMaxVer))
{
var parsedVersion = int.Parse(version);
var parsedMaxVer = int.Parse(handlerMaxVer);
if(parsedVersion > parsedMaxVer)
return null;
}
if(handlerModule != module || handlerMethod != method)
return null;
var handleMethod = handlerInstance.GetType().GetMethod("Handle", [typeof(string)]);
var handleAsyncMethod = handlerInstance.GetType().GetMethod("HandleAsync", [typeof(string)]);
if (handler.IsAbstract)
{
throw new InvalidOperationException($"Cannot create instance of abstract class: {handler.FullName}");
}
var response = handleMethod?.DeclaringType != typeof(Handler)
? handlerInstance.Handle(model)
: handleAsyncMethod?.DeclaringType != typeof(Handler)
? await handlerInstance.HandleAsync(model)
: null;
if (response is not null) return response;
_logger.LogError("Handle and HandleAsync not implemented for {Handler}", handler.Name);
return null;
}
}