diff --git a/back/ef.rsp b/back/ef.rsp index 4023d566..1205cb29 100644 --- a/back/ef.rsp +++ b/back/ef.rsp @@ -1,2 +1,2 @@ --project -src/Kyoo.Postgresql/Kyoo.Postgresql.csproj +src/Kyoo.Core diff --git a/back/src/Kyoo.Core/CoreModule.cs b/back/src/Kyoo.Core/CoreModule.cs index a72dab49..db5e99e1 100644 --- a/back/src/Kyoo.Core/CoreModule.cs +++ b/back/src/Kyoo.Core/CoreModule.cs @@ -20,6 +20,7 @@ using System; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Kyoo.Core.Controllers; +using Kyoo.Core.Extensions; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; @@ -38,7 +39,7 @@ public static class CoreModule where TRepo : class, IRepository { services.AddScoped(); - services.AddScoped>(x => x.GetRequiredService()); + services.AddScoped>(x => x.GetRequiredService()).AllowLazy(); } public static void ConfigureKyoo(this WebApplicationBuilder builder) diff --git a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs index 9bed18bf..a27509eb 100644 --- a/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs +++ b/back/src/Kyoo.Core/Extensions/ServiceExtensions.cs @@ -16,7 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; using System.Linq; +using System.Linq.Expressions; using System.Text.Json; using System.Text.Json.Serialization; using AspNetCore.Proxy; @@ -83,4 +85,52 @@ public static class ServiceExtensions services.AddProxies(); services.AddHttpClient(); } + + // Stollen from https://stackoverflow.com/questions/44934511/does-net-core-dependency-injection-support-lazyt + public static IServiceCollection AllowLazy(this IServiceCollection services) + { + ServiceDescriptor lastRegistration = services.Last(); + Type serviceType = lastRegistration.ServiceType; + + // The constructor for Lazy expects a Func which is hard to create dynamically. + Type lazyServiceType = typeof(Lazy<>).MakeGenericType(serviceType); + + // Create a typed MethodInfo for `serviceProvider.GetRequiredService`, + // where T has been resolved to the required ServiceType + System.Reflection.MethodInfo? getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions).GetMethod( + nameof(ServiceProviderServiceExtensions.GetRequiredService), + 1, + [typeof(IServiceProvider)] + ); + + System.Reflection.MethodInfo? getRequiredServiceMethodTyped = getRequiredServiceMethod?.MakeGenericMethod( + serviceType + ); + + // Now create a lambda expression equivalent to: + // + // serviceProvider => serviceProvider.GetRequiredService(); + // + ParameterExpression parameterExpr = Expression.Parameter(typeof(IServiceProvider), "serviceLocator"); + LambdaExpression lambda = Expression.Lambda( + Expression.Call(null, getRequiredServiceMethodTyped!, parameterExpr), + parameterExpr + ); + + Delegate lambdaCompiled = lambda.Compile(); + + services.Add( + new ServiceDescriptor( + lazyServiceType, + serviceProvider => + Activator.CreateInstance( + lazyServiceType, + lambdaCompiled.DynamicInvoke(serviceProvider) + )!, + lastRegistration.Lifetime + ) + ); + + return services; + } } diff --git a/back/src/Kyoo.Core/Kyoo.Core.csproj b/back/src/Kyoo.Core/Kyoo.Core.csproj index 49be7338..c1ab42ef 100644 --- a/back/src/Kyoo.Core/Kyoo.Core.csproj +++ b/back/src/Kyoo.Core/Kyoo.Core.csproj @@ -3,6 +3,7 @@ Kyoo.Core Kyoo.Core Exe + kyoo 50 @@ -22,6 +23,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/back/src/Kyoo.Core/Program.cs b/back/src/Kyoo.Core/Program.cs index 3ea03994..ca7eb121 100644 --- a/back/src/Kyoo.Core/Program.cs +++ b/back/src/Kyoo.Core/Program.cs @@ -29,7 +29,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; using Serilog.Templates; @@ -38,7 +37,7 @@ using Serilog.Templates.Themes; #if DEBUG const string EnvironmentName = "Development"; #else - const string EnvironmentName = "Production"; +const string EnvironmentName = "Production"; #endif WebApplicationBuilder builder = WebApplication.CreateBuilder( @@ -72,13 +71,10 @@ AppDomain.CurrentDomain.UnhandledException += (_, ex) => Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception"); builder.Host.UseSerilog(); - -// Set current directory, used by thumbnails for example. -string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); -if (!Directory.Exists(path)) - Directory.CreateDirectory(path); -Environment.CurrentDirectory = path; -Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); +builder + .Services.AddMvcCore() + .AddApplicationPart(typeof(CoreModule).Assembly) + .AddApplicationPart(typeof(AuthenticationModule).Assembly); builder.Services.ConfigureMvc(); builder.Services.ConfigureOpenApi(); @@ -97,6 +93,13 @@ app.UseRouting(); app.UseAuthentication(); app.MapControllers(); +// Set current directory, used by thumbnails for example. +string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); +if (!Directory.Exists(path)) + Directory.CreateDirectory(path); +Environment.CurrentDirectory = path; +Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory); + // Activate services that always run in the background app.Services.GetRequiredService(); app.Services.GetRequiredService(); diff --git a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs index 1ba74dae..7fa428e5 100644 --- a/back/src/Kyoo.Meilisearch/MeilisearchModule.cs +++ b/back/src/Kyoo.Meilisearch/MeilisearchModule.cs @@ -16,6 +16,9 @@ // You should have received a copy of the GNU General Public License // along with Kyoo. If not, see . +using System; +using System.Collections.Generic; +using System.Threading.Tasks; using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Models; using Meilisearch; @@ -151,7 +154,7 @@ public static class MeilisearchModule builder.Configuration.GetValue("MEILI_MASTER_KEY") ) ); - builder.Services.AddSingleton(); + builder.Services.AddScoped(); builder.Services.AddSingleton(); } } diff --git a/back/src/Kyoo.Postgresql/PostgresContext.cs b/back/src/Kyoo.Postgresql/PostgresContext.cs index 9bdaa75d..e3cef657 100644 --- a/back/src/Kyoo.Postgresql/PostgresContext.cs +++ b/back/src/Kyoo.Postgresql/PostgresContext.cs @@ -33,38 +33,15 @@ using Npgsql; namespace Kyoo.Postgresql; -public class PostgresContext : DatabaseContext +public class PostgresContext(DbContextOptions options, IHttpContextAccessor accessor) + : DatabaseContext(options, accessor) { - /// - /// Should the configure step be skipped? This is used when the database is created via DbContextOptions. - /// - private readonly bool _skipConfigure; - - public PostgresContext(DbContextOptions options, IHttpContextAccessor accessor) - : base(options, accessor) - { - _skipConfigure = true; - } - - /// - /// Set connection information for this database context - /// - /// An option builder to fill. protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - if (!_skipConfigure) - { - optionsBuilder.UseNpgsql(); - } - optionsBuilder.UseSnakeCaseNamingConvention(); base.OnConfiguring(optionsBuilder); } - /// - /// Set database parameters to support every types of Kyoo. - /// - /// The database's model builder. protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.HasPostgresEnum();