aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/ApplicationHost.cs
diff options
context:
space:
mode:
authorBaronGreenback <jimcartlidge@yahoo.co.uk>2020-10-17 09:26:14 +0100
committerGitHub <noreply@github.com>2020-10-17 09:26:14 +0100
commitd42bb515ce3692abd9295008872c7f9d62b47652 (patch)
tree53743242f3b34aeeb24334572e50d67dc9f92727 /Emby.Server.Implementations/ApplicationHost.cs
parent75efb8f52d4234bfdefa2a0ac48f7261aa9ef58b (diff)
parent86090ab1f65c66958c897cacd04221c537053eb3 (diff)
Merge branch 'master' into video-resolver
Diffstat (limited to 'Emby.Server.Implementations/ApplicationHost.cs')
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs469
1 files changed, 277 insertions, 192 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index be4e05a64..31ca73829 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -38,23 +38,24 @@ using Emby.Server.Implementations.LiveTv;
using Emby.Server.Implementations.Localization;
using Emby.Server.Implementations.Net;
using Emby.Server.Implementations.Playlists;
+using Emby.Server.Implementations.Plugins;
+using Emby.Server.Implementations.QuickConnect;
using Emby.Server.Implementations.ScheduledTasks;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
-using Emby.Server.Implementations.Services;
using Emby.Server.Implementations.Session;
+using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
-using Emby.Server.Implementations.SyncPlay;
-using MediaBrowser.Api;
+using Jellyfin.Api.Helpers;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
+using MediaBrowser.Common.Json;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
-using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Collections;
@@ -73,13 +74,14 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.QuickConnect;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.Controller.TV;
using MediaBrowser.Controller.SyncPlay;
+using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Configuration;
@@ -90,20 +92,20 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Services;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Plugins.TheTvdb;
+using MediaBrowser.Providers.Plugins.Tmdb;
using MediaBrowser.Providers.Subtitles;
-using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
-using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Prometheus.DotNetRuntime;
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
+using WebSocketManager = Emby.Server.Implementations.HttpServer.WebSocketManager;
namespace Emby.Server.Implementations
{
@@ -120,18 +122,22 @@ namespace Emby.Server.Implementations
private readonly IFileSystem _fileSystemManager;
private readonly INetworkManager _networkManager;
private readonly IXmlSerializer _xmlSerializer;
+ private readonly IJsonSerializer _jsonSerializer;
private readonly IStartupOptions _startupOptions;
private IMediaEncoder _mediaEncoder;
private ISessionManager _sessionManager;
- private IHttpServer _httpServer;
- private IHttpClient _httpClient;
+ private IHttpClientFactory _httpClientFactory;
+
+ private string[] _urlPrefixes;
/// <summary>
/// Gets a value indicating whether this instance can self restart.
/// </summary>
public bool CanSelfRestart => _startupOptions.RestartPath != null;
+ public bool CoreStartupHasCompleted { get; private set; }
+
public virtual bool CanLaunchWebBrowser
{
get
@@ -173,7 +179,9 @@ namespace Emby.Server.Implementations
/// <summary>
/// Gets the logger.
/// </summary>
- protected ILogger Logger { get; }
+ protected ILogger<ApplicationHost> Logger { get; }
+
+ protected IServiceCollection ServiceCollection { get; }
private IPlugin[] _plugins;
@@ -192,7 +200,7 @@ namespace Emby.Server.Implementations
/// Gets or sets the application paths.
/// </summary>
/// <value>The application paths.</value>
- protected ServerApplicationPaths ApplicationPaths { get; set; }
+ protected IServerApplicationPaths ApplicationPaths { get; set; }
/// <summary>
/// Gets or sets all concrete types.
@@ -233,16 +241,26 @@ namespace Emby.Server.Implementations
public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
/// <summary>
- /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
+ /// Initializes a new instance of the <see cref="ApplicationHost"/> class.
/// </summary>
+ /// <param name="applicationPaths">Instance of the <see cref="IServerApplicationPaths"/> interface.</param>
+ /// <param name="loggerFactory">Instance of the <see cref="ILoggerFactory"/> interface.</param>
+ /// <param name="options">Instance of the <see cref="IStartupOptions"/> interface.</param>
+ /// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
+ /// <param name="networkManager">Instance of the <see cref="INetworkManager"/> interface.</param>
+ /// <param name="serviceCollection">Instance of the <see cref="IServiceCollection"/> interface.</param>
public ApplicationHost(
- ServerApplicationPaths applicationPaths,
+ IServerApplicationPaths applicationPaths,
ILoggerFactory loggerFactory,
IStartupOptions options,
IFileSystem fileSystem,
- INetworkManager networkManager)
+ INetworkManager networkManager,
+ IServiceCollection serviceCollection)
{
_xmlSerializer = new MyXmlSerializer();
+ _jsonSerializer = new JsonSerializer();
+
+ ServiceCollection = serviceCollection;
_networkManager = networkManager;
networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
@@ -273,6 +291,10 @@ namespace Emby.Server.Implementations
Password = ServerConfigurationManager.Configuration.CertificatePassword
};
Certificate = GetCertificate(CertificateInfo);
+
+ ApplicationVersion = typeof(ApplicationHost).Assembly.GetName().Version;
+ ApplicationVersionString = ApplicationVersion.ToString(3);
+ ApplicationUserAgent = Name.Replace(' ', '-') + "/" + ApplicationVersionString;
}
public string ExpandVirtualPath(string path)
@@ -302,16 +324,16 @@ namespace Emby.Server.Implementations
}
/// <inheritdoc />
- public Version ApplicationVersion { get; } = typeof(ApplicationHost).Assembly.GetName().Version;
+ public Version ApplicationVersion { get; }
/// <inheritdoc />
- public string ApplicationVersionString { get; } = typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
+ public string ApplicationVersionString { get; }
/// <summary>
/// Gets the current application user agent.
/// </summary>
/// <value>The application user agent.</value>
- public string ApplicationUserAgent => Name.Replace(' ', '-') + "/" + ApplicationVersionString;
+ public string ApplicationUserAgent { get; }
/// <summary>
/// Gets the email address for use within a comment section of a user agent field.
@@ -442,8 +464,7 @@ namespace Emby.Server.Implementations
Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
Logger.LogInformation("Core startup complete");
- _httpServer.GlobalResponse = null;
-
+ CoreStartupHasCompleted = true;
stopWatch.Restart();
await Task.WhenAll(StartEntryPoints(entryPoints, false)).ConfigureAwait(false);
Logger.LogInformation("Executed all post-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
@@ -466,7 +487,7 @@ namespace Emby.Server.Implementations
}
/// <inheritdoc/>
- public void Init(IServiceCollection serviceCollection)
+ public void Init()
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
@@ -484,12 +505,10 @@ namespace Emby.Server.Implementations
foreach (var plugin in Plugins)
{
- pluginBuilder.AppendLine(
- string.Format(
- CultureInfo.InvariantCulture,
- "{0} {1}",
- plugin.Name,
- plugin.Version));
+ pluginBuilder.Append(plugin.Name)
+ .Append(' ')
+ .Append(plugin.Version)
+ .AppendLine();
}
Logger.LogInformation("Plugins: {Plugins}", pluginBuilder.ToString());
@@ -497,150 +516,142 @@ namespace Emby.Server.Implementations
DiscoverTypes();
- RegisterServices(serviceCollection);
+ RegisterServices();
}
- public Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
- => _httpServer.RequestHandler(context);
-
/// <summary>
/// Registers services/resources with the service collection that will be available via DI.
/// </summary>
- protected virtual void RegisterServices(IServiceCollection serviceCollection)
+ protected virtual void RegisterServices()
{
- serviceCollection.AddSingleton(_startupOptions);
-
- serviceCollection.AddMemoryCache();
-
- serviceCollection.AddSingleton(ConfigurationManager);
- serviceCollection.AddSingleton<IApplicationHost>(this);
-
- serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
-
- serviceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
+ ServiceCollection.AddSingleton(_startupOptions);
- serviceCollection.AddSingleton(_fileSystemManager);
- serviceCollection.AddSingleton<TvdbClientManager>();
+ ServiceCollection.AddMemoryCache();
- serviceCollection.AddSingleton<IHttpClient, HttpClientManager.HttpClientManager>();
+ ServiceCollection.AddSingleton(ConfigurationManager);
+ ServiceCollection.AddSingleton<IApplicationHost>(this);
- serviceCollection.AddSingleton(_networkManager);
+ ServiceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
- serviceCollection.AddSingleton<IIsoManager, IsoManager>();
+ ServiceCollection.AddSingleton<IJsonSerializer, JsonSerializer>();
- serviceCollection.AddSingleton<ITaskManager, TaskManager>();
+ ServiceCollection.AddSingleton(_fileSystemManager);
+ ServiceCollection.AddSingleton<TvdbClientManager>();
+ ServiceCollection.AddSingleton<TmdbClientManager>();
- serviceCollection.AddSingleton(_xmlSerializer);
+ ServiceCollection.AddSingleton(_networkManager);
- serviceCollection.AddSingleton<IStreamHelper, StreamHelper>();
+ ServiceCollection.AddSingleton<IIsoManager, IsoManager>();
- serviceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
+ ServiceCollection.AddSingleton<ITaskManager, TaskManager>();
- serviceCollection.AddSingleton<ISocketFactory, SocketFactory>();
+ ServiceCollection.AddSingleton(_xmlSerializer);
- serviceCollection.AddSingleton<IInstallationManager, InstallationManager>();
+ ServiceCollection.AddSingleton<IStreamHelper, StreamHelper>();
- serviceCollection.AddSingleton<IZipClient, ZipClient>();
+ ServiceCollection.AddSingleton<ICryptoProvider, CryptographyProvider>();
- serviceCollection.AddSingleton<IHttpResultFactory, HttpResultFactory>();
+ ServiceCollection.AddSingleton<ISocketFactory, SocketFactory>();
- serviceCollection.AddSingleton<IServerApplicationHost>(this);
- serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
+ ServiceCollection.AddSingleton<IInstallationManager, InstallationManager>();
- serviceCollection.AddSingleton(ServerConfigurationManager);
+ ServiceCollection.AddSingleton<IZipClient, ZipClient>();
- serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
+ ServiceCollection.AddSingleton<IServerApplicationHost>(this);
+ ServiceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
- serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
+ ServiceCollection.AddSingleton(ServerConfigurationManager);
- serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
- serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
+ ServiceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
- serviceCollection.AddSingleton<IDisplayPreferencesRepository, SqliteDisplayPreferencesRepository>();
+ ServiceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
- serviceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
+ ServiceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
+ ServiceCollection.AddSingleton<IUserDataManager, UserDataManager>();
- serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
+ ServiceCollection.AddSingleton<IItemRepository, SqliteItemRepository>();
- serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
+ ServiceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
// 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.AddSingleton<IUserManager, UserManager>();
+ 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: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
- serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
- serviceCollection.AddSingleton<IMediaEncoder>(provider =>
- ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty));
+ ServiceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
+ ServiceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
// 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<IProviderManager>(provider.GetRequiredService<IProviderManager>));
- serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
- serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
+ ServiceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
+ ServiceCollection.AddTransient(provider => new Lazy<IProviderManager>(provider.GetRequiredService<IProviderManager>));
+ ServiceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
+ 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<IHttpServer, HttpListenerHost>();
+ ServiceCollection.AddSingleton<IWebSocketManager, WebSocketManager>();
- 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
- serviceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
- serviceCollection.AddSingleton<IDtoService, DtoService>();
+ ServiceCollection.AddTransient(provider => new Lazy<ILiveTvManager>(provider.GetRequiredService<ILiveTvManager>));
+ 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<ILiveTvManager, LiveTvManager>();
+ ServiceCollection.AddSingleton<LiveTvDtoService>();
+ 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<ISessionContext, SessionContext>();
+ ServiceCollection.AddSingleton<IAuthorizationContext, AuthorizationContext>();
+ ServiceCollection.AddSingleton<ISessionContext, SessionContext>();
- serviceCollection.AddSingleton<IAuthService, AuthService>();
+ ServiceCollection.AddSingleton<IAuthService, AuthService>();
+ ServiceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();
- serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
+ ServiceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();
- serviceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
- serviceCollection.AddSingleton<EncodingHelper>();
+ ServiceCollection.AddSingleton<IResourceFileManager, ResourceFileManager>();
+ ServiceCollection.AddSingleton<EncodingHelper>();
- serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
+ ServiceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();
+
+ ServiceCollection.AddSingleton<TranscodingJobHelper>();
+ ServiceCollection.AddScoped<MediaInfoHelper>();
+ ServiceCollection.AddScoped<AudioHelper>();
+ ServiceCollection.AddScoped<DynamicHlsHelper>();
}
/// <summary>
@@ -654,20 +665,14 @@ namespace Emby.Server.Implementations
_mediaEncoder = Resolve<IMediaEncoder>();
_sessionManager = Resolve<ISessionManager>();
- _httpServer = Resolve<IHttpServer>();
- _httpClient = Resolve<IHttpClient>();
+ _httpClientFactory = Resolve<IHttpClientFactory>();
- ((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
- ((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
SetStaticProperties();
- var userManager = (UserManager)Resolve<IUserManager>();
- userManager.Initialize();
-
var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
- ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
+ ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, Resolve<IUserManager>());
FindParts();
}
@@ -750,7 +755,6 @@ namespace Emby.Server.Implementations
BaseItem.ProviderManager = Resolve<IProviderManager>();
BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
BaseItem.ItemRepository = Resolve<IItemRepository>();
- User.UserManager = Resolve<IUserManager>();
BaseItem.FileSystem = _fileSystemManager;
BaseItem.UserDataManager = Resolve<IUserDataManager>();
BaseItem.ChannelManager = Resolve<IChannelManager>();
@@ -762,7 +766,6 @@ namespace Emby.Server.Implementations
CollectionFolder.XmlSerializer = _xmlSerializer;
CollectionFolder.JsonSerializer = Resolve<IJsonSerializer>();
CollectionFolder.ApplicationHost = this;
- AuthenticatedAttribute.AuthService = Resolve<IAuthService>();
}
/// <summary>
@@ -782,7 +785,7 @@ namespace Emby.Server.Implementations
.Where(i => i != null)
.ToArray();
- _httpServer.Init(GetExportTypes<IService>(), GetExports<IWebSocketListener>(), GetUrlPrefixes());
+ _urlPrefixes = GetUrlPrefixes().ToArray();
Resolve<ILibraryManager>().AddParts(
GetExports<IResolverIgnoreRule>(),
@@ -807,7 +810,6 @@ namespace Emby.Server.Implementations
Resolve<IMediaSourceManager>().AddParts(GetExports<IMediaSourceProvider>());
Resolve<INotificationManager>().AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
- Resolve<IUserManager>().AddParts(GetExports<IAuthenticationProvider>(), GetExports<IPasswordResetProvider>());
Resolve<IIsoManager>().AddParts(GetExports<IIsoMounter>());
}
@@ -816,37 +818,7 @@ namespace Emby.Server.Implementations
{
try
{
- if (plugin is IPluginAssembly assemblyPlugin)
- {
- var assembly = plugin.GetType().Assembly;
- var assemblyName = assembly.GetName();
- var assemblyFilePath = assembly.Location;
-
- var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath));
-
- assemblyPlugin.SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version);
-
- try
- {
- var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
- if (idAttributes.Length > 0)
- {
- var attribute = (GuidAttribute)idAttributes[0];
- var assemblyId = new Guid(attribute.Value);
-
- assemblyPlugin.SetId(assemblyId);
- }
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error getting plugin Id from {PluginName}.", plugin.GetType().FullName);
- }
- }
-
- if (plugin is IHasPluginConfiguration hasPluginConfiguration)
- {
- hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
- }
+ plugin.RegisterServices(ServiceCollection);
}
catch (Exception ex)
{
@@ -881,6 +853,11 @@ namespace Emby.Server.Implementations
Logger.LogError(ex, "Error getting exported types from {Assembly}", ass.FullName);
continue;
}
+ catch (TypeLoadException ex)
+ {
+ Logger.LogError(ex, "Error loading types from {Assembly}.", ass.FullName);
+ continue;
+ }
foreach (Type type in exportedTypes)
{
@@ -942,7 +919,7 @@ namespace Emby.Server.Implementations
}
}
- if (!_httpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
+ if (!_urlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
{
requiresRestart = true;
}
@@ -964,7 +941,7 @@ namespace Emby.Server.Implementations
}
/// <summary>
- /// Notifies that the kernel that a change has been made that requires a restart
+ /// Notifies that the kernel that a change has been made that requires a restart.
/// </summary>
public void NotifyPendingRestart()
{
@@ -1017,6 +994,119 @@ namespace Emby.Server.Implementations
protected abstract void RestartInternal();
/// <summary>
+ /// Comparison function used in <see cref="GetPlugins" />.
+ /// </summary>
+ /// <param name="a">Item to compare.</param>
+ /// <param name="b">Item to compare with.</param>
+ /// <returns>Boolean result of the operation.</returns>
+ private static int VersionCompare(
+ (Version PluginVersion, string Name, string Path) a,
+ (Version PluginVersion, string Name, string Path) b)
+ {
+ int compare = string.Compare(a.Name, b.Name, true, CultureInfo.InvariantCulture);
+
+ if (compare == 0)
+ {
+ return a.PluginVersion.CompareTo(b.PluginVersion);
+ }
+
+ return compare;
+ }
+
+ /// <summary>
+ /// Returns a list of plugins to install.
+ /// </summary>
+ /// <param name="path">Path to check.</param>
+ /// <param name="cleanup">True if an attempt should be made to delete old plugs.</param>
+ /// <returns>Enumerable list of dlls to load.</returns>
+ private IEnumerable<string> GetPlugins(string path, bool cleanup = true)
+ {
+ var dllList = new List<string>();
+ var versions = new List<(Version PluginVersion, string Name, string Path)>();
+ var directories = Directory.EnumerateDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
+ string metafile;
+
+ foreach (var dir in directories)
+ {
+ try
+ {
+ metafile = Path.Combine(dir, "meta.json");
+ if (File.Exists(metafile))
+ {
+ var manifest = _jsonSerializer.DeserializeFromFile<PluginManifest>(metafile);
+
+ if (!Version.TryParse(manifest.TargetAbi, out var targetAbi))
+ {
+ targetAbi = new Version(0, 0, 0, 1);
+ }
+
+ if (!Version.TryParse(manifest.Version, out var version))
+ {
+ version = new Version(0, 0, 0, 1);
+ }
+
+ if (ApplicationVersion >= targetAbi)
+ {
+ // Only load Plugins if the plugin is built for this version or below.
+ versions.Add((version, manifest.Name, dir));
+ }
+ }
+ else
+ {
+ // No metafile, so lets see if the folder is versioned.
+ metafile = dir.Split(new[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries)[^1];
+
+ int versionIndex = dir.LastIndexOf('_');
+ if (versionIndex != -1 && Version.TryParse(dir.Substring(versionIndex + 1), out Version ver))
+ {
+ // Versioned folder.
+ versions.Add((ver, metafile, dir));
+ }
+ else
+ {
+ // Un-versioned folder - Add it under the path name and version 0.0.0.1.
+ versions.Add((new Version(0, 0, 0, 1), metafile, dir));
+ }
+ }
+ }
+ catch
+ {
+ continue;
+ }
+ }
+
+ string lastName = string.Empty;
+ versions.Sort(VersionCompare);
+ // Traverse backwards through the list.
+ // The first item will be the latest version.
+ for (int x = versions.Count - 1; x >= 0; x--)
+ {
+ if (!string.Equals(lastName, versions[x].Name, StringComparison.OrdinalIgnoreCase))
+ {
+ dllList.AddRange(Directory.EnumerateFiles(versions[x].Path, "*.dll", SearchOption.AllDirectories));
+ lastName = versions[x].Name;
+ continue;
+ }
+
+ if (!string.IsNullOrEmpty(lastName) && cleanup)
+ {
+ // Attempt a cleanup of old folders.
+ try
+ {
+ Logger.LogDebug("Deleting {Path}", versions[x].Path);
+ Directory.Delete(versions[x].Path, true);
+ }
+ catch (Exception e)
+ {
+ Logger.LogWarning(e, "Unable to delete {Path}", versions[x].Path);
+ }
+ }
+ }
+
+ return dllList;
+ }
+
+ /// <summary>
/// Gets the composable part assemblies.
/// </summary>
/// <returns>IEnumerable{Assembly}.</returns>
@@ -1024,7 +1114,7 @@ namespace Emby.Server.Implementations
{
if (Directory.Exists(ApplicationPaths.PluginsPath))
{
- foreach (var file in Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories))
+ foreach (var file in GetPlugins(ApplicationPaths.PluginsPath))
{
Assembly plugAss;
try
@@ -1042,12 +1132,6 @@ namespace Emby.Server.Implementations
}
}
- // Include composable parts in the Api assembly
- yield return typeof(ApiEntryPoint).Assembly;
-
- // Include composable parts in the Dashboard assembly
- yield return typeof(DashboardService).Assembly;
-
// Include composable parts in the Model assembly
yield return typeof(SystemInfo).Assembly;
@@ -1144,7 +1228,8 @@ namespace Emby.Server.Implementations
Id = SystemId,
OperatingSystem = OperatingSystem.Id.ToString(),
ServerName = FriendlyName,
- LocalAddress = localAddress
+ LocalAddress = localAddress,
+ StartupWizardCompleted = ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted
};
}
@@ -1163,7 +1248,7 @@ namespace Emby.Server.Implementations
return null;
}
- return GetLocalApiUrl(addresses.First());
+ return GetLocalApiUrl(addresses[0]);
}
catch (Exception ex)
{
@@ -1236,13 +1321,13 @@ namespace Emby.Server.Implementations
var addresses = ServerConfigurationManager
.Configuration
.LocalNetworkAddresses
- .Select(NormalizeConfiguredLocalAddress)
+ .Select(x => NormalizeConfiguredLocalAddress(x))
.Where(i => i != null)
.ToList();
if (addresses.Count == 0)
{
- addresses.AddRange(_networkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
+ addresses.AddRange(_networkManager.GetLocalIpAddresses());
}
var resultList = new List<IPAddress>();
@@ -1257,8 +1342,7 @@ namespace Emby.Server.Implementations
}
}
- var valid = await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false);
- if (valid)
+ if (await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false))
{
resultList.Add(address);
@@ -1272,13 +1356,12 @@ namespace Emby.Server.Implementations
return resultList;
}
- public IPAddress NormalizeConfiguredLocalAddress(string address)
+ public IPAddress NormalizeConfiguredLocalAddress(ReadOnlySpan<char> address)
{
var index = address.Trim('/').IndexOf('/');
-
if (index != -1)
{
- address = address.Substring(index + 1);
+ address = address.Slice(index + 1);
}
if (IPAddress.TryParse(address.Trim('/'), out IPAddress result))
@@ -1308,25 +1391,17 @@ namespace Emby.Server.Implementations
try
{
- using (var response = await _httpClient.SendAsync(
- new HttpRequestOptions
- {
- Url = apiUrl,
- LogErrorResponseBody = false,
- BufferContent = false,
- CancellationToken = cancellationToken
- }, HttpMethod.Post).ConfigureAwait(false))
- {
- using (var reader = new StreamReader(response.Content))
- {
- var result = await reader.ReadToEndAsync().ConfigureAwait(false);
- var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
+ using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
+ using var response = await _httpClientFactory.CreateClient(NamedClient.Default)
+ .SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
- _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
- Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
- return valid;
- }
- }
+ await using var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
+ var result = await System.Text.Json.JsonSerializer.DeserializeAsync<string>(stream, JsonDefaults.GetOptions(), cancellationToken).ConfigureAwait(false);
+ var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
+
+ _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
+ Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
+ return valid;
}
catch (OperationCanceledException)
{
@@ -1404,6 +1479,20 @@ namespace Emby.Server.Implementations
_plugins = list.ToArray();
}
+ public IEnumerable<Assembly> GetApiPluginAssemblies()
+ {
+ var assemblies = _allConcreteTypes
+ .Where(i => typeof(ControllerBase).IsAssignableFrom(i))
+ .Select(i => i.Assembly)
+ .Distinct();
+
+ foreach (var assembly in assemblies)
+ {
+ Logger.LogDebug("Found API endpoints in plugin {Name}", assembly.FullName);
+ yield return assembly;
+ }
+ }
+
public virtual void LaunchUrl(string url)
{
if (!CanLaunchWebBrowser)
@@ -1434,10 +1523,6 @@ namespace Emby.Server.Implementations
}
}
- public virtual void EnableLoopback(string appName)
- {
- }
-
private bool _disposed = false;
/// <summary>