diff --git a/Kyoo.Authentication/AuthenticationModule.cs b/Kyoo.Authentication/AuthenticationModule.cs
index 8e2c78c4..1e9dcd01 100644
--- a/Kyoo.Authentication/AuthenticationModule.cs
+++ b/Kyoo.Authentication/AuthenticationModule.cs
@@ -9,6 +9,7 @@ using IdentityServer4.Services;
using Kyoo.Authentication.Models;
using Kyoo.Authentication.Views;
using Kyoo.Controllers;
+using Kyoo.Models.Attributes;
using Kyoo.Models.Permissions;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
@@ -64,6 +65,11 @@ namespace Kyoo.Authentication
/// The environment information to check if the app runs in debug mode
///
private readonly IWebHostEnvironment _environment;
+
+ ///
+ /// The configuration manager used to register typed/untyped implementations.
+ ///
+ [Injected] public IConfigurationManager ConfigurationManager { private get; set; }
///
@@ -98,9 +104,7 @@ namespace Kyoo.Authentication
services.Configure(_configuration.GetSection(PermissionOption.Path));
services.Configure(_configuration.GetSection(CertificateOption.Path));
services.Configure(_configuration.GetSection(AuthenticationOption.Path));
- services.AddConfiguration(AuthenticationOption.Path);
-
-
+
List clients = new();
_configuration.GetSection("authentication:clients").Bind(clients);
CertificateOption certificateOptions = new();
@@ -139,6 +143,8 @@ namespace Kyoo.Authentication
///
public void ConfigureAspNet(IApplicationBuilder app)
{
+ ConfigurationManager.AddTyped(AuthenticationOption.Path);
+
app.UseCookiePolicy(new CookiePolicyOptions
{
MinimumSameSitePolicy = SameSiteMode.Strict
diff --git a/Kyoo.Common/Controllers/IConfigurationManager.cs b/Kyoo.Common/Controllers/IConfigurationManager.cs
index 9159d92c..02430b10 100644
--- a/Kyoo.Common/Controllers/IConfigurationManager.cs
+++ b/Kyoo.Common/Controllers/IConfigurationManager.cs
@@ -12,6 +12,21 @@ namespace Kyoo.Controllers
///
public interface IConfigurationManager
{
+ ///
+ /// Add an editable configuration to the editable configuration list
+ ///
+ /// The root path of the editable configuration. It should not be a nested type.
+ /// The type of the configuration
+ void AddTyped(string path);
+
+ ///
+ /// Add an editable configuration to the editable configuration list.
+ /// WARNING: this method allow you to add an unmanaged type. This type won't be editable. This can be used
+ /// for external libraries or variable arguments.
+ ///
+ /// The root path of the editable configuration. It should not be a nested type.
+ void AddUntyped(string path);
+
///
/// Get the value of a setting using it's path.
///
diff --git a/Kyoo.Common/Module.cs b/Kyoo.Common/Module.cs
index d4442d98..0e8de063 100644
--- a/Kyoo.Common/Module.cs
+++ b/Kyoo.Common/Module.cs
@@ -1,10 +1,7 @@
-using System.Linq;
using Autofac;
using Autofac.Builder;
using Kyoo.Controllers;
-using Kyoo.Models;
using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
namespace Kyoo
{
@@ -75,37 +72,6 @@ namespace Kyoo
return builder.RegisterRepository().As();
}
- ///
- /// Add an editable configuration to the editable configuration list
- ///
- /// The service collection to edit
- /// The root path of the editable configuration. It should not be a nested type.
- /// The type of the configuration
- /// The given service collection is returned.
- public static IServiceCollection AddConfiguration(this IServiceCollection services, string path)
- where T : class
- {
- if (services.Any(x => x.ServiceType == typeof(T)))
- return services;
- foreach (ConfigurationReference confRef in ConfigurationReference.CreateReference(path))
- services.AddSingleton(confRef);
- return services;
- }
-
- ///
- /// Add an editable configuration to the editable configuration list.
- /// WARNING: this method allow you to add an unmanaged type. This type won't be editable. This can be used
- /// for external libraries or variable arguments.
- ///
- /// The service collection to edit
- /// The root path of the editable configuration. It should not be a nested type.
- /// The given service collection is returned.
- public static IServiceCollection AddUntypedConfiguration(this IServiceCollection services, string path)
- {
- services.AddSingleton(ConfigurationReference.CreateUntyped(path));
- return services;
- }
-
///
/// Get the public URL of kyoo using the given configuration instance.
///
diff --git a/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj b/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
index 8877cb95..ac7dad56 100644
--- a/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
+++ b/Kyoo.TheTvdb/Kyoo.TheTvdb.csproj
@@ -19,8 +19,8 @@
-
+
diff --git a/Kyoo.TheTvdb/PluginTvdb.cs b/Kyoo.TheTvdb/PluginTvdb.cs
index 62fc0885..1d008fbf 100644
--- a/Kyoo.TheTvdb/PluginTvdb.cs
+++ b/Kyoo.TheTvdb/PluginTvdb.cs
@@ -1,7 +1,12 @@
using System;
using System.Collections.Generic;
using Autofac;
+using Kyoo.Authentication.Models;
using Kyoo.Controllers;
+using Kyoo.Models.Attributes;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
using TvDbSharper;
namespace Kyoo.TheTvdb
@@ -33,11 +38,44 @@ namespace Kyoo.TheTvdb
public ICollection Requires => ArraySegment.Empty;
+ ///
+ /// The configuration to use.
+ ///
+ private readonly IConfiguration _configuration;
+
+ ///
+ /// The configuration manager used to register typed/untyped implementations.
+ ///
+ [Injected] public IConfigurationManager ConfigurationManager { private get; set; }
+
+
+ ///
+ /// Create a new tvdb module instance and use the given configuration.
+ ///
+ /// The configuration to use
+ public PluginTvdb(IConfiguration configuration)
+ {
+ _configuration = configuration;
+ }
+
+
///
public void Configure(ContainerBuilder builder)
{
builder.RegisterType().As();
builder.RegisterProvider();
}
+
+ ///
+ public void Configure(IServiceCollection services, ICollection availableTypes)
+ {
+ services.Configure(_configuration.GetSection(TvdbOption.Path));
+ }
+
+ ///
+ public void ConfigureAspNet(IApplicationBuilder app)
+ {
+ ConfigurationManager.AddTyped(TvdbOption.Path);
+ }
}
}
\ No newline at end of file
diff --git a/Kyoo/Controllers/ConfigurationManager.cs b/Kyoo/Controllers/ConfigurationManager.cs
index c0a63895..32b2e7f7 100644
--- a/Kyoo/Controllers/ConfigurationManager.cs
+++ b/Kyoo/Controllers/ConfigurationManager.cs
@@ -36,7 +36,29 @@ namespace Kyoo.Controllers
_references = references.ToDictionary(x => x.Path, x => x.Type, StringComparer.OrdinalIgnoreCase);
}
- private Type GetType(string path)
+
+ ///
+ public void AddTyped(string path)
+ {
+ foreach (ConfigurationReference confRef in ConfigurationReference.CreateReference(path))
+ _references.Add(confRef.Path, confRef.Type);
+ }
+
+ ///
+ public void AddUntyped(string path)
+ {
+ ConfigurationReference config = ConfigurationReference.CreateUntyped(path);
+ _references.Add(config.Path, config.Type);
+ }
+
+ ///
+ /// Get the type of the resource at the given path
+ ///
+ /// The path of the resource
+ /// The path is not editable or readable
+ /// No configuration exists for the given path
+ /// The type of the resource at the given path
+ private Type _GetType(string path)
{
path = path.Replace("__", ":");
@@ -59,7 +81,7 @@ namespace Kyoo.Controllers
{
path = path.Replace("__", ":");
// TODO handle lists and dictionaries.
- Type type = GetType(path);
+ Type type = _GetType(path);
object ret = _configuration.GetValue(type, path);
if (ret != null)
return ret;
@@ -73,7 +95,7 @@ namespace Kyoo.Controllers
{
path = path.Replace("__", ":");
// TODO handle lists and dictionaries.
- Type type = GetType(path);
+ Type type = _GetType(path);
if (typeof(T).IsAssignableFrom(type))
throw new InvalidCastException($"The type {typeof(T).Name} is not valid for " +
$"a resource of type {type.Name}.");
@@ -84,12 +106,12 @@ namespace Kyoo.Controllers
public async Task EditValue(string path, object value)
{
path = path.Replace("__", ":");
- Type type = GetType(path);
+ Type type = _GetType(path);
value = JObject.FromObject(value).ToObject(type);
if (value == null)
throw new ArgumentException("Invalid value format.");
- ExpandoObject config = ToObject(_configuration);
+ ExpandoObject config = _ToObject(_configuration);
IDictionary configDic = config;
configDic[path] = value;
JObject obj = JObject.FromObject(config);
@@ -104,7 +126,7 @@ namespace Kyoo.Controllers
/// The configuration to transform
/// A strongly typed representation of the configuration.
[SuppressMessage("ReSharper", "RedundantJumpStatement")]
- private ExpandoObject ToObject(IConfiguration config)
+ private ExpandoObject _ToObject(IConfiguration config)
{
ExpandoObject obj = new();
@@ -112,12 +134,12 @@ namespace Kyoo.Controllers
{
try
{
- Type type = GetType(section.Path);
+ Type type = _GetType(section.Path);
obj.TryAdd(section.Key, section.Get(type));
}
catch (ArgumentException)
{
- obj.TryAdd(section.Key, ToUntyped(section));
+ obj.TryAdd(section.Key, _ToUntyped(section));
}
catch
{
@@ -133,13 +155,13 @@ namespace Kyoo.Controllers
///
/// The section to convert
/// The converted section
- private static object ToUntyped(IConfigurationSection config)
+ private static object _ToUntyped(IConfigurationSection config)
{
ExpandoObject obj = new();
foreach (IConfigurationSection section in config.GetChildren())
{
- obj.TryAdd(section.Key, ToUntyped(section));
+ obj.TryAdd(section.Key, _ToUntyped(section));
}
if (!obj.Any())
diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs
index cd0a38f6..230480c6 100644
--- a/Kyoo/Controllers/PluginManager.cs
+++ b/Kyoo/Controllers/PluginManager.cs
@@ -22,7 +22,7 @@ namespace Kyoo.Controllers
///
/// The service provider. It allow plugin's activation.
///
- private readonly IServiceProvider _provider;
+ private IServiceProvider _provider;
///
/// The configuration to get the plugin's directory.
///
@@ -52,6 +52,13 @@ namespace Kyoo.Controllers
_logger = logger;
}
+ public void SetProvider(IServiceProvider provider)
+ {
+ // TODO temporary bullshit to inject services before the configure asp net.
+ // TODO should rework this when the host will be reworked, as well as the asp net configure.
+ _provider = provider;
+ }
+
///
public T GetPlugin(string name)
@@ -128,6 +135,7 @@ namespace Kyoo.Controllers
_logger.LogInformation("Plugin enabled: {Plugins}", _plugins.Select(x => x.Name));
}
+ ///
public void ConfigureContainer(ContainerBuilder builder)
{
foreach (IPlugin plugin in _plugins)
@@ -146,7 +154,11 @@ namespace Kyoo.Controllers
public void ConfigureAspnet(IApplicationBuilder app)
{
foreach (IPlugin plugin in _plugins)
+ {
+ using IServiceScope scope = _provider.CreateScope();
+ Helper.InjectServices(plugin, x => scope.ServiceProvider.GetRequiredService(x));
plugin.ConfigureAspNet(app);
+ }
}
///
diff --git a/Kyoo/Controllers/TaskManager.cs b/Kyoo/Controllers/TaskManager.cs
index a10875c1..980bbab0 100644
--- a/Kyoo/Controllers/TaskManager.cs
+++ b/Kyoo/Controllers/TaskManager.cs
@@ -165,27 +165,12 @@ namespace Kyoo.Controllers
}));
using IServiceScope scope = _provider.CreateScope();
- InjectServices(task, x => scope.ServiceProvider.GetRequiredService(x));
+ Helper.InjectServices(task, x => scope.ServiceProvider.GetRequiredService(x));
await task.Run(args, progress, _taskToken.Token);
- InjectServices(task, _ => null);
+ Helper.InjectServices(task, _ => null);
_logger.LogInformation("Task finished: {Task}", task.Name);
}
- ///
- /// Inject services into the marked properties of the given object.
- ///
- /// The object to inject
- /// The function used to retrieve services. (The function is called immediately)
- private static void InjectServices(ITask obj, [InstantHandle] Func retrieve)
- {
- IEnumerable properties = obj.GetType().GetProperties()
- .Where(x => x.GetCustomAttribute() != null)
- .Where(x => x.CanWrite);
-
- foreach (PropertyInfo property in properties)
- property.SetValue(obj, retrieve(property.PropertyType));
- }
-
///
/// Start tasks that are scheduled for start.
///
diff --git a/Kyoo/CoreModule.cs b/Kyoo/CoreModule.cs
index f19ba596..4d4baf7d 100644
--- a/Kyoo/CoreModule.cs
+++ b/Kyoo/CoreModule.cs
@@ -5,6 +5,7 @@ using Autofac;
using Autofac.Core;
using Autofac.Core.Registration;
using Kyoo.Controllers;
+using Kyoo.Models.Attributes;
using Kyoo.Models.Options;
using Kyoo.Models.Permissions;
using Kyoo.Tasks;
@@ -81,6 +82,11 @@ namespace Kyoo
/// The configuration to use.
///
private readonly IConfiguration _configuration;
+
+ ///
+ /// The configuration manager used to register typed/untyped implementations.
+ ///
+ [Injected] public IConfigurationManager ConfigurationManager { private get; set; }
///
@@ -136,14 +142,9 @@ namespace Kyoo
string publicUrl = _configuration.GetPublicUrl();
services.Configure(_configuration.GetSection(BasicOptions.Path));
- services.AddConfiguration(BasicOptions.Path);
services.Configure(_configuration.GetSection(TaskOptions.Path));
- services.AddConfiguration(TaskOptions.Path);
services.Configure(_configuration.GetSection(MediaOptions.Path));
- services.AddConfiguration(MediaOptions.Path);
- services.AddUntypedConfiguration("database");
- services.AddUntypedConfiguration("logging");
-
+
services.AddControllers()
.AddNewtonsoftJson(x =>
{
@@ -157,6 +158,12 @@ namespace Kyoo
///
public void ConfigureAspNet(IApplicationBuilder app)
{
+ ConfigurationManager.AddTyped(BasicOptions.Path);
+ ConfigurationManager.AddTyped(TaskOptions.Path);
+ ConfigurationManager.AddTyped(MediaOptions.Path);
+ ConfigurationManager.AddUntyped("database");
+ ConfigurationManager.AddUntyped("logging");
+
FileExtensionContentTypeProvider contentTypeProvider = new();
contentTypeProvider.Mappings[".data"] = "application/octet-stream";
app.UseStaticFiles(new StaticFileOptions
diff --git a/Kyoo/Helper.cs b/Kyoo/Helper.cs
new file mode 100644
index 00000000..244f6eec
--- /dev/null
+++ b/Kyoo/Helper.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Reflection;
+using System.Threading.Tasks;
+using JetBrains.Annotations;
+using Kyoo.Models.Attributes;
+using Newtonsoft.Json;
+
+namespace Kyoo
+{
+ public static class Helper
+ {
+ ///
+ /// Inject services into the marked properties of the given object.
+ ///
+ /// The object to inject
+ /// The function used to retrieve services. (The function is called immediately)
+ public static void InjectServices(object obj, [InstantHandle] Func retrieve)
+ {
+ IEnumerable properties = obj.GetType().GetProperties()
+ .Where(x => x.GetCustomAttribute() != null)
+ .Where(x => x.CanWrite);
+
+ foreach (PropertyInfo property in properties)
+ property.SetValue(obj, retrieve(property.PropertyType));
+ }
+
+ ///
+ /// An helper method to get json content from an http server. This is a temporary thing and will probably be
+ /// replaced by a call to the function of the same name in the System.Net.Http.Json namespace when .net6
+ /// gets released.
+ ///
+ /// The http server to use.
+ /// The url to retrieve
+ /// The type of object to convert
+ /// A T representing the json contained at the given url.
+ public static async Task GetFromJsonAsync(this HttpClient client, string url)
+ {
+ HttpResponseMessage ret = await client.GetAsync(url);
+ ret.EnsureSuccessStatusCode();
+ string content = await ret.Content.ReadAsStringAsync();
+ return JsonConvert.DeserializeObject(content);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs
index 9d3c19dd..04a24408 100644
--- a/Kyoo/Startup.cs
+++ b/Kyoo/Startup.cs
@@ -71,7 +71,6 @@ namespace Kyoo
services.AddHttpClient();
- // services.AddTransient(typeof(Lazy<>), typeof(LazyDi<>));
_plugins.ConfigureServices(services);
}
@@ -87,7 +86,7 @@ namespace Kyoo
///
/// The asp net host to configure
/// The host environment (is the app in development mode?)
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
@@ -114,7 +113,9 @@ namespace Kyoo
return next();
});
app.UseResponseCompression();
-
+
+ if (_plugins is PluginManager manager)
+ manager.SetProvider(provider);
_plugins.ConfigureAspnet(app);
app.UseSpa(spa =>