using System.Collections.Immutable; using System.Linq.Expressions; using System.Reflection; using GameServer.Handlers.Attributes; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Protocol; namespace GameServer.Handlers.Factory; internal class MessageHandlerFactory { private readonly ImmutableDictionary s_messageHandlers; public MessageHandlerFactory(ILogger logger) { IEnumerable handlerTypes = Assembly.GetExecutingAssembly().GetTypes() .Where(t => t.IsAssignableTo(typeof(MessageHandlerBase)) && !t.IsAbstract); s_messageHandlers = GenerateHandlerMethods(handlerTypes); logger.LogInformation("Registered {count} message handlers", s_messageHandlers.Count); } public MessageHandler? GetHandler(MessageId messageId) { s_messageHandlers.TryGetValue(messageId, out MessageHandler? handler); return handler; } private static ImmutableDictionary GenerateHandlerMethods(IEnumerable handlerTypes) { var builder = ImmutableDictionary.CreateBuilder(); MethodInfo getServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod("GetRequiredService", [typeof(IServiceProvider)])!; foreach (Type type in handlerTypes) { IEnumerable methods = type.GetMethods() .Where(method => method.GetCustomAttribute() != null); foreach (MethodInfo method in methods) { MessageHandlerAttribute attribute = method.GetCustomAttribute()!; ParameterExpression serviceProviderParam = Expression.Parameter(typeof(IServiceProvider)); ParameterExpression dataParam = Expression.Parameter(typeof(ReadOnlyMemory)); MethodCallExpression getServiceCall = Expression.Call(getServiceMethod.MakeGenericMethod(type), serviceProviderParam); MethodCallExpression handlerCall = Expression.Call(getServiceCall, method, dataParam); Expression lambda = Expression.Lambda(handlerCall, serviceProviderParam, dataParam); builder.Add(attribute.MessageId, lambda.Compile()); } } return builder.ToImmutable(); } }