Fix services provider issues

This commit is contained in:
Zoe Roux 2024-04-01 04:56:18 +02:00
parent 9bd1e50de3
commit 436cbee752
No known key found for this signature in database
7 changed files with 76 additions and 37 deletions

View File

@ -1,2 +1,2 @@
--project --project
src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Core

View File

@ -20,6 +20,7 @@ using System;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Kyoo.Core.Controllers; using Kyoo.Core.Controllers;
using Kyoo.Core.Extensions;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -38,7 +39,7 @@ public static class CoreModule
where TRepo : class, IRepository<T> where TRepo : class, IRepository<T>
{ {
services.AddScoped<TRepo>(); services.AddScoped<TRepo>();
services.AddScoped<IRepository<T>>(x => x.GetRequiredService<TRepo>()); services.AddScoped<IRepository<T>>(x => x.GetRequiredService<TRepo>()).AllowLazy();
} }
public static void ConfigureKyoo(this WebApplicationBuilder builder) public static void ConfigureKyoo(this WebApplicationBuilder builder)

View File

@ -16,7 +16,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Linq; using System.Linq;
using System.Linq.Expressions;
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using AspNetCore.Proxy; using AspNetCore.Proxy;
@ -83,4 +85,52 @@ public static class ServiceExtensions
services.AddProxies(); services.AddProxies();
services.AddHttpClient(); 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<T> expects a Func<T> which is hard to create dynamically.
Type lazyServiceType = typeof(Lazy<>).MakeGenericType(serviceType);
// Create a typed MethodInfo for `serviceProvider.GetRequiredService<T>`,
// 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<T>();
//
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;
}
} }

View File

@ -3,6 +3,7 @@
<AssemblyName>Kyoo.Core</AssemblyName> <AssemblyName>Kyoo.Core</AssemblyName>
<RootNamespace>Kyoo.Core</RootNamespace> <RootNamespace>Kyoo.Core</RootNamespace>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<AssemblyName>kyoo</AssemblyName>
<!-- Limit the number of threads, the default is to not limit so scanning the library <!-- Limit the number of threads, the default is to not limit so scanning the library
create way too many of them and slows the whole server. --> create way too many of them and slows the whole server. -->
<ThreadPoolMaxThreads>50</ThreadPoolMaxThreads> <ThreadPoolMaxThreads>50</ThreadPoolMaxThreads>
@ -22,6 +23,10 @@
<PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.1" /> <PackageReference Include="Serilog.Sinks.SyslogMessages" Version="3.0.1" />
<PackageReference Include="SkiaSharp" Version="2.88.7" /> <PackageReference Include="SkiaSharp" Version="2.88.7" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -29,7 +29,6 @@ using Microsoft.AspNetCore.Builder;
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.Logging;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;
using Serilog.Templates; using Serilog.Templates;
@ -38,7 +37,7 @@ using Serilog.Templates.Themes;
#if DEBUG #if DEBUG
const string EnvironmentName = "Development"; const string EnvironmentName = "Development";
#else #else
const string EnvironmentName = "Production"; const string EnvironmentName = "Production";
#endif #endif
WebApplicationBuilder builder = WebApplication.CreateBuilder( WebApplicationBuilder builder = WebApplication.CreateBuilder(
@ -72,13 +71,10 @@ AppDomain.CurrentDomain.UnhandledException += (_, ex) =>
Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception"); Log.Fatal(ex.ExceptionObject as Exception, "Unhandled exception");
builder.Host.UseSerilog(); builder.Host.UseSerilog();
builder
// Set current directory, used by thumbnails for example. .Services.AddMvcCore()
string path = Path.GetFullPath(builder.Configuration.GetValue("DATADIR", "/kyoo")!); .AddApplicationPart(typeof(CoreModule).Assembly)
if (!Directory.Exists(path)) .AddApplicationPart(typeof(AuthenticationModule).Assembly);
Directory.CreateDirectory(path);
Environment.CurrentDirectory = path;
Log.Information("Data directory: {DataDirectory}", Environment.CurrentDirectory);
builder.Services.ConfigureMvc(); builder.Services.ConfigureMvc();
builder.Services.ConfigureOpenApi(); builder.Services.ConfigureOpenApi();
@ -97,6 +93,13 @@ app.UseRouting();
app.UseAuthentication(); app.UseAuthentication();
app.MapControllers(); 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 // Activate services that always run in the background
app.Services.GetRequiredService<MeiliSync>(); app.Services.GetRequiredService<MeiliSync>();
app.Services.GetRequiredService<RabbitProducer>(); app.Services.GetRequiredService<RabbitProducer>();

View File

@ -16,6 +16,9 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>. // along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Kyoo.Abstractions.Controllers; using Kyoo.Abstractions.Controllers;
using Kyoo.Abstractions.Models; using Kyoo.Abstractions.Models;
using Meilisearch; using Meilisearch;
@ -151,7 +154,7 @@ public static class MeilisearchModule
builder.Configuration.GetValue<string?>("MEILI_MASTER_KEY") builder.Configuration.GetValue<string?>("MEILI_MASTER_KEY")
) )
); );
builder.Services.AddSingleton<ISearchManager, SearchManager>(); builder.Services.AddScoped<ISearchManager, SearchManager>();
builder.Services.AddSingleton<MeiliSync>(); builder.Services.AddSingleton<MeiliSync>();
} }
} }

View File

@ -33,38 +33,15 @@ using Npgsql;
namespace Kyoo.Postgresql; namespace Kyoo.Postgresql;
public class PostgresContext : DatabaseContext public class PostgresContext(DbContextOptions options, IHttpContextAccessor accessor)
: DatabaseContext(options, accessor)
{ {
/// <summary>
/// Should the configure step be skipped? This is used when the database is created via DbContextOptions.
/// </summary>
private readonly bool _skipConfigure;
public PostgresContext(DbContextOptions options, IHttpContextAccessor accessor)
: base(options, accessor)
{
_skipConfigure = true;
}
/// <summary>
/// Set connection information for this database context
/// </summary>
/// <param name="optionsBuilder">An option builder to fill.</param>
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{ {
if (!_skipConfigure)
{
optionsBuilder.UseNpgsql();
}
optionsBuilder.UseSnakeCaseNamingConvention(); optionsBuilder.UseSnakeCaseNamingConvention();
base.OnConfiguring(optionsBuilder); base.OnConfiguring(optionsBuilder);
} }
/// <summary>
/// Set database parameters to support every types of Kyoo.
/// </summary>
/// <param name="modelBuilder">The database's model builder.</param>
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
modelBuilder.HasPostgresEnum<Status>(); modelBuilder.HasPostgresEnum<Status>();