using System; using System.Collections.Generic; using System.Reflection; using Jellyfin.Database.Providers.Sqlite; using Jellyfin.Server.Implementations.DatabaseConfiguration; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Configuration; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using JellyfinDbProviderFactory = System.Func; namespace Jellyfin.Server.Implementations.Extensions; /// /// Extensions for the interface. /// public static class ServiceCollectionExtensions { private static IEnumerable DatabaseProviderTypes() { yield return typeof(SqliteDatabaseProvider); } private static IDictionary GetSupportedDbProviders() { var items = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (var providerType in DatabaseProviderTypes()) { var keyAttribute = providerType.GetCustomAttribute(); if (keyAttribute is null || string.IsNullOrWhiteSpace(keyAttribute.DatabaseProviderKey)) { continue; } var provider = providerType; items[keyAttribute.DatabaseProviderKey] = (services) => (IJellyfinDatabaseProvider)ActivatorUtilities.CreateInstance(services, providerType); } return items; } /// /// Adds the interface to the service collection with second level caching enabled. /// /// An instance of the interface. /// The server configuration manager. /// The startup Configuration. /// The updated service collection. public static IServiceCollection AddJellyfinDbContext( this IServiceCollection serviceCollection, IServerConfigurationManager configurationManager, IConfiguration configuration) { var efCoreConfiguration = configurationManager.GetConfiguration("database"); var providers = GetSupportedDbProviders(); JellyfinDbProviderFactory? providerFactory = null; if (efCoreConfiguration?.DatabaseType is null) { var cmdMigrationArgument = configuration.GetValue("migration-provider"); if (!string.IsNullOrWhiteSpace(cmdMigrationArgument)) { efCoreConfiguration = new DatabaseConfigurationOptions() { DatabaseType = cmdMigrationArgument, }; } else { // when nothing is setup via new Database configuration, fallback to SQLite with default settings. efCoreConfiguration = new DatabaseConfigurationOptions() { DatabaseType = "Jellyfin-SQLite", }; configurationManager.SaveConfiguration("database", efCoreConfiguration); } } if (!providers.TryGetValue(efCoreConfiguration.DatabaseType.ToUpperInvariant(), out providerFactory!)) { throw new InvalidOperationException($"Jellyfin cannot find the database provider of type '{efCoreConfiguration.DatabaseType}'. Supported types are {string.Join(", ", providers.Keys)}"); } serviceCollection.AddSingleton(providerFactory!); serviceCollection.AddPooledDbContextFactory((serviceProvider, opt) => { var provider = serviceProvider.GetRequiredService(); provider.Initialise(opt); }); return serviceCollection; } }