Fixing database configuration

There is still broken dependencies when the module is in another assembly
This commit is contained in:
Zoe Roux 2021-05-04 17:59:05 +02:00
parent 709e12191d
commit feb643da2e
10 changed files with 120 additions and 68 deletions

View File

@ -16,13 +16,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="IdentityServer4" Version="4.1.1" /> <PackageReference Include="IdentityServer4" Version="4.1.2" />
<PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.1" /> <PackageReference Include="IdentityServer4.AspNetIdentity" Version="4.1.2" />
<PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.1" /> <PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.2" />
<PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="4.1.1" /> <PackageReference Include="IdentityServer4.EntityFramework.Storage" Version="4.1.2" />
<PackageReference Include="IdentityServer4.Storage" Version="4.1.1" /> <PackageReference Include="IdentityServer4.Storage" Version="4.1.2" />
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" /> <PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.8.9" /> <PackageReference Include="Portable.BouncyCastle" Version="1.8.10" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -84,6 +84,20 @@ namespace Kyoo
return Set<Link<T1, T2>>(); return Set<Link<T1, T2>>();
} }
/// <summary>
/// The default constructor
/// </summary>
protected DatabaseContext() { }
/// <summary>
/// Create a new <see cref="DatabaseContext"/> using specific options
/// </summary>
/// <param name="options">The options to use.</param>
protected DatabaseContext(DbContextOptions options)
: base(options)
{ }
/// <summary> /// <summary>
/// Set basic configurations (like preventing query tracking) /// Set basic configurations (like preventing query tracking)
/// </summary> /// </summary>

View File

@ -12,10 +12,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.5" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" />
<PackageReference Include="Npgsql" Version="5.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -16,11 +16,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3"> <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.5.1" />
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -21,6 +21,11 @@ namespace Kyoo.Postgresql
/// Is this instance in debug mode? /// Is this instance in debug mode?
/// </summary> /// </summary>
private readonly bool _debugMode; private readonly bool _debugMode;
/// <summary>
/// Should the configure step be skipped? This is used when the database is created via DbContextOptions.
/// </summary>
private readonly bool _skipConfigure;
/// <summary> /// <summary>
/// A basic constructor that set default values (query tracker behaviors, mapping enums...) /// A basic constructor that set default values (query tracker behaviors, mapping enums...)
@ -32,6 +37,19 @@ namespace Kyoo.Postgresql
NpgsqlConnection.GlobalTypeMapper.MapEnum<StreamType>(); NpgsqlConnection.GlobalTypeMapper.MapEnum<StreamType>();
} }
/// <summary>
/// Create a new <see cref="PostgresContext"/> using specific options
/// </summary>
/// <param name="options">The options to use.</param>
public PostgresContext(DbContextOptions options)
: base(options)
{
NpgsqlConnection.GlobalTypeMapper.MapEnum<Status>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<ItemType>();
NpgsqlConnection.GlobalTypeMapper.MapEnum<StreamType>();
_skipConfigure = true;
}
/// <summary> /// <summary>
/// A basic constructor that set default values (query tracker behaviors, mapping enums...) /// A basic constructor that set default values (query tracker behaviors, mapping enums...)
/// </summary> /// </summary>
@ -49,10 +67,13 @@ namespace Kyoo.Postgresql
/// <param name="optionsBuilder">An option builder to fill.</param> /// <param name="optionsBuilder">An option builder to fill.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
optionsBuilder.UseNpgsql(_connection); if (!_skipConfigure)
if (_debugMode) {
optionsBuilder.EnableDetailedErrors() optionsBuilder.UseNpgsql(_connection);
.EnableSensitiveDataLogging(); if (_debugMode)
optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging();
}
base.OnConfiguring(optionsBuilder); base.OnConfiguring(optionsBuilder);
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using Kyoo.Controllers; using Kyoo.Controllers;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
@ -59,9 +60,16 @@ namespace Kyoo.Postgresql
/// <inheritdoc /> /// <inheritdoc />
public void Configure(IServiceCollection services, ICollection<Type> availableTypes) public void Configure(IServiceCollection services, ICollection<Type> availableTypes)
{ {
services.AddScoped<DatabaseContext>(_ => new PostgresContext( services.AddDbContext<DatabaseContext, PostgresContext>(x =>
_configuration.GetDatabaseConnection("postgres"), {
_environment.IsDevelopment())); x.UseNpgsql(_configuration.GetDatabaseConnection("postgres"));
if (_environment.IsDevelopment())
x.EnableDetailedErrors().EnableSensitiveDataLogging();
});
// services.AddScoped<DatabaseContext>(_ => new PostgresContext(
// _configuration.GetDatabaseConnection("postgres"),
// _environment.IsDevelopment()));
// services.AddScoped<DbContext>(x => x.GetRequiredService<PostgresContext>());
} }
} }
} }

View File

@ -14,14 +14,14 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.5" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>
<PackageReference Include="coverlet.collector" Version="1.3.0"> <PackageReference Include="coverlet.collector" Version="3.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
</PackageReference> </PackageReference>

View File

@ -69,6 +69,31 @@ namespace Kyoo.Controllers
return _plugins; return _plugins;
} }
/// <summary>
/// Load a single plugin and return all IPlugin implementations contained in the Assembly.
/// </summary>
/// <param name="path">The path of the dll</param>
/// <returns>The list of dlls in hte assembly</returns>
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<IPlugin>();
}
}
/// <inheritdoc /> /// <inheritdoc />
public void LoadPlugins(ICollection<IPlugin> plugins) public void LoadPlugins(ICollection<IPlugin> plugins)
{ {
@ -78,27 +103,12 @@ namespace Kyoo.Controllers
_logger.LogTrace("Loading new plugins..."); _logger.LogTrace("Loading new plugins...");
string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories); string[] pluginsPaths = Directory.GetFiles(pluginFolder, "*.dll", SearchOption.AllDirectories);
plugins = pluginsPaths.SelectMany(path => plugins = plugins.Concat(pluginsPaths.SelectMany(LoadPlugin))
{ .GroupBy(x => x.Name)
path = Path.GetFullPath(path); .Select(x => x.First())
try .ToList();
{
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<IPlugin>();
}
}).Concat(plugins).ToList();
ICollection<Type> available = GetProvidedTypes(); ICollection<Type> available = GetProvidedTypes(plugins);
_plugins.AddRange(plugins.Where(plugin => _plugins.AddRange(plugins.Where(plugin =>
{ {
Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x))); Type missing = plugin.Requires.FirstOrDefault(x => available.All(y => !y.IsAssignableTo(x)));
@ -119,7 +129,7 @@ namespace Kyoo.Controllers
/// <inheritdoc /> /// <inheritdoc />
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
ICollection<Type> available = GetProvidedTypes(); ICollection<Type> available = GetProvidedTypes(_plugins);
foreach (IPlugin plugin in _plugins) foreach (IPlugin plugin in _plugins)
plugin.Configure(services, available); plugin.Configure(services, available);
} }
@ -134,11 +144,12 @@ namespace Kyoo.Controllers
/// <summary> /// <summary>
/// Get the list of types provided by the currently loaded plugins. /// Get the list of types provided by the currently loaded plugins.
/// </summary> /// </summary>
/// <param name="plugins">The list of plugins that will be used as a plugin pool to get provided types.</param>
/// <returns>The list of types available.</returns> /// <returns>The list of types available.</returns>
private ICollection<Type> GetProvidedTypes() private ICollection<Type> GetProvidedTypes(ICollection<IPlugin> plugins)
{ {
List<Type> available = _plugins.SelectMany(x => x.Provides).ToList(); List<Type> available = plugins.SelectMany(x => x.Provides).ToList();
List<ConditionalProvide> conditionals =_plugins List<ConditionalProvide> conditionals = plugins
.SelectMany(x => x.ConditionalProvides) .SelectMany(x => x.ConditionalProvides)
.Where(x => x.Condition.Condition()) .Where(x => x.Condition.Condition())
.ToList(); .ToList();
@ -199,6 +210,14 @@ namespace Kyoo.Controllers
/// <inheritdoc /> /// <inheritdoc />
protected override Assembly Load(AssemblyName assemblyName) 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); string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath != null) if (assemblyPath != null)
return LoadFromAssemblyPath(assemblyPath); return LoadFromAssemblyPath(assemblyPath);

View File

@ -36,17 +36,11 @@
<ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" /> <ProjectReference Include="../Kyoo.Common/Kyoo.Common.csproj" />
<ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" /> <ProjectReference Include="../Kyoo.CommonAPI/Kyoo.CommonAPI.csproj" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" /> <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.5" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.12" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="3.1.14" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.3" /> <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="5.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Abstractions" Version="5.0.3" /> <ProjectReference Include="..\Kyoo.Postgresql\Kyoo.Postgresql.csproj" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -2,6 +2,7 @@ using System;
using System.IO; using System.IO;
using Kyoo.Controllers; using Kyoo.Controllers;
using Kyoo.Models; using Kyoo.Models;
using Kyoo.Postgresql;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SpaServices.AngularCli; using Microsoft.AspNetCore.SpaServices.AngularCli;
@ -39,12 +40,12 @@ namespace Kyoo
/// </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) public Startup(IServiceProvider hostProvider, IConfiguration configuration, ILoggerFactory loggerFactory, IWebHostEnvironment host)
{ {
_configuration = configuration; _configuration = configuration;
_plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>()); _plugins = new PluginManager(hostProvider, _configuration, loggerFactory.CreateLogger<PluginManager>());
_plugins.LoadPlugins(new [] {new CoreModule()}); _plugins.LoadPlugins(new IPlugin[] {new CoreModule(), new PostgresModule(configuration, host)});
} }
/// <summary> /// <summary>
@ -132,13 +133,13 @@ namespace Kyoo
}); });
app.UseResponseCompression(); app.UseResponseCompression();
app.UseSpa(spa => // app.UseSpa(spa =>
{ // {
spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp"); // spa.Options.SourcePath = Path.Join(AppDomain.CurrentDomain.BaseDirectory, "Kyoo.WebApp");
//
if (env.IsDevelopment()) // if (env.IsDevelopment())
spa.UseAngularCliServer("start"); // spa.UseAngularCliServer("start");
}); // });
_plugins.ConfigureAspnet(app); _plugins.ConfigureAspnet(app);