//
// 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();
}
}