//
// 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 NosSmooth.Packets.Converters;
using NosSmooth.Packets.Converters.Basic;
using NosSmooth.Packets.Converters.Special;
using NosSmooth.Packets.Packets;
namespace NosSmooth.Packets.Extensions;
///
/// Extensions for .
///
public static class ServiceCollectionExtensions
{
///
/// Add packet serialization classes.
///
///
/// All generic implementations of ITypeConverter the class
/// implements will be registered.
///
/// The service collection.
/// The collection.
public static IServiceCollection AddPacketSerialization(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSingleton()
.AddSingleton()
.AddSingleton(p =>
{
var repository = new PacketTypesRepository(p.GetRequiredService());
var packetTypes = typeof(ServiceCollectionExtensions).Assembly
.GetExportedTypes()
.Where(x => x != typeof(UnresolvedPacket) && !x.IsAbstract && typeof(IPacket).IsAssignableFrom(x));
foreach (var packetType in packetTypes)
{
var result = repository.AddPacketType(packetType);
if (!result.IsSuccess)
{
// TODO: figure out how to handle this.
throw new Exception(result.Error.Message);
}
}
return repository;
})
.AddGeneratedSerializers(typeof(ServiceCollectionExtensions).Assembly)
.AddBasicConverters();
}
///
/// Adds all generated serializers from the given assembly.
///
/// The service collection.
/// The assembly.
/// The collection.
public static IServiceCollection AddGeneratedSerializers(this IServiceCollection serviceCollection, Assembly assembly)
{
var types = assembly.GetExportedTypes()
.Where(x => x.Namespace?.Contains("Generated") ?? false)
.Where(x => x.GetInterfaces().Any(
i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ITypeConverter<>)
));
foreach (var type in types)
{
serviceCollection.AddTypeConverter(type);
}
return serviceCollection;
}
///
/// Adds basic converters for int, uint, short, ushort, long, ulong, char, string
/// and special converters for lists and enums.
///
/// The service collection.
/// The collection.
public static IServiceCollection AddBasicConverters(this IServiceCollection serviceCollection)
{
return serviceCollection
.AddSpecialConverter()
.AddSpecialConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter()
.AddTypeConverter();
}
///
/// Add generic type converter.
///
///
/// All generic implementations of ITypeConverter the class
/// implements will be registered.
///
/// The service collection.
/// The type of the converter.
/// The collection.
public static IServiceCollection AddTypeConverter(this IServiceCollection serviceCollection)
where TConverter : ITypeConverter
=> serviceCollection.AddTypeConverter(typeof(TConverter));
///
/// Add generic type converter.
///
///
/// All generic implementations of ITypeConverter the class
/// implements will be registered.
///
/// The service collection.
/// The type of the converter.
/// The collection.
public static IServiceCollection AddTypeConverter(this IServiceCollection serviceCollection, Type converterType)
{
if (!converterType.GetInterfaces().Any(
i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ITypeConverter<>)
))
{
throw new ArgumentException(
$"{nameof(converterType)} should implement ITypeConverter.",
nameof(converterType));
}
var handlerTypeInterfaces = converterType.GetInterfaces();
var handlerInterfaces = handlerTypeInterfaces.Where
(
r => r.IsGenericType && r.GetGenericTypeDefinition() == typeof(ITypeConverter<>)
);
foreach (var handlerInterface in handlerInterfaces)
{
serviceCollection.AddSingleton(handlerInterface, converterType);
}
return serviceCollection;
}
///
/// Add the specified converter as a special converter.
///
/// The service collection.
/// The type to add as a special converter.
/// The collection.
public static IServiceCollection AddSpecialConverter(this IServiceCollection serviceCollection)
where TSpecialConverter : class, ISpecialTypeConverter
{
return serviceCollection.AddSingleton();
}
}