using System; using System.Collections.Generic; using System.Linq; using Autofac; using Kyoo.Abstractions; using Kyoo.Abstractions.Controllers; using Kyoo.Authentication; using Kyoo.Core.Controllers; using Kyoo.Core.Models.Options; using Kyoo.Core.Tasks; using Kyoo.Postgresql; using Kyoo.SqLite; using Kyoo.TheMovieDb; using Kyoo.TheTvdb; using Kyoo.Utils; using Kyoo.WebApp; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Kyoo.Core { /// /// The Startup class is used to configure the AspNet's webhost. /// public class PluginsStartup { /// /// A plugin manager used to load plugins and allow them to configure services / asp net. /// private readonly IPluginManager _plugins; /// /// The configuration used to register and so on for plugin's specified types. /// private readonly IConfiguration _configuration; /// /// Created from the DI container, those services are needed to load information and instantiate plugins.s /// /// The plugin manager to use to load new plugins and configure the host. /// /// The configuration used to register and so on for plugin's specified types. /// public PluginsStartup(IPluginManager plugins, IConfiguration configuration) { _plugins = plugins; _configuration = configuration; _plugins.LoadPlugins( typeof(CoreModule), typeof(WebAppModule), typeof(AuthenticationModule), typeof(PostgresModule), typeof(SqLiteModule), typeof(PluginTvdb), typeof(PluginTmdb) ); } /// /// Configure the services context via the . /// /// The service collection to fill. public void ConfigureServices(IServiceCollection services) { foreach (IPlugin plugin in _plugins.GetAllPlugins()) plugin.Configure(services); IEnumerable> configTypes = _plugins.GetAllPlugins() .SelectMany(x => x.Configuration) .Where(x => x.Value != null); foreach ((string path, Type type) in configTypes) { Utility.RunGenericMethod( typeof(OptionsConfigurationServiceCollectionExtensions), nameof(OptionsConfigurationServiceCollectionExtensions.Configure), type, services, _configuration.GetSection(path) ); } } /// /// Configure the autofac container via the . /// /// The builder to configure. public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterInstance(_plugins).As().ExternallyOwned(); builder.RegisterTask(); foreach (IPlugin plugin in _plugins.GetAllPlugins()) plugin.Configure(builder); } /// /// Configure the asp net host. /// /// The asp net host to configure /// An autofac container used to create a new scope to configure asp-net. /// The configuration manager used to register strongly typed config. public void Configure(IApplicationBuilder app, ILifetimeScope container, IConfigurationManager config) { IEnumerable steps = _plugins.GetAllPlugins() .SelectMany(x => x.ConfigureSteps) .OrderByDescending(x => x.Priority); using ILifetimeScope scope = container.BeginLifetimeScope(x => x.RegisterInstance(app).SingleInstance().ExternallyOwned()); IServiceProvider provider = scope.Resolve(); foreach (IStartupAction step in steps) step.Run(provider); IEnumerable> pluginConfig = _plugins.GetAllPlugins() .SelectMany(x => x.Configuration) .GroupBy(x => x.Key.Split(':').First()) .Select(x => x .OrderBy(y => y.Key.Length) .First() ); foreach ((string path, Type type) in pluginConfig) config.Register(path, type); } /// /// Create a new from a webhost. /// This is meant to be used from . /// /// The context of the web host. /// /// The logger factory used to log while the application is setting itself up. /// /// A new . public static PluginsStartup FromWebHost(WebHostBuilderContext host, ILoggerFactory logger) { HostServiceProvider hostProvider = new(host.HostingEnvironment, host.Configuration, logger); PluginManager plugins = new( hostProvider, Options.Create(host.Configuration.GetSection(BasicOptions.Path).Get()), logger.CreateLogger() ); return new PluginsStartup(plugins, host.Configuration); } /// /// A simple host service provider used to activate plugins instance. /// The same services as a generic host are available and an has been added. /// private class HostServiceProvider : IServiceProvider { /// /// The host environment that could be used by plugins to configure themself. /// private readonly IWebHostEnvironment _hostEnvironment; /// /// The configuration context. /// private readonly IConfiguration _configuration; /// /// A logger factory used to create a logger for the plugin manager. /// private readonly ILoggerFactory _loggerFactory; /// /// Create a new that will return given services when asked. /// /// /// The host environment that could be used by plugins to configure themself. /// /// The configuration context /// A logger factory used to create a logger for the plugin manager. public HostServiceProvider(IWebHostEnvironment hostEnvironment, IConfiguration configuration, ILoggerFactory loggerFactory) { _hostEnvironment = hostEnvironment; _configuration = configuration; _loggerFactory = loggerFactory; } /// public object GetService(Type serviceType) { if (serviceType == typeof(IWebHostEnvironment) || serviceType == typeof(IHostEnvironment)) return _hostEnvironment; if (serviceType == typeof(IConfiguration)) return _configuration; if (serviceType.GetGenericTypeDefinition() == typeof(ILogger<>)) { return Utility.RunGenericMethod( typeof(LoggerFactoryExtensions), nameof(LoggerFactoryExtensions.CreateLogger), serviceType.GetGenericArguments().First(), _loggerFactory ); } return null; } } } }