From feb643da2edb38ed094e9964c4afd76539d19002 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Tue, 4 May 2021 17:59:05 +0200 Subject: [PATCH] Fixing database configuration There is still broken dependencies when the module is in another assembly --- .../Kyoo.Authentication.csproj | 12 ++-- Kyoo.CommonAPI/DatabaseContext.cs | 14 ++++ Kyoo.CommonAPI/Kyoo.CommonAPI.csproj | 5 +- Kyoo.Postgresql/Kyoo.Postgresql.csproj | 6 +- Kyoo.Postgresql/PostgresContext.cs | 29 ++++++-- Kyoo.Postgresql/PostgresModule.cs | 14 +++- Kyoo.Tests/Kyoo.Tests.csproj | 6 +- Kyoo/Controllers/PluginManager.cs | 67 ++++++++++++------- Kyoo/Kyoo.csproj | 16 ++--- Kyoo/Startup.cs | 19 +++--- 10 files changed, 120 insertions(+), 68 deletions(-) diff --git a/Kyoo.Authentication/Kyoo.Authentication.csproj b/Kyoo.Authentication/Kyoo.Authentication.csproj index 29c2a08a..17107035 100644 --- a/Kyoo.Authentication/Kyoo.Authentication.csproj +++ b/Kyoo.Authentication/Kyoo.Authentication.csproj @@ -16,13 +16,13 @@ - - - - - + + + + + - + diff --git a/Kyoo.CommonAPI/DatabaseContext.cs b/Kyoo.CommonAPI/DatabaseContext.cs index b58710f3..d92c208f 100644 --- a/Kyoo.CommonAPI/DatabaseContext.cs +++ b/Kyoo.CommonAPI/DatabaseContext.cs @@ -84,6 +84,20 @@ namespace Kyoo return Set>(); } + + /// + /// The default constructor + /// + protected DatabaseContext() { } + + /// + /// Create a new using specific options + /// + /// The options to use. + protected DatabaseContext(DbContextOptions options) + : base(options) + { } + /// /// Set basic configurations (like preventing query tracking) /// diff --git a/Kyoo.CommonAPI/Kyoo.CommonAPI.csproj b/Kyoo.CommonAPI/Kyoo.CommonAPI.csproj index 3a2b6456..5288b814 100644 --- a/Kyoo.CommonAPI/Kyoo.CommonAPI.csproj +++ b/Kyoo.CommonAPI/Kyoo.CommonAPI.csproj @@ -12,10 +12,9 @@ - - + + - diff --git a/Kyoo.Postgresql/Kyoo.Postgresql.csproj b/Kyoo.Postgresql/Kyoo.Postgresql.csproj index 65f2f5e5..10887b80 100644 --- a/Kyoo.Postgresql/Kyoo.Postgresql.csproj +++ b/Kyoo.Postgresql/Kyoo.Postgresql.csproj @@ -16,11 +16,7 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + diff --git a/Kyoo.Postgresql/PostgresContext.cs b/Kyoo.Postgresql/PostgresContext.cs index ea220cfc..36ca803e 100644 --- a/Kyoo.Postgresql/PostgresContext.cs +++ b/Kyoo.Postgresql/PostgresContext.cs @@ -21,6 +21,11 @@ namespace Kyoo.Postgresql /// Is this instance in debug mode? /// private readonly bool _debugMode; + + /// + /// Should the configure step be skipped? This is used when the database is created via DbContextOptions. + /// + private readonly bool _skipConfigure; /// /// A basic constructor that set default values (query tracker behaviors, mapping enums...) @@ -32,6 +37,19 @@ namespace Kyoo.Postgresql NpgsqlConnection.GlobalTypeMapper.MapEnum(); } + /// + /// Create a new using specific options + /// + /// The options to use. + public PostgresContext(DbContextOptions options) + : base(options) + { + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + NpgsqlConnection.GlobalTypeMapper.MapEnum(); + _skipConfigure = true; + } + /// /// A basic constructor that set default values (query tracker behaviors, mapping enums...) /// @@ -49,10 +67,13 @@ namespace Kyoo.Postgresql /// An option builder to fill. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - optionsBuilder.UseNpgsql(_connection); - if (_debugMode) - optionsBuilder.EnableDetailedErrors() - .EnableSensitiveDataLogging(); + if (!_skipConfigure) + { + optionsBuilder.UseNpgsql(_connection); + if (_debugMode) + optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging(); + } + base.OnConfiguring(optionsBuilder); } diff --git a/Kyoo.Postgresql/PostgresModule.cs b/Kyoo.Postgresql/PostgresModule.cs index 52453540..df829fdd 100644 --- a/Kyoo.Postgresql/PostgresModule.cs +++ b/Kyoo.Postgresql/PostgresModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Kyoo.Controllers; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -59,9 +60,16 @@ namespace Kyoo.Postgresql /// public void Configure(IServiceCollection services, ICollection availableTypes) { - services.AddScoped(_ => new PostgresContext( - _configuration.GetDatabaseConnection("postgres"), - _environment.IsDevelopment())); + services.AddDbContext(x => + { + x.UseNpgsql(_configuration.GetDatabaseConnection("postgres")); + if (_environment.IsDevelopment()) + x.EnableDetailedErrors().EnableSensitiveDataLogging(); + }); + // services.AddScoped(_ => new PostgresContext( + // _configuration.GetDatabaseConnection("postgres"), + // _environment.IsDevelopment())); + // services.AddScoped(x => x.GetRequiredService()); } } } \ No newline at end of file diff --git a/Kyoo.Tests/Kyoo.Tests.csproj b/Kyoo.Tests/Kyoo.Tests.csproj index 65e01c1f..b5e3dd82 100644 --- a/Kyoo.Tests/Kyoo.Tests.csproj +++ b/Kyoo.Tests/Kyoo.Tests.csproj @@ -14,14 +14,14 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/Kyoo/Controllers/PluginManager.cs b/Kyoo/Controllers/PluginManager.cs index eaf08b97..c17e3230 100644 --- a/Kyoo/Controllers/PluginManager.cs +++ b/Kyoo/Controllers/PluginManager.cs @@ -69,6 +69,31 @@ namespace Kyoo.Controllers return _plugins; } + /// + /// Load a single plugin and return all IPlugin implementations contained in the Assembly. + /// + /// The path of the dll + /// The list of dlls in hte assembly + private IPlugin[] LoadPlugin(string path) + { + path = Path.GetFullPath(path); + try + { + PluginDependencyLoader loader = new(path); + Assembly assembly = loader.LoadFromAssemblyPath(path); + return assembly.GetTypes() + .Where(x => typeof(IPlugin).IsAssignableFrom(x)) + .Where(x => _plugins.All(y => y.GetType() != x)) + .Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)) + .ToArray(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Could not load the plugin at {Path}", path); + return Array.Empty(); + } + } + /// public void LoadPlugins(ICollection plugins) { @@ -78,27 +103,12 @@ namespace Kyoo.Controllers _logger.LogTrace("Loading new plugins..."); string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories); - plugins = pluginsPaths.SelectMany(path => - { - path = Path.GetFullPath(path); - try - { - PluginDependencyLoader loader = new(path); - Assembly assembly = loader.LoadFromAssemblyPath(path); - return assembly.GetTypes() - .Where(x => typeof(IPlugin).IsAssignableFrom(x)) - .Where(x => _plugins.All(y => y.GetType() != x)) - .Select(x => (IPlugin)ActivatorUtilities.CreateInstance(_provider, x)) - .ToArray(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Could not load the plugin at {Path}", path); - return Array.Empty(); - } - }).Concat(plugins).ToList(); + plugins = plugins.Concat(pluginsPaths.SelectMany(LoadPlugin)) + .GroupBy(x => x.Name) + .Select(x => x.First()) + .ToList(); - ICollection available = GetProvidedTypes(); + ICollection available = GetProvidedTypes(plugins); _plugins.AddRange(plugins.Where(plugin => { Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x))); @@ -119,7 +129,7 @@ namespace Kyoo.Controllers /// public void ConfigureServices(IServiceCollection services) { - ICollection available = GetProvidedTypes(); + ICollection available = GetProvidedTypes(_plugins); foreach (IPlugin plugin in _plugins) plugin.Configure(services, available); } @@ -134,11 +144,12 @@ namespace Kyoo.Controllers /// /// Get the list of types provided by the currently loaded plugins. /// + /// The list of plugins that will be used as a plugin pool to get provided types. /// The list of types available. - private ICollection GetProvidedTypes() + private ICollection GetProvidedTypes(ICollection plugins) { - List available = _plugins.SelectMany(x => x.Provides).ToList(); - List conditionals =_plugins + List available = plugins.SelectMany(x => x.Provides).ToList(); + List conditionals = plugins .SelectMany(x => x.ConditionalProvides) .Where(x => x.Condition.Condition()) .ToList(); @@ -199,6 +210,14 @@ namespace Kyoo.Controllers /// protected override Assembly Load(AssemblyName assemblyName) { + Assembly existing = AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(x => + { + AssemblyName name = x.GetName(); + return name.Name == assemblyName.Name && name.Version == assemblyName.Version; + }); + if (existing != null) + return existing; string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); if (assemblyPath != null) return LoadFromAssemblyPath(assemblyPath); diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj index ca011593..d4e376b4 100644 --- a/Kyoo/Kyoo.csproj +++ b/Kyoo/Kyoo.csproj @@ -36,17 +36,11 @@ - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - + + + + + diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index 730d4b37..c267bd00 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -2,6 +2,7 @@ using System; using System.IO; using Kyoo.Controllers; using Kyoo.Models; +using Kyoo.Postgresql; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.SpaServices.AngularCli; @@ -39,12 +40,12 @@ namespace Kyoo /// /// The configuration context /// A logger factory used to create a logger for the plugin manager. - public Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory) + public Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory, IWebHostEnvironment host) { _configuration = configuration; _plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger()); - _plugins.LoadPlugins(new [] {new CoreModule()}); + _plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host)}); } /// @@ -132,13 +133,13 @@ namespace Kyoo }); app.UseResponseCompression(); - app.UseSpa(spa => - { - spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); - - if (env.IsDevelopment()) - spa.UseAngularCliServer("start"); - }); + // app.UseSpa(spa => + // { + // spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); + // + // if (env.IsDevelopment()) + // spa.UseAngularCliServer("start"); + // }); _plugins.ConfigureAspnet(app);