Allow plugins to register services.

This commit is contained in:
Patrick Barron 2020-08-16 17:25:14 -04:00
parent 075ae53d83
commit a77cf53573
7 changed files with 126 additions and 93 deletions

View File

@ -53,7 +53,6 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates; using MediaBrowser.Common.Updates;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Collections;
@ -173,6 +172,8 @@ namespace Emby.Server.Implementations
/// </summary> /// </summary>
protected ILogger<ApplicationHost> Logger { get; } protected ILogger<ApplicationHost> Logger { get; }
protected IServiceCollection ServiceCollection { get; }
private IPlugin[] _plugins; private IPlugin[] _plugins;
/// <summary> /// <summary>
@ -238,9 +239,11 @@ namespace Emby.Server.Implementations
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IStartupOptions options, IStartupOptions options,
IFileSystem fileSystem, IFileSystem fileSystem,
INetworkManager networkManager) INetworkManager networkManager,
IServiceCollection serviceCollection)
{ {
_xmlSerializer = new MyXmlSerializer(); _xmlSerializer = new MyXmlSerializer();
ServiceCollection = serviceCollection;
_networkManager = networkManager; _networkManager = networkManager;
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets; networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
@ -464,7 +467,7 @@ namespace Emby.Server.Implementations
} }
/// <inheritdoc/> /// <inheritdoc/>
public void Init(IServiceCollection serviceCollection) public void Init()
{ {
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber; HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber; HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@ -493,7 +496,7 @@ namespace Emby.Server.Implementations
DiscoverTypes(); DiscoverTypes();
RegisterServices(serviceCollection); RegisterServices();
} }
public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next) public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
@ -502,136 +505,136 @@ namespace Emby.Server.Implementations
/// <summary> /// <summary>
/// Registers services/resources with the service collection that will be available via DI. /// Registers services/resources with the service collection that will be available via DI.
/// </summary> /// </summary>
protected virtual void RegisterServices(IServiceCollection serviceCollection) protected virtual void RegisterServices()
{ {
serviceCollection.AddSingleton(_startupOptions); ServiceCollection.AddSingleton(_startupOptions);
serviceCollection.AddMemoryCache(); ServiceCollection.AddMemoryCache();
serviceCollection.AddSingleton(ConfigurationManager); ServiceCollection.AddSingleton(ConfigurationManager);
serviceCollection.AddSingleton<IApplicationHost>(this); ServiceCollection.AddSingleton<IApplicationHost>(this);
serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths); ServiceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>(); ServiceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
serviceCollection.AddSingleton(_fileSystemManager); ServiceCollection.AddSingleton(_fileSystemManager);
serviceCollection.AddSingleton<TvdbClientManager>(); ServiceCollection.AddSingleton<TvdbClientManager>();
serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>(); ServiceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
serviceCollection.AddSingleton(_networkManager); ServiceCollection.AddSingleton(_networkManager);
serviceCollection.AddSingleton<IIsoManager, IsoManager>(); ServiceCollection.AddSingleton<IIsoManager, IsoManager>();
serviceCollection.AddSingleton<ITaskManager, TaskManager>(); ServiceCollection.AddSingleton<ITaskManager, TaskManager>();
serviceCollection.AddSingleton(_xmlSerializer); ServiceCollection.AddSingleton(_xmlSerializer);
serviceCollection.AddSingleton<IStreamHelper, StreamHelper>(); ServiceCollection.AddSingleton<IStreamHelper, StreamHelper>();
serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>(); ServiceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
serviceCollection.AddSingleton<ISocketFactory, SocketFactory>(); ServiceCollection.AddSingleton<ISocketFactory, SocketFactory>();
serviceCollection.AddSingleton<IInstallationManager, InstallationManager>(); ServiceCollection.AddSingleton<IInstallationManager, InstallationManager>();
serviceCollection.AddSingleton<IZipClient, ZipClient>(); ServiceCollection.AddSingleton<IZipClient, ZipClient>();
serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>(); ServiceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
serviceCollection.AddSingleton<IServerApplicationHost>(this); ServiceCollection.AddSingleton<IServerApplicationHost>(this);
serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths); ServiceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
serviceCollection.AddSingleton(ServerConfigurationManager); ServiceCollection.AddSingleton(ServerConfigurationManager);
serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>(); ServiceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>(); ServiceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>(); ServiceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>(); ServiceCollection.AddSingleton<IUserDataManager, UserDataManager>();
serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>(); ServiceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>(); ServiceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>)); ServiceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>)); ServiceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(); ServiceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>)); ServiceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
serviceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>)); ServiceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>)); ServiceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
serviceCollection.AddSingleton<ILibraryManager, LibraryManager>(); ServiceCollection.AddSingleton<ILibraryManager, LibraryManager>();
serviceCollection.AddSingleton<IMusicManager, MusicManager>(); ServiceCollection.AddSingleton<IMusicManager, MusicManager>();
serviceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>(); ServiceCollection.AddSingleton<ILibraryMonitor, LibraryMonitor>();
serviceCollection.AddSingleton<ISearchEngine, SearchEngine>(); ServiceCollection.AddSingleton<ISearchEngine, SearchEngine>();
serviceCollection.AddSingleton<ServiceController>(); ServiceCollection.AddSingleton<ServiceController>();
serviceCollection.AddSingleton<IHttpServer, HttpListenerHost>(); ServiceCollection.AddSingleton<IHttpServer, HttpListenerHost>();
serviceCollection.AddSingleton<IImageProcessor, ImageProcessor>(); ServiceCollection.AddSingleton<IImageProcessor, ImageProcessor>();
serviceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>(); ServiceCollection.AddSingleton<ITVSeriesManager, TVSeriesManager>();
serviceCollection.AddSingleton<IDeviceManager, DeviceManager>(); ServiceCollection.AddSingleton<IDeviceManager, DeviceManager>();
serviceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>(); ServiceCollection.AddSingleton<IMediaSourceManager, MediaSourceManager>();
serviceCollection.AddSingleton<ISubtitleManager, SubtitleManager>(); ServiceCollection.AddSingleton<ISubtitleManager, SubtitleManager>();
serviceCollection.AddSingleton<IProviderManager, ProviderManager>(); ServiceCollection.AddSingleton<IProviderManager, ProviderManager>();
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required // TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>)); ServiceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
serviceCollection.AddSingleton<IDtoService, DtoService>(); ServiceCollection.AddSingleton<IDtoService, DtoService>();
serviceCollection.AddSingleton<IChannelManager, ChannelManager>(); ServiceCollection.AddSingleton<IChannelManager, ChannelManager>();
serviceCollection.AddSingleton<ISessionManager, SessionManager>(); ServiceCollection.AddSingleton<ISessionManager, SessionManager>();
serviceCollection.AddSingleton<IDlnaManager, DlnaManager>(); ServiceCollection.AddSingleton<IDlnaManager, DlnaManager>();
serviceCollection.AddSingleton<ICollectionManager, CollectionManager>(); ServiceCollection.AddSingleton<ICollectionManager, CollectionManager>();
serviceCollection.AddSingleton<IPlaylistManager, PlaylistManager>(); ServiceCollection.AddSingleton<IPlaylistManager, PlaylistManager>();
serviceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>(); ServiceCollection.AddSingleton<ISyncPlayManager, SyncPlayManager>();
serviceCollection.AddSingleton<LiveTvDtoService>(); ServiceCollection.AddSingleton<LiveTvDtoService>();
serviceCollection.AddSingleton<ILiveTvManager, LiveTvManager>(); ServiceCollection.AddSingleton<ILiveTvManager, LiveTvManager>();
serviceCollection.AddSingleton<IUserViewManager, UserViewManager>(); ServiceCollection.AddSingleton<IUserViewManager, UserViewManager>();
serviceCollection.AddSingleton<INotificationManager, NotificationManager>(); ServiceCollection.AddSingleton<INotificationManager, NotificationManager>();
serviceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>(); ServiceCollection.AddSingleton<IDeviceDiscovery, DeviceDiscovery>();
serviceCollection.AddSingleton<IChapterManager, ChapterManager>(); ServiceCollection.AddSingleton<IChapterManager, ChapterManager>();
serviceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>(); ServiceCollection.AddSingleton<IEncodingManager, MediaEncoder.EncodingManager>();
serviceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>(); ServiceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
serviceCollection.AddSingleton<ISessionContext, SessionContext>(); ServiceCollection.AddSingleton<ISessionContext, SessionContext>();
serviceCollection.AddSingleton<IAuthService, AuthService>(); ServiceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(); ServiceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>(); ServiceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
serviceCollection.AddSingleton<EncodingHelper>(); ServiceCollection.AddSingleton<EncodingHelper>();
serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>(); ServiceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
serviceCollection.AddSingleton<TranscodingJobHelper>(); ServiceCollection.AddSingleton<TranscodingJobHelper>();
} }
/// <summary> /// <summary>
@ -831,6 +834,8 @@ namespace Emby.Server.Implementations
{ {
hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s)); hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
} }
plugin.RegisterServices(ServiceCollection);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -33,30 +33,33 @@ namespace Jellyfin.Server
/// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param> /// <param name="options">The <see cref="StartupOptions" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param> /// <param name="fileSystem">The <see cref="IFileSystem" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param> /// <param name="networkManager">The <see cref="INetworkManager" /> to be used by the <see cref="CoreAppHost" />.</param>
/// <param name="collection">The <see cref="IServiceCollection"/> to be used by the <see cref="CoreAppHost"/>.</param>
public CoreAppHost( public CoreAppHost(
IServerApplicationPaths applicationPaths, IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IStartupOptions options, IStartupOptions options,
IFileSystem fileSystem, IFileSystem fileSystem,
INetworkManager networkManager) INetworkManager networkManager,
IServiceCollection collection)
: base( : base(
applicationPaths, applicationPaths,
loggerFactory, loggerFactory,
options, options,
fileSystem, fileSystem,
networkManager) networkManager,
collection)
{ {
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void RegisterServices(IServiceCollection serviceCollection) protected override void RegisterServices()
{ {
// Register an image encoder // Register an image encoder
bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable(); bool useSkiaEncoder = SkiaEncoder.IsNativeLibAvailable();
Type imageEncoderType = useSkiaEncoder Type imageEncoderType = useSkiaEncoder
? typeof(SkiaEncoder) ? typeof(SkiaEncoder)
: typeof(NullImageEncoder); : typeof(NullImageEncoder);
serviceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType); ServiceCollection.AddSingleton(typeof(IImageEncoder), imageEncoderType);
// Log a warning if the Skia encoder could not be used // Log a warning if the Skia encoder could not be used
if (!useSkiaEncoder) if (!useSkiaEncoder)
@ -71,15 +74,15 @@ namespace Jellyfin.Server
// .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"), // .UseSqlite($"Filename={Path.Combine(ApplicationPaths.DataPath, "jellyfin.db")}"),
// ServiceLifetime.Transient); // ServiceLifetime.Transient);
serviceCollection.AddEventServices(); ServiceCollection.AddEventServices();
serviceCollection.AddSingleton<IEventManager, EventManager>(); ServiceCollection.AddSingleton<IEventManager, EventManager>();
serviceCollection.AddSingleton<JellyfinDbProvider>(); ServiceCollection.AddSingleton<JellyfinDbProvider>();
serviceCollection.AddSingleton<IActivityManager, ActivityManager>(); ServiceCollection.AddSingleton<IActivityManager, ActivityManager>();
serviceCollection.AddSingleton<IUserManager, UserManager>(); ServiceCollection.AddSingleton<IUserManager, UserManager>();
serviceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>(); ServiceCollection.AddSingleton<IDisplayPreferencesManager, DisplayPreferencesManager>();
base.RegisterServices(serviceCollection); base.RegisterServices();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -154,13 +154,15 @@ namespace Jellyfin.Server
ApplicationHost.LogEnvironmentInfo(_logger, appPaths); ApplicationHost.LogEnvironmentInfo(_logger, appPaths);
PerformStaticInitialization(); PerformStaticInitialization();
var serviceCollection = new ServiceCollection();
var appHost = new CoreAppHost( var appHost = new CoreAppHost(
appPaths, appPaths,
_loggerFactory, _loggerFactory,
options, options,
new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths), new ManagedFileSystem(_loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>())); new NetworkManager(_loggerFactory.CreateLogger<NetworkManager>()),
serviceCollection);
try try
{ {
@ -178,8 +180,7 @@ namespace Jellyfin.Server
} }
} }
ServiceCollection serviceCollection = new ServiceCollection(); appHost.Init();
appHost.Init(serviceCollection);
var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build(); var webHost = new WebHostBuilder().ConfigureWebHostBuilder(appHost, serviceCollection, options, startupConfig, appPaths).Build();

View File

@ -116,8 +116,7 @@ namespace MediaBrowser.Common
/// <summary> /// <summary>
/// Initializes this instance. /// Initializes this instance.
/// </summary> /// </summary>
/// <param name="serviceCollection">The service collection.</param> void Init();
void Init(IServiceCollection serviceCollection);
/// <summary> /// <summary>
/// Creates the instance. /// Creates the instance.

View File

@ -6,6 +6,7 @@ using System.Reflection;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
using MediaBrowser.Model.Serialization; using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.DependencyInjection;
namespace MediaBrowser.Common.Plugins namespace MediaBrowser.Common.Plugins
{ {
@ -81,6 +82,16 @@ namespace MediaBrowser.Common.Plugins
{ {
} }
/// <inheritdoc />
public virtual void RegisterServices(IServiceCollection serviceCollection)
{
}
/// <inheritdoc />
public virtual void UnregisterServices(IServiceCollection serviceCollection)
{
}
/// <inheritdoc /> /// <inheritdoc />
public void SetAttributes(string assemblyFilePath, string dataFolderPath, Version assemblyVersion) public void SetAttributes(string assemblyFilePath, string dataFolderPath, Version assemblyVersion)
{ {

View File

@ -2,6 +2,7 @@
using System; using System;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
using Microsoft.Extensions.DependencyInjection;
namespace MediaBrowser.Common.Plugins namespace MediaBrowser.Common.Plugins
{ {
@ -61,6 +62,18 @@ namespace MediaBrowser.Common.Plugins
/// Called when just before the plugin is uninstalled from the server. /// Called when just before the plugin is uninstalled from the server.
/// </summary> /// </summary>
void OnUninstalling(); void OnUninstalling();
/// <summary>
/// Registers the plugin's services to the service collection.
/// </summary>
/// <param name="serviceCollection">The service collection.</param>
void RegisterServices(IServiceCollection serviceCollection);
/// <summary>
/// Unregisters the plugin's services from the service collection.
/// </summary>
/// <param name="serviceCollection">The service collection.</param>
void UnregisterServices(IServiceCollection serviceCollection);
} }
public interface IHasPluginConfiguration public interface IHasPluginConfiguration

View File

@ -72,6 +72,7 @@ namespace MediaBrowser.Api.Tests
var startupConfig = Program.CreateAppConfiguration(commandLineOpts, appPaths); var startupConfig = Program.CreateAppConfiguration(commandLineOpts, appPaths);
ILoggerFactory loggerFactory = new SerilogLoggerFactory(); ILoggerFactory loggerFactory = new SerilogLoggerFactory();
var serviceCollection = new ServiceCollection();
_disposableComponents.Add(loggerFactory); _disposableComponents.Add(loggerFactory);
// Create the app host and initialize it // Create the app host and initialize it
@ -80,10 +81,10 @@ namespace MediaBrowser.Api.Tests
loggerFactory, loggerFactory,
commandLineOpts, commandLineOpts,
new ManagedFileSystem(loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths), new ManagedFileSystem(loggerFactory.CreateLogger<ManagedFileSystem>(), appPaths),
new NetworkManager(loggerFactory.CreateLogger<NetworkManager>())); new NetworkManager(loggerFactory.CreateLogger<NetworkManager>()),
serviceCollection);
_disposableComponents.Add(appHost); _disposableComponents.Add(appHost);
var serviceCollection = new ServiceCollection(); appHost.Init();
appHost.Init(serviceCollection);
// Configure the web host builder // Configure the web host builder
Program.ConfigureWebHostBuilder(builder, appHost, serviceCollection, commandLineOpts, startupConfig, appPaths); Program.ConfigureWebHostBuilder(builder, appHost, serviceCollection, commandLineOpts, startupConfig, appPaths);