mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-06-06 07:04:12 -04:00
Host: Using a genric host instead of a web host
This commit is contained in:
parent
33b74cac37
commit
a64cbcea62
@ -2,25 +2,11 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
|
using Kyoo.Models;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A class wrapping a value that will be set after the completion of the task it is related to.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This class replace the use of an out parameter on a task since tasks and out can't be combined.
|
|
||||||
/// </remarks>
|
|
||||||
/// <typeparam name="T">The type of the value</typeparam>
|
|
||||||
public class AsyncRef<T>
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The value that will be set before the completion of the task.
|
|
||||||
/// </summary>
|
|
||||||
public T Value { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
|
/// A service to abstract the file system to allow custom file systems (like distant file systems or external providers)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -55,7 +55,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <returns>A new task parameter.</returns>
|
/// <returns>A new task parameter.</returns>
|
||||||
public static TaskParameter Create<T>(string name, string description)
|
public static TaskParameter Create<T>(string name, string description)
|
||||||
{
|
{
|
||||||
return new()
|
return new TaskParameter
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
Description = description,
|
Description = description,
|
||||||
@ -72,7 +72,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <returns>A new task parameter.</returns>
|
/// <returns>A new task parameter.</returns>
|
||||||
public static TaskParameter CreateRequired<T>(string name, string description)
|
public static TaskParameter CreateRequired<T>(string name, string description)
|
||||||
{
|
{
|
||||||
return new()
|
return new TaskParameter
|
||||||
{
|
{
|
||||||
Name = name,
|
Name = name,
|
||||||
Description = description,
|
Description = description,
|
||||||
|
17
Kyoo.Common/Models/AsyncRef.cs
Normal file
17
Kyoo.Common/Models/AsyncRef.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Kyoo.Models
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A class wrapping a value that will be set after the completion of the task it is related to.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class replace the use of an out parameter on a task since tasks and out can't be combined.
|
||||||
|
/// </remarks>
|
||||||
|
/// <typeparam name="T">The type of the value</typeparam>
|
||||||
|
public class AsyncRef<T>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The value that will be set before the completion of the task.
|
||||||
|
/// </summary>
|
||||||
|
public T Value { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ using System.IO;
|
|||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kyoo.Common.Models.Attributes;
|
using Kyoo.Common.Models.Attributes;
|
||||||
|
using Kyoo.Models;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Kyoo.Controllers
|
namespace Kyoo.Controllers
|
||||||
|
@ -26,7 +26,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The configuration to get the plugin's directory.
|
/// The configuration to get the plugin's directory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly IOptionsMonitor<BasicOptions> _options;
|
private readonly IOptions<BasicOptions> _options;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The logger used by this class.
|
/// The logger used by this class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -44,7 +44,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <param name="options">The configuration instance, to get the plugin's directory path.</param>
|
/// <param name="options">The configuration instance, to get the plugin's directory path.</param>
|
||||||
/// <param name="logger">The logger used by this class.</param>
|
/// <param name="logger">The logger used by this class.</param>
|
||||||
public PluginManager(IServiceProvider provider,
|
public PluginManager(IServiceProvider provider,
|
||||||
IOptionsMonitor<BasicOptions> options,
|
IOptions<BasicOptions> options,
|
||||||
ILogger<PluginManager> logger)
|
ILogger<PluginManager> logger)
|
||||||
{
|
{
|
||||||
_provider = provider;
|
_provider = provider;
|
||||||
@ -106,7 +106,7 @@ namespace Kyoo.Controllers
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void LoadPlugins(ICollection<IPlugin> plugins)
|
public void LoadPlugins(ICollection<IPlugin> plugins)
|
||||||
{
|
{
|
||||||
string pluginFolder = _options.CurrentValue.PluginPath;
|
string pluginFolder = _options.Value.PluginPath;
|
||||||
if (!Directory.Exists(pluginFolder))
|
if (!Directory.Exists(pluginFolder))
|
||||||
Directory.CreateDirectory(pluginFolder);
|
Directory.CreateDirectory(pluginFolder);
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Autofac;
|
|
||||||
using Autofac.Extensions.DependencyInjection;
|
using Autofac.Extensions.DependencyInjection;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Kyoo
|
namespace Kyoo
|
||||||
@ -32,7 +32,7 @@ namespace Kyoo
|
|||||||
if (!File.Exists("./settings.json"))
|
if (!File.Exists("./settings.json"))
|
||||||
File.Copy(Path.Join(AppDomain.CurrentDomain.BaseDirectory, "settings.json"), "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
|
bool? debug = Environment.GetEnvironmentVariable("ENVIRONMENT")?.ToLowerInvariant() switch
|
||||||
{
|
{
|
||||||
@ -83,40 +83,67 @@ namespace Kyoo
|
|||||||
.AddCommandLine(args);
|
.AddCommandLine(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure the logging.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context">The host context that contains the configuration</param>
|
||||||
|
/// <param name="builder">The logger builder to configure.</param>
|
||||||
|
private static void _ConfigureLogging(HostBuilderContext context, ILoggingBuilder builder)
|
||||||
|
{
|
||||||
|
builder.AddConfiguration(context.Configuration.GetSection("logging"))
|
||||||
|
.AddSimpleConsole(x =>
|
||||||
|
{
|
||||||
|
x.TimestampFormat = "[hh:mm:ss] ";
|
||||||
|
})
|
||||||
|
.AddDebug()
|
||||||
|
.AddEventSourceLogger();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a a web host
|
/// Create a a web host
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
/// <param name="args">Command line parameters that can be handled by kestrel</param>
|
||||||
|
/// <param name="loggingConfiguration">
|
||||||
|
/// An action to configure the logging. If it is null, <see cref="_ConfigureLogging"/> will be used.
|
||||||
|
/// </param>
|
||||||
/// <returns>A new web host instance</returns>
|
/// <returns>A new web host instance</returns>
|
||||||
private static IWebHostBuilder CreateWebHostBuilder(string[] args)
|
public static IHostBuilder CreateWebHostBuilder(string[] args,
|
||||||
|
Action<HostBuilderContext, ILoggingBuilder> loggingConfiguration = null)
|
||||||
{
|
{
|
||||||
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
|
IConfiguration configuration = SetupConfig(new ConfigurationBuilder(), args).Build();
|
||||||
|
loggingConfiguration ??= _ConfigureLogging;
|
||||||
|
|
||||||
return new WebHostBuilder()
|
return new HostBuilder()
|
||||||
.ConfigureServices(x =>
|
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
|
||||||
{
|
|
||||||
AutofacServiceProviderFactory factory = new();
|
|
||||||
x.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<ContainerBuilder>>(factory));
|
|
||||||
})
|
|
||||||
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
.UseContentRoot(AppDomain.CurrentDomain.BaseDirectory)
|
||||||
.UseConfiguration(configuration)
|
|
||||||
.ConfigureAppConfiguration(x => SetupConfig(x, args))
|
.ConfigureAppConfiguration(x => SetupConfig(x, args))
|
||||||
.ConfigureLogging((context, builder) =>
|
.ConfigureLogging(loggingConfiguration)
|
||||||
{
|
|
||||||
builder.AddConfiguration(context.Configuration.GetSection("logging"))
|
|
||||||
.AddSimpleConsole(x =>
|
|
||||||
{
|
|
||||||
x.TimestampFormat = "[hh:mm:ss] ";
|
|
||||||
})
|
|
||||||
.AddDebug()
|
|
||||||
.AddEventSourceLogger();
|
|
||||||
})
|
|
||||||
.ConfigureServices(x => x.AddRouting())
|
.ConfigureServices(x => x.AddRouting())
|
||||||
.UseKestrel(options => { options.AddServerHeader = false; })
|
.ConfigureWebHost(x => x
|
||||||
.UseIIS()
|
.UseKestrel(options => { options.AddServerHeader = false; })
|
||||||
.UseIISIntegration()
|
.UseIIS()
|
||||||
.UseUrls(configuration.GetValue<string>("basics:url"))
|
.UseIISIntegration()
|
||||||
.UseStartup<Startup>();
|
.UseUrls(configuration.GetValue<string>("basics:url"))
|
||||||
|
.UseStartup(host => new Startup(
|
||||||
|
host.HostingEnvironment,
|
||||||
|
host.Configuration,
|
||||||
|
LoggerFactory.Create(builder => loggingConfiguration(host.ToGenericHost(), builder)))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert an <see cref="WebHostBuilderContext"/> to a <see cref="HostBuilderContext"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="host">The <see cref="WebHostBuilderContext"/> to convert.</param>
|
||||||
|
/// <returns>A <see cref="HostBuilderContext"/> containing the same properties.</returns>
|
||||||
|
private static HostBuilderContext ToGenericHost(this WebHostBuilderContext host)
|
||||||
|
{
|
||||||
|
return new HostBuilderContext(new Dictionary<object, object>())
|
||||||
|
{
|
||||||
|
Configuration = host.Configuration,
|
||||||
|
HostingEnvironment = host.HostingEnvironment
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,31 +34,36 @@ namespace Kyoo
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Created from the DI container, those services are needed to load information and instantiate plugins.s
|
/// Created from the DI container, those services are needed to load information and instantiate plugins.s
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hostProvider">
|
/// <param name="hostEnvironment">
|
||||||
/// The ServiceProvider used to create this <see cref="Startup"/> instance.
|
/// The host environment that could be used by plugins to configure themself.
|
||||||
/// 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.
|
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <param name="configuration">The configuration context</param>
|
/// <param name="configuration">The configuration context</param>
|
||||||
/// <param name="loggerFactory">A logger factory used to create a logger for the plugin manager.</param>
|
/// <param name="loggerFactory">A logger factory used to create a logger for the plugin manager.</param>
|
||||||
public Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory, IWebHostEnvironment host)
|
public Startup(IWebHostEnvironment hostEnvironment,
|
||||||
|
IConfiguration configuration,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
{
|
{
|
||||||
IOptionsMonitor<BasicOptions> options = hostProvider.GetService<IOptionsMonitor<BasicOptions>>();
|
HostServiceProvider hostProvider = new(hostEnvironment, configuration, loggerFactory);
|
||||||
_plugins = new PluginManager(hostProvider, options, loggerFactory.CreateLogger<PluginManager>());
|
_plugins = new PluginManager(
|
||||||
|
hostProvider,
|
||||||
|
Options.Create(configuration.GetSection(BasicOptions.Path).Get<BasicOptions>()),
|
||||||
|
loggerFactory.CreateLogger<PluginManager>()
|
||||||
|
);
|
||||||
|
|
||||||
// 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[] {
|
_plugins.LoadPlugins(new IPlugin[] {
|
||||||
new CoreModule(configuration),
|
new CoreModule(configuration),
|
||||||
new PostgresModule(configuration, host),
|
new PostgresModule(configuration, hostEnvironment),
|
||||||
// new SqLiteModule(configuration, host),
|
// new SqLiteModule(configuration, host),
|
||||||
new AuthenticationModule(configuration, loggerFactory, host),
|
new AuthenticationModule(configuration, loggerFactory, hostEnvironment),
|
||||||
new PluginTvdb(configuration),
|
new PluginTvdb(configuration),
|
||||||
new PluginTmdb(configuration)
|
new PluginTmdb(configuration)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Configure the WebApp services context.
|
/// Configure the services context via the <see cref="PluginManager"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services">The service collection to fill.</param>
|
/// <param name="services">The service collection to fill.</param>
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
@ -79,6 +84,10 @@ namespace Kyoo
|
|||||||
_plugins.ConfigureServices(services);
|
_plugins.ConfigureServices(services);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configure the autofac container via the <see cref="PluginManager"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="builder">The builder to configure.</param>
|
||||||
public void ConfigureContainer(ContainerBuilder builder)
|
public void ConfigureContainer(ContainerBuilder builder)
|
||||||
{
|
{
|
||||||
builder.RegisterModule<AttributedMetadataModule>();
|
builder.RegisterModule<AttributedMetadataModule>();
|
||||||
@ -132,5 +141,57 @@ namespace Kyoo
|
|||||||
spa.UseAngularCliServer("start");
|
spa.UseAngularCliServer("start");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A simple host service provider used to activate plugins instance.
|
||||||
|
/// The same services as a generic host are available and an <see cref="ILoggerFactory"/> has been added.
|
||||||
|
/// </summary>
|
||||||
|
private class HostServiceProvider : IServiceProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The host environment that could be used by plugins to configure themself.
|
||||||
|
/// </summary>
|
||||||
|
private readonly IWebHostEnvironment _hostEnvironment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The configuration context.
|
||||||
|
/// </summary>
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A logger factory used to create a logger for the plugin manager.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ILoggerFactory _loggerFactory;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new <see cref="HostServiceProvider"/> that will return given services when asked.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostEnvironment">
|
||||||
|
/// The host environment that could be used by plugins to configure themself.
|
||||||
|
/// </param>
|
||||||
|
/// <param name="configuration">The configuration context</param>
|
||||||
|
/// <param name="loggerFactory">A logger factory used to create a logger for the plugin manager.</param>
|
||||||
|
public HostServiceProvider(IWebHostEnvironment hostEnvironment,
|
||||||
|
IConfiguration configuration,
|
||||||
|
ILoggerFactory loggerFactory)
|
||||||
|
{
|
||||||
|
_hostEnvironment = hostEnvironment;
|
||||||
|
_configuration = configuration;
|
||||||
|
_loggerFactory = loggerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user