mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-06-27 17:01:16 -04:00
Allow custom plugin provided database providers to be loaded (#14171)
This commit is contained in:
parent
d5672ce407
commit
916e897ed2
4 changed files with 97 additions and 3 deletions
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Jellyfin.Database.Implementations;
|
||||
using Jellyfin.Database.Implementations.DbConfiguration;
|
||||
|
@ -42,6 +44,28 @@ public static class ServiceCollectionExtensions
|
|||
return items;
|
||||
}
|
||||
|
||||
private static JellyfinDbProviderFactory? LoadDatabasePlugin(CustomDatabaseOptions customProviderOptions, IApplicationPaths applicationPaths)
|
||||
{
|
||||
var plugin = Directory.EnumerateDirectories(applicationPaths.PluginsPath)
|
||||
.Where(e => Path.GetFileName(e)!.StartsWith(customProviderOptions.PluginName, StringComparison.OrdinalIgnoreCase))
|
||||
.Order()
|
||||
.FirstOrDefault()
|
||||
?? throw new InvalidOperationException($"The requested custom database plugin with the name '{customProviderOptions.PluginName}' could not been found in '{applicationPaths.PluginsPath}'");
|
||||
|
||||
var dbProviderAssembly = Path.Combine(plugin, Path.ChangeExtension(customProviderOptions.PluginAssembly, "dll"));
|
||||
if (!File.Exists(dbProviderAssembly))
|
||||
{
|
||||
throw new InvalidOperationException($"Could not find the requested assembly at '{dbProviderAssembly}'");
|
||||
}
|
||||
|
||||
// we have to load the assembly without proxy to ensure maximum performance for this.
|
||||
var assembly = Assembly.LoadFrom(dbProviderAssembly);
|
||||
var dbProviderType = assembly.GetExportedTypes().FirstOrDefault(f => f.IsAssignableTo(typeof(IJellyfinDatabaseProvider)))
|
||||
?? throw new InvalidOperationException($"Could not find any type implementing the '{nameof(IJellyfinDatabaseProvider)}' interface.");
|
||||
|
||||
return (services) => (IJellyfinDatabaseProvider)ActivatorUtilities.CreateInstance(services, dbProviderType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="IDbContextFactory{TContext}"/> interface to the service collection with second level caching enabled.
|
||||
/// </summary>
|
||||
|
@ -55,7 +79,6 @@ public static class ServiceCollectionExtensions
|
|||
IConfiguration configuration)
|
||||
{
|
||||
var efCoreConfiguration = configurationManager.GetConfiguration<DatabaseConfigurationOptions>("database");
|
||||
var providers = GetSupportedDbProviders();
|
||||
JellyfinDbProviderFactory? providerFactory = null;
|
||||
|
||||
if (efCoreConfiguration?.DatabaseType is null)
|
||||
|
@ -80,9 +103,22 @@ public static class ServiceCollectionExtensions
|
|||
}
|
||||
}
|
||||
|
||||
if (!providers.TryGetValue(efCoreConfiguration.DatabaseType.ToUpperInvariant(), out providerFactory!))
|
||||
if (efCoreConfiguration.DatabaseType.Equals("PLUGIN_PROVIDER", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException($"Jellyfin cannot find the database provider of type '{efCoreConfiguration.DatabaseType}'. Supported types are {string.Join(", ", providers.Keys)}");
|
||||
if (efCoreConfiguration.CustomProviderOptions is null)
|
||||
{
|
||||
throw new InvalidOperationException("The custom database provider must declare the custom provider options to work");
|
||||
}
|
||||
|
||||
providerFactory = LoadDatabasePlugin(efCoreConfiguration.CustomProviderOptions, configurationManager.ApplicationPaths);
|
||||
}
|
||||
else
|
||||
{
|
||||
var providers = GetSupportedDbProviders();
|
||||
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<IJellyfinDatabaseProvider>(providerFactory!);
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Jellyfin.Database.Implementations.DbConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// The custom value option for custom database providers.
|
||||
/// </summary>
|
||||
public class CustomDatabaseOption
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the key of the value.
|
||||
/// </summary>
|
||||
public required string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value.
|
||||
/// </summary>
|
||||
public required string Value { get; set; }
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Jellyfin.Database.Implementations.DbConfiguration;
|
||||
|
||||
/// <summary>
|
||||
/// Defines the options for a custom database connector.
|
||||
/// </summary>
|
||||
public class CustomDatabaseOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Plugin name to search for database providers.
|
||||
/// </summary>
|
||||
public required string PluginName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the plugin assembly to search for providers.
|
||||
/// </summary>
|
||||
public required string PluginAssembly { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection string for the custom database provider.
|
||||
/// </summary>
|
||||
public required string ConnectionString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of extra options for the custom provider.
|
||||
/// </summary>
|
||||
#pragma warning disable CA2227 // Collection properties should be read only
|
||||
public Collection<CustomDatabaseOption> Options { get; set; } = [];
|
||||
#pragma warning restore CA2227 // Collection properties should be read only
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Jellyfin.Database.Implementations.DbConfiguration;
|
||||
|
||||
/// <summary>
|
||||
|
@ -10,6 +12,11 @@ public class DatabaseConfigurationOptions
|
|||
/// </summary>
|
||||
public required string DatabaseType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the options required to use a custom database provider.
|
||||
/// </summary>
|
||||
public CustomDatabaseOptions? CustomProviderOptions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the kind of locking behavior jellyfin should perform. Possible options are "NoLock", "Pessimistic", "Optimistic".
|
||||
/// Defaults to "NoLock".
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue