// // ServiceCollectionExtensions.cs // // Copyright (c) František Boháček. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Linq; using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using NosCore.Packets; using NosCore.Packets.Attributes; using NosCore.Packets.Enumerations; using NosCore.Packets.Interfaces; using NosSmooth.Core.Client; using NosSmooth.Core.Commands; using NosSmooth.Core.Packets; using NosSmooth.Core.Packets.Converters; namespace NosSmooth.Core.Extensions; /// /// Contains extension methods for . /// public static class ServiceCollectionExtensions { /// /// Adds base packet and command handling for nostale client. /// /// The service collection to register the responder to. /// Custom types of packets to serialize and deserialize. /// The collection. public static IServiceCollection AddNostaleCore ( this IServiceCollection serviceCollection, params Type[] additionalPacketTypes ) { serviceCollection .TryAddSingleton(); var clientPacketTypes = typeof(IPacket).Assembly.GetTypes() .Where(p => (p.Namespace?.Contains("Client") ?? false) && p.GetInterfaces().Contains(typeof(IPacket)) && p.IsClass && !p.IsAbstract).ToList(); var serverPacketTypes = typeof(IPacket).Assembly.GetTypes() .Where(p => (p.Namespace?.Contains("Server") ?? false) && p.GetInterfaces().Contains(typeof(IPacket)) && p.IsClass && !p.IsAbstract).ToList(); if (additionalPacketTypes.Length != 0) { clientPacketTypes.AddRange(additionalPacketTypes); } serviceCollection.AddSingleton(p => new PacketSerializerProvider(clientPacketTypes, serverPacketTypes, p)); serviceCollection.AddSingleton(p => p.GetRequiredService().ServerSerializer); serviceCollection.AddSingleton(); serviceCollection.AddSpecificPacketConverter(); return serviceCollection; } /// /// Adds the specified packet responder that will be called upon receiving the given event. /// /// The service collection to register the responder to. /// The type of the responder. /// Thrown if the type of the responder is incorrect. /// The collection. public static IServiceCollection AddPacketResponder ( this IServiceCollection serviceCollection ) where TPacketResponder : class, IPacketResponder { return serviceCollection.AddPacketResponder(typeof(TPacketResponder)); } /// /// Adds the specified packet responder that will be called upon receiving the given event. /// /// The service collection to register the responder to. /// The type of the responder. /// The collection. /// Thrown if the type of the responder is incorrect. public static IServiceCollection AddPacketResponder ( this IServiceCollection serviceCollection, Type responderType ) { if (responderType.GetInterfaces().Any(i => i == typeof(IEveryPacketResponder))) { return serviceCollection.AddScoped(typeof(IEveryPacketResponder), responderType); } if (!responderType.GetInterfaces().Any( i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IPacketResponder<>) )) { throw new ArgumentException( $"{nameof(responderType)} should implement IPacketResponder.", nameof(responderType)); } var responderTypeInterfaces = responderType.GetInterfaces(); var responderInterfaces = responderTypeInterfaces.Where ( r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(IPacketResponder<>) ); foreach (var responderInterface in responderInterfaces) { serviceCollection.AddScoped(responderInterface, responderType); } return serviceCollection; } /// /// Adds the specified command handler. /// /// The service collection to register the responder to. /// The type of the command. /// Thrown if the type of the responder is incorrect. /// The collection. public static IServiceCollection AddCommandHandler ( this IServiceCollection serviceCollection ) where TCommandHandler : class, ICommandHandler { return serviceCollection.AddCommandHandler(typeof(TCommandHandler)); } /// /// Adds the specified command handler. /// /// The service collection to register the responder to. /// The type of the command handler. /// The collection. /// Thrown if the type of the responder is incorrect. public static IServiceCollection AddCommandHandler ( this IServiceCollection serviceCollection, Type commandHandlerType ) { if (!commandHandlerType.GetInterfaces().Any( i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICommandHandler<>) )) { throw new ArgumentException( $"{nameof(commandHandlerType)} should implement ICommandHandler.", nameof(commandHandlerType)); } var handlerTypeInterfaces = commandHandlerType.GetInterfaces(); var handlerInterfaces = handlerTypeInterfaces.Where ( r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(ICommandHandler<>) ); foreach (var handlerInterface in handlerInterfaces) { serviceCollection.AddScoped(handlerInterface, commandHandlerType); } return serviceCollection; } /// /// Adds the specified packet converter. /// /// The service collection to register the responder to. /// The type of the packet. /// Thrown if the type of the responder is incorrect. /// The collection. public static IServiceCollection AddSpecificPacketConverter(this IServiceCollection serviceCollection) where TPacketConverter : class, ISpecificPacketSerializer { return serviceCollection.AddSingleton(); } }