diff --git a/Kyoo.Common/Controllers/IFileSystem.cs b/Kyoo.Common/Controllers/IFileSystem.cs index 92e951b7..f443254f 100644 --- a/Kyoo.Common/Controllers/IFileSystem.cs +++ b/Kyoo.Common/Controllers/IFileSystem.cs @@ -2,25 +2,11 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using JetBrains.Annotations; +using Kyoo.Models; using Microsoft.AspNetCore.Mvc; namespace Kyoo.Controllers { - /// - /// A class wrapping a value that will be set after the completion of the task it is related to. - /// - /// - /// This class replace the use of an out parameter on a task since tasks and out can't be combined. - /// - /// The type of the value - public class AsyncRef - { - /// - /// The value that will be set before the completion of the task. - /// - public T Value { get; set; } - } - /// /// A service to abstract the file system to allow custom file systems (like distant file systems or external providers) /// diff --git a/Kyoo.Common/Controllers/ITask.cs b/Kyoo.Common/Controllers/ITask.cs index e8d07000..4d764fc7 100644 --- a/Kyoo.Common/Controllers/ITask.cs +++ b/Kyoo.Common/Controllers/ITask.cs @@ -55,7 +55,7 @@ namespace Kyoo.Controllers /// A new task parameter. public static TaskParameter Create(string name, string description) { - return new() + return new TaskParameter { Name = name, Description = description, @@ -72,7 +72,7 @@ namespace Kyoo.Controllers /// A new task parameter. public static TaskParameter CreateRequired(string name, string description) { - return new() + return new TaskParameter { Name = name, Description = description, diff --git a/Kyoo.Common/Models/AsyncRef.cs b/Kyoo.Common/Models/AsyncRef.cs new file mode 100644 index 00000000..98738ac6 --- /dev/null +++ b/Kyoo.Common/Models/AsyncRef.cs @@ -0,0 +1,17 @@ +namespace Kyoo.Models +{ + /// + /// A class wrapping a value that will be set after the completion of the task it is related to. + /// + /// + /// This class replace the use of an out parameter on a task since tasks and out can't be combined. + /// + /// The type of the value + public class AsyncRef + { + /// + /// The value that will be set before the completion of the task. + /// + public T Value { get; set; } + } +} \ No newline at end of file diff --git a/Kyoo/Controllers/FileSystems/HttpFileSystem.cs b/Kyoo/Controllers/FileSystems/HttpFileSystem.cs index c7954db8..99155f62 100644 --- a/Kyoo/Controllers/FileSystems/HttpFileSystem.cs +++ b/Kyoo/Controllers/FileSystems/HttpFileSystem.cs @@ -5,6 +5,7 @@ using System.IO; using System.Net.Http; using System.Threading.Tasks; using Kyoo.Common.Models.Attributes; +using Kyoo.Models; using Microsoft.AspNetCore.Mvc; namespace Kyoo.Controllers diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index 46185f16..646c644d 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -26,7 +26,7 @@ namespace Kyoo.Controllers /// /// The configuration to get the plugin's directory. /// - private readonly IOptionsMonitor _options; + private readonly IOptions _options; /// /// The logger used by this class. /// @@ -44,7 +44,7 @@ namespace Kyoo.Controllers /// The configuration instance, to get the plugin's directory path. /// The logger used by this class. public PluginManager(IServiceProvider provider, - IOptionsMonitor options, + IOptions options, ILogger logger) { _provider = provider; @@ -106,7 +106,7 @@ namespace Kyoo.Controllers /// public void LoadPlugins(ICollection plugins) { - string pluginFolder = _options.CurrentValue.PluginPath; + string pluginFolder = _options.Value.PluginPath; if (!Directory.Exists(pluginFolder)) Directory.CreateDirectory(pluginFolder); diff --git a/Kyoo/Program.cs b/Kyoo/Program.cs index f1adfb40..509ae5f6 100644 --- a/Kyoo/Program.cs +++ b/Kyoo/Program.cs @@ -1,13 +1,13 @@ using System; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading.Tasks; -using Autofac; using Autofac.Extensions.DependencyInjection; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; namespace Kyoo @@ -32,7 +32,7 @@ namespace Kyoo if (!File.Exists("./settings.json")) File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "settings.json"); - IWebHostBuilder builder = CreateWebHostBuilder(args); + IHostBuilder builder = CreateWebHostBuilder(args); bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch { @@ -83,40 +83,67 @@ namespace Kyoo .AddCommandLine(args); } + /// + /// Configure the logging. + /// + /// The host context that contains the configuration + /// The logger builder to configure. + private static void _ConfigureLogging(HostBuilderContext context, ILoggingBuilder builder) + { + builder.AddConfiguration(context.Configuration.GetSection("logging")) + .AddSimpleConsole(x => + { + x.TimestampFormat = "[hh:mm:ss] "; + }) + .AddDebug() + .AddEventSourceLogger(); + } + /// /// Create a a web host /// /// Command line parameters that can be handled by kestrel + /// + /// An action to configure the logging. If it is null, will be used. + /// /// A new web host instance - private static IWebHostBuilder CreateWebHostBuilder(string[] args) + public static IHostBuilder CreateWebHostBuilder(string[] args, + Action loggingConfiguration = null) { IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build(); + loggingConfiguration ??= _ConfigureLogging; - return new WebHostBuilder() - .ConfigureServices(x => - { - AutofacServiceProviderFactory factory = new(); - x.Replace(ServiceDescriptor.Singleton>(factory)); - }) + return new HostBuilder() + .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .UseContentRoot(AppDomain.CurrentDomain.BaseDirectory) - .UseConfiguration(configuration) .ConfigureAppConfiguration(x => SetupConfig(x, args)) - .ConfigureLogging((context, builder) => - { - builder.AddConfiguration(context.Configuration.GetSection("logging")) - .AddSimpleConsole(x => - { - x.TimestampFormat = "[hh:mm:ss] "; - }) - .AddDebug() - .AddEventSourceLogger(); - }) + .ConfigureLogging(loggingConfiguration) .ConfigureServices(x => x.AddRouting()) - .UseKestrel(options => { options.AddServerHeader = false; }) - .UseIIS() - .UseIISIntegration() - .UseUrls(configuration.GetValue("basics:url")) - .UseStartup(); + .ConfigureWebHost(x => x + .UseKestrel(options => { options.AddServerHeader = false; }) + .UseIIS() + .UseIISIntegration() + .UseUrls(configuration.GetValue("basics:url")) + .UseStartup(host => new Startup( + host.HostingEnvironment, + host.Configuration, + LoggerFactory.Create(builder => loggingConfiguration(host.ToGenericHost(), builder))) + ) + ); + } + + /// + /// Convert an to a . + /// + /// The to convert. + /// A containing the same properties. + private static HostBuilderContext ToGenericHost(this WebHostBuilderContext host) + { + return new HostBuilderContext(new Dictionary()) + { + Configuration = host.Configuration, + HostingEnvironment = host.HostingEnvironment + }; } } } diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 804a08f0..cd9d4175 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -34,31 +34,36 @@ namespace Kyoo /// /// Created from the DI container, those services are needed to load information and instantiate plugins.s /// - /// - /// The ServiceProvider used to create this instance. - /// The host provider that contains only well-known services that are Kyoo independent. - /// This is used to instantiate plugins that might need a logger, a configuration or an host environment. + /// + /// 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 Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory, IWebHostEnvironment host) + public Startup(IWebHostEnvironment hostEnvironment, + IConfiguration configuration, + ILoggerFactory loggerFactory) { - IOptionsMonitor options = hostProvider.GetService>(); - _plugins = new PluginManager(hostProvider, options, loggerFactory.CreateLogger()); + HostServiceProvider hostProvider = new(hostEnvironment, configuration, loggerFactory); + _plugins = new PluginManager( + hostProvider, + Options.Create(configuration.GetSection(BasicOptions.Path).Get()), + loggerFactory.CreateLogger() + ); - // TODO remove postgres from here and load it like a normal plugin. + // TODO maybe keep all core-plugins here to simplify the build process but use their typeof in the method + // (to allow simple constructor changes), leaving the instantiation responsibility to the plugin manager. _plugins.LoadPlugins(new IPlugin[] { new CoreModule(configuration), - new PostgresModule(configuration, host), + new PostgresModule(configuration, hostEnvironment), // new SqLiteModule(configuration, host), - new AuthenticationModule(configuration, loggerFactory, host), + new AuthenticationModule(configuration, loggerFactory, hostEnvironment), new PluginTvdb(configuration), new PluginTmdb(configuration) }); } /// - /// Configure the WebApp services context. + /// Configure the services context via the . /// /// The service collection to fill. public void ConfigureServices(IServiceCollection services) @@ -79,6 +84,10 @@ namespace Kyoo _plugins.ConfigureServices(services); } + /// + /// Configure the autofac container via the . + /// + /// The builder to configure. public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterModule(); @@ -132,5 +141,57 @@ namespace Kyoo spa.UseAngularCliServer("start"); }); } + + /// + /// 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 == typeof(ILoggerFactory)) + return _loggerFactory; + return null; + } + } } }