using Emby.Common.Implementations.Serialization;
using Emby.Dlna;
using Emby.Dlna.ConnectionManager;
using Emby.Dlna.ContentDirectory;
using Emby.Dlna.Main;
using Emby.Dlna.MediaReceiverRegistrar;
using Emby.Dlna.Ssdp;
using Emby.Drawing;
using Emby.Photos;
using Emby.Server.Implementations.Activity;
using Emby.Server.Implementations.Archiving;
using Emby.Server.Implementations.Channels;
using Emby.Server.Implementations.Collections;
using Emby.Server.Implementations.Configuration;
using Emby.Server.Implementations.Cryptography;
using Emby.Server.Implementations.Data;
using Emby.Server.Implementations.Devices;
using Emby.Server.Implementations.Diagnostics;
using Emby.Server.Implementations.Dto;
using Emby.Server.Implementations.FFMpeg;
using Emby.Server.Implementations.HttpServer;
using Emby.Server.Implementations.HttpServer.Security;
using Emby.Server.Implementations.IO;
using Emby.Server.Implementations.Library;
using Emby.Server.Implementations.LiveTv;
using Emby.Server.Implementations.Localization;
using Emby.Server.Implementations.MediaEncoder;
using Emby.Server.Implementations.Net;
using Emby.Server.Implementations.Notifications;
using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.Reflection;
using Emby.Server.Implementations.ScheduledTasks;
using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Session;
using Emby.Server.Implementations.Social;
using Emby.Server.Implementations.Threading;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
using Emby.Server.Implementations.Xml;
using Emby.Server.MediaEncoding.Subtitles;
using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Progress;
using MediaBrowser.Common.Security;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Connect;
using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Dlna;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Notifications;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Resolvers;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
using MediaBrowser.Controller.Sync;
using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Activity;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Cryptography;
using MediaBrowser.Model.Diagnostics;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Events;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.News;
using MediaBrowser.Model.Reflection;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using MediaBrowser.Model.Social;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Model.Text;
using MediaBrowser.Model.Threading;
using MediaBrowser.Model.Updates;
using MediaBrowser.Model.Xml;
using MediaBrowser.Providers.Chapters;
using MediaBrowser.Providers.Manager;
using MediaBrowser.Providers.Subtitles;
using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
using OpenSubtitlesHandler;
using ServiceStack;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using StringExtensions = MediaBrowser.Controller.Extensions.StringExtensions;
using X509Certificate = System.Security.Cryptography.X509Certificates.X509Certificate;
namespace Emby.Server.Implementations
{
///
/// Class CompositionRoot
///
public abstract class ApplicationHost : IServerApplicationHost, IDependencyContainer, IDisposable
{
///
/// Gets a value indicating whether this instance can self restart.
///
/// true if this instance can self restart; otherwise, false.
public abstract bool CanSelfRestart { get; }
///
/// Gets or sets a value indicating whether this instance can self update.
///
/// true if this instance can self update; otherwise, false.
public virtual bool CanSelfUpdate
{
get
{
return false;
}
}
///
/// Occurs when [has pending restart changed].
///
public event EventHandler HasPendingRestartChanged;
///
/// Occurs when [application updated].
///
public event EventHandler> ApplicationUpdated;
///
/// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
///
/// true if this instance has pending application restart; otherwise, false.
public bool HasPendingRestart { get; private set; }
public bool IsShuttingDown { get; private set; }
///
/// Gets or sets the logger.
///
/// The logger.
protected ILogger Logger { get; set; }
///
/// Gets or sets the plugins.
///
/// The plugins.
public IPlugin[] Plugins { get; protected set; }
///
/// Gets or sets the log manager.
///
/// The log manager.
public ILogManager LogManager { get; protected set; }
///
/// Gets the application paths.
///
/// The application paths.
protected ServerApplicationPaths ApplicationPaths { get; set; }
///
/// Gets assemblies that failed to load
///
/// The failed assemblies.
public List FailedAssemblies { get; protected set; }
///
/// Gets all concrete types.
///
/// All concrete types.
public Type[] AllConcreteTypes { get; protected set; }
///
/// The disposable parts
///
protected readonly List DisposableParts = new List();
///
/// Gets a value indicating whether this instance is first run.
///
/// true if this instance is first run; otherwise, false.
public bool IsFirstRun { get; private set; }
///
/// Gets the configuration manager.
///
/// The configuration manager.
protected IConfigurationManager ConfigurationManager { get; set; }
public IFileSystem FileSystemManager { get; set; }
protected IEnvironmentInfo EnvironmentInfo { get; set; }
private IBlurayExaminer BlurayExaminer { get; set; }
public PackageVersionClass SystemUpdateLevel
{
get
{
#if BETA
return PackageVersionClass.Beta;
#endif
return PackageVersionClass.Release;
}
}
public virtual string OperatingSystemDisplayName
{
get { return EnvironmentInfo.OperatingSystemName; }
}
///
/// The container
///
protected readonly SimpleInjector.Container Container = new SimpleInjector.Container();
protected ISystemEvents SystemEvents { get; set; }
protected IMemoryStreamFactory MemoryStreamFactory { get; set; }
///
/// Gets the server configuration manager.
///
/// The server configuration manager.
public IServerConfigurationManager ServerConfigurationManager
{
get { return (IServerConfigurationManager)ConfigurationManager; }
}
///
/// Gets the configuration manager.
///
/// IConfigurationManager.
protected IConfigurationManager GetConfigurationManager()
{
return new ServerConfigurationManager(ApplicationPaths, LogManager, XmlSerializer, FileSystemManager);
}
///
/// Gets or sets the server manager.
///
/// The server manager.
private IServerManager ServerManager { get; set; }
///
/// Gets or sets the user manager.
///
/// The user manager.
public IUserManager UserManager { get; set; }
///
/// Gets or sets the library manager.
///
/// The library manager.
internal ILibraryManager LibraryManager { get; set; }
///
/// Gets or sets the directory watchers.
///
/// The directory watchers.
private ILibraryMonitor LibraryMonitor { get; set; }
///
/// Gets or sets the provider manager.
///
/// The provider manager.
private IProviderManager ProviderManager { get; set; }
///
/// Gets or sets the HTTP server.
///
/// The HTTP server.
private IHttpServer HttpServer { get; set; }
private IDtoService DtoService { get; set; }
public IImageProcessor ImageProcessor { get; set; }
///
/// Gets or sets the media encoder.
///
/// The media encoder.
private IMediaEncoder MediaEncoder { get; set; }
private ISubtitleEncoder SubtitleEncoder { get; set; }
private IConnectManager ConnectManager { get; set; }
private ISessionManager SessionManager { get; set; }
private ILiveTvManager LiveTvManager { get; set; }
public ILocalizationManager LocalizationManager { get; set; }
private IEncodingManager EncodingManager { get; set; }
private IChannelManager ChannelManager { get; set; }
private ISyncManager SyncManager { get; set; }
///
/// Gets or sets the user data repository.
///
/// The user data repository.
private IUserDataManager UserDataManager { get; set; }
private IUserRepository UserRepository { get; set; }
internal IDisplayPreferencesRepository DisplayPreferencesRepository { get; set; }
internal IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
private INotificationManager NotificationManager { get; set; }
private ISubtitleManager SubtitleManager { get; set; }
private IChapterManager ChapterManager { get; set; }
private IDeviceManager DeviceManager { get; set; }
internal IUserViewManager UserViewManager { get; set; }
private IAuthenticationRepository AuthenticationRepository { get; set; }
private ITVSeriesManager TVSeriesManager { get; set; }
private ICollectionManager CollectionManager { get; set; }
private IMediaSourceManager MediaSourceManager { get; set; }
private IPlaylistManager PlaylistManager { get; set; }
///
/// Gets or sets the installation manager.
///
/// The installation manager.
protected IInstallationManager InstallationManager { get; private set; }
///
/// Gets the security manager.
///
/// The security manager.
protected ISecurityManager SecurityManager { get; private set; }
///
/// Gets or sets the zip client.
///
/// The zip client.
protected IZipClient ZipClient { get; private set; }
protected IAuthService AuthService { get; private set; }
protected readonly StartupOptions StartupOptions;
protected readonly string ReleaseAssetFilename;
internal IPowerManagement PowerManagement { get; private set; }
internal IImageEncoder ImageEncoder { get; private set; }
protected IProcessFactory ProcessFactory { get; private set; }
protected ITimerFactory TimerFactory { get; private set; }
protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
protected readonly IXmlSerializer XmlSerializer;
protected ISocketFactory SocketFactory { get; private set; }
protected ITaskManager TaskManager { get; private set; }
public IHttpClient HttpClient { get; private set; }
protected INetworkManager NetworkManager { get; set; }
public IJsonSerializer JsonSerializer { get; private set; }
protected IIsoManager IsoManager { get; private set; }
///
/// Initializes a new instance of the class.
///
public ApplicationHost(ServerApplicationPaths applicationPaths,
ILogManager logManager,
StartupOptions options,
IFileSystem fileSystem,
IPowerManagement powerManagement,
string releaseAssetFilename,
IEnvironmentInfo environmentInfo,
IImageEncoder imageEncoder,
ISystemEvents systemEvents,
INetworkManager networkManager)
{
// hack alert, until common can target .net core
BaseExtensions.CryptographyProvider = CryptographyProvider;
XmlSerializer = new MyXmlSerializer(fileSystem, logManager.GetLogger("XmlSerializer"));
NetworkManager = networkManager;
EnvironmentInfo = environmentInfo;
SystemEvents = systemEvents;
MemoryStreamFactory = new MemoryStreamProvider();
FailedAssemblies = new List();
ApplicationPaths = applicationPaths;
LogManager = logManager;
FileSystemManager = fileSystem;
ConfigurationManager = GetConfigurationManager();
// Initialize this early in case the -v command line option is used
Logger = LogManager.GetLogger("App");
StartupOptions = options;
ReleaseAssetFilename = releaseAssetFilename;
PowerManagement = powerManagement;
ImageEncoder = imageEncoder;
SetBaseExceptionMessage();
fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
}
private Version _version;
///
/// Gets the current application version
///
/// The application version.
public Version ApplicationVersion
{
get
{
return _version ?? (_version = GetAssembly(GetType()).GetName().Version);
}
}
private DeviceId _deviceId;
public string SystemId
{
get
{
if (_deviceId == null)
{
_deviceId = new DeviceId(ApplicationPaths, LogManager.GetLogger("SystemId"), FileSystemManager);
}
return _deviceId.Value;
}
}
///
/// Gets the name.
///
/// The name.
public string Name
{
get
{
return "Emby Server";
}
}
private Assembly GetAssembly(Type type)
{
return type.GetTypeInfo().Assembly;
}
public virtual bool SupportsAutoRunAtStartup
{
get
{
return EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows;
}
}
///
/// Creates an instance of type and resolves all constructor dependancies
///
/// The type.
/// System.Object.
public object CreateInstance(Type type)
{
try
{
return Container.GetInstance(type);
}
catch (Exception ex)
{
Logger.ErrorException("Error creating {0}", ex, type.FullName);
throw;
}
}
///
/// Creates the instance safe.
///
/// The type.
/// System.Object.
protected object CreateInstanceSafe(Type type)
{
try
{
return Container.GetInstance(type);
}
catch (Exception ex)
{
Logger.ErrorException("Error creating {0}", ex, type.FullName);
// Don't blow up in release mode
return null;
}
}
///
/// Registers the specified obj.
///
///
/// The obj.
/// if set to true [manage lifetime].
protected void RegisterSingleInstance(T obj, bool manageLifetime = true)
where T : class
{
Container.RegisterSingleton(obj);
if (manageLifetime)
{
var disposable = obj as IDisposable;
if (disposable != null)
{
DisposableParts.Add(disposable);
}
}
}
///
/// Registers the single instance.
///
///
/// The func.
protected void RegisterSingleInstance(Func func)
where T : class
{
Container.RegisterSingleton(func);
}
///
/// Resolves this instance.
///
///
/// ``0.
public T Resolve()
{
return (T)Container.GetRegistration(typeof(T), true).GetInstance();
}
///
/// Resolves this instance.
///
///
/// ``0.
public T TryResolve()
{
var result = Container.GetRegistration(typeof(T), false);
if (result == null)
{
return default(T);
}
return (T)result.GetInstance();
}
///
/// Loads the assembly.
///
/// The file.
/// Assembly.
protected Assembly LoadAssembly(string file)
{
try
{
return Assembly.Load(File.ReadAllBytes(file));
}
catch (Exception ex)
{
FailedAssemblies.Add(file);
Logger.ErrorException("Error loading assembly {0}", ex, file);
return null;
}
}
///
/// Gets the export types.
///
///
/// IEnumerable{Type}.
public IEnumerable GetExportTypes()
{
var currentType = typeof(T);
return AllConcreteTypes.Where(currentType.IsAssignableFrom);
}
///
/// Gets the exports.
///
///
/// if set to true [manage liftime].
/// IEnumerable{``0}.
public IEnumerable GetExports(bool manageLiftime = true)
{
var parts = GetExportTypes()
.Select(CreateInstanceSafe)
.Where(i => i != null)
.Cast()
.ToList();
if (manageLiftime)
{
lock (DisposableParts)
{
DisposableParts.AddRange(parts.OfType());
}
}
return parts;
}
private void SetBaseExceptionMessage()
{
var builder = GetBaseExceptionMessage(ApplicationPaths);
builder.Insert(0, string.Format("Version: {0}{1}", ApplicationVersion, Environment.NewLine));
builder.Insert(0, "*** Error Report ***" + Environment.NewLine);
LogManager.ExceptionMessagePrefix = builder.ToString();
}
///
/// Runs the startup tasks.
///
public async Task RunStartupTasks()
{
Resolve().AddTasks(GetExports(false));
ConfigureAutorun();
ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
await MediaEncoder.Init().ConfigureAwait(false);
if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath))
{
if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
{
ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false;
ServerConfigurationManager.SaveConfiguration();
}
}
Logger.Info("ServerId: {0}", SystemId);
Logger.Info("Core startup complete");
HttpServer.GlobalResponse = null;
Logger.Info("Post-init migrations complete");
foreach (var entryPoint in GetExports().ToList())
{
var name = entryPoint.GetType().FullName;
Logger.Info("Starting entry point {0}", name);
var now = DateTime.UtcNow;
try
{
entryPoint.Run();
}
catch (Exception ex)
{
Logger.ErrorException("Error in {0}", ex, name);
}
Logger.Info("Entry point completed: {0}. Duration: {1} seconds", name, (DateTime.UtcNow - now).TotalSeconds.ToString(CultureInfo.InvariantCulture), "ImageInfos");
}
Logger.Info("All entry points have started");
LogManager.RemoveConsoleOutput();
}
///
/// Configures the autorun.
///
private void ConfigureAutorun()
{
try
{
ConfigureAutoRunAtStartup(ConfigurationManager.CommonConfiguration.RunAtStartup);
}
catch (Exception ex)
{
Logger.ErrorException("Error configuring autorun", ex);
}
}
private IJsonSerializer CreateJsonSerializer()
{
try
{
// https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4
Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0=");
}
catch
{
// Failing under mono
}
return new JsonSerializer(FileSystemManager, LogManager.GetLogger("JsonSerializer"));
}
public async Task Init(IProgress progress)
{
HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
// Safeguard against invalid configuration
if (HttpPort == HttpsPort)
{
HttpPort = ServerConfiguration.DefaultHttpPort;
HttpsPort = ServerConfiguration.DefaultHttpsPort;
}
progress.Report(1);
JsonSerializer = CreateJsonSerializer();
OnLoggerLoaded(true);
LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false);
IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted;
progress.Report(2);
LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
? LogSeverity.Debug
: LogSeverity.Info;
progress.Report(3);
DiscoverTypes();
progress.Report(14);
SetHttpLimit();
progress.Report(15);
var innerProgress = new ActionableProgress();
innerProgress.RegisterAction(p => progress.Report(.8 * p + 15));
await RegisterResources(innerProgress).ConfigureAwait(false);
FindParts();
progress.Report(95);
await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false);
progress.Report(100);
}
protected virtual void OnLoggerLoaded(bool isFirstLoad)
{
Logger.Info("Application version: {0}", ApplicationVersion);
if (!isFirstLoad)
{
LogEnvironmentInfo(Logger, ApplicationPaths, false);
}
// Put the app config in the log for troubleshooting purposes
var configJson = new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration));
if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePassword))
{
configJson = configJson.Replace(ServerConfigurationManager.Configuration.CertificatePassword, "####");
}
Logger.LogMultiline("Application configuration:", LogSeverity.Info, configJson);
if (Plugins != null)
{
var pluginBuilder = new StringBuilder();
foreach (var plugin in Plugins)
{
pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
}
Logger.LogMultiline("Plugins:", LogSeverity.Info, pluginBuilder);
}
}
protected abstract IConnectManager CreateConnectManager();
protected abstract ISyncManager CreateSyncManager();
protected virtual IHttpClient CreateHttpClient()
{
return new HttpClientManager.HttpClientManager(ApplicationPaths, LogManager.GetLogger("HttpClient"), FileSystemManager, MemoryStreamFactory, GetDefaultUserAgent);
}
///
/// Registers resources that classes will depend on
///
protected async Task RegisterResources(IProgress progress)
{
RegisterSingleInstance(ConfigurationManager);
RegisterSingleInstance(this);
RegisterSingleInstance(ApplicationPaths);
RegisterSingleInstance(JsonSerializer);
RegisterSingleInstance(MemoryStreamFactory);
RegisterSingleInstance(SystemEvents);
RegisterSingleInstance(LogManager, false);
RegisterSingleInstance(Logger);
RegisterSingleInstance(EnvironmentInfo);
RegisterSingleInstance(FileSystemManager);
HttpClient = CreateHttpClient();
RegisterSingleInstance(HttpClient);
RegisterSingleInstance(NetworkManager);
IsoManager = new IsoManager();
RegisterSingleInstance(IsoManager);
TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LogManager.GetLogger("TaskManager"), FileSystemManager, SystemEvents);
RegisterSingleInstance(TaskManager);
RegisterSingleInstance(XmlSerializer);
ProcessFactory = new ProcessFactory();
RegisterSingleInstance(ProcessFactory);
TimerFactory = new TimerFactory();
RegisterSingleInstance(TimerFactory);
RegisterSingleInstance(CryptographyProvider);
SocketFactory = new SocketFactory(LogManager.GetLogger("SocketFactory"));
RegisterSingleInstance(SocketFactory);
RegisterSingleInstance(PowerManagement);
SecurityManager = new PluginSecurityManager(this, HttpClient, JsonSerializer, ApplicationPaths, LogManager, FileSystemManager, CryptographyProvider);
RegisterSingleInstance(SecurityManager);
InstallationManager = new InstallationManager(LogManager.GetLogger("InstallationManager"), this, ApplicationPaths, HttpClient, JsonSerializer, SecurityManager, ConfigurationManager, FileSystemManager, CryptographyProvider, PackageRuntime);
RegisterSingleInstance(InstallationManager);
ZipClient = new ZipClient(FileSystemManager);
RegisterSingleInstance(ZipClient);
RegisterSingleInstance(new HttpResultFactory(LogManager, FileSystemManager, JsonSerializer, MemoryStreamFactory));
RegisterSingleInstance(this);
RegisterSingleInstance(ApplicationPaths);
RegisterSingleInstance(ServerConfigurationManager);
IAssemblyInfo assemblyInfo = new AssemblyInfo();
RegisterSingleInstance(assemblyInfo);
LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LogManager.GetLogger("LocalizationManager"), assemblyInfo, new TextLocalizer());
StringExtensions.LocalizationManager = LocalizationManager;
RegisterSingleInstance(LocalizationManager);
ITextEncoding textEncoding = new TextEncoding.TextEncoding(FileSystemManager, LogManager.GetLogger("TextEncoding"), JsonSerializer);
RegisterSingleInstance(textEncoding);
Utilities.EncodingHelper = textEncoding;
BlurayExaminer = new BdInfoExaminer(FileSystemManager, textEncoding);
RegisterSingleInstance(BlurayExaminer);
RegisterSingleInstance(new XmlReaderSettingsFactory());
UserDataManager = new UserDataManager(LogManager, ServerConfigurationManager);
RegisterSingleInstance(UserDataManager);
UserRepository = GetUserRepository();
// This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
RegisterSingleInstance(UserRepository);
var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LogManager.GetLogger("SqliteDisplayPreferencesRepository"), JsonSerializer, ApplicationPaths, MemoryStreamFactory, FileSystemManager);
DisplayPreferencesRepository = displayPreferencesRepo;
RegisterSingleInstance(DisplayPreferencesRepository);
var itemRepo = new SqliteItemRepository(ServerConfigurationManager, JsonSerializer, LogManager.GetLogger("SqliteItemRepository"), MemoryStreamFactory, assemblyInfo, FileSystemManager, EnvironmentInfo, TimerFactory);
ItemRepository = itemRepo;
RegisterSingleInstance(ItemRepository);
AuthenticationRepository = GetAuthenticationRepository();
RegisterSingleInstance(AuthenticationRepository);
UserManager = new UserManager(LogManager.GetLogger("UserManager"), ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, () => ConnectManager, this, JsonSerializer, FileSystemManager, CryptographyProvider);
RegisterSingleInstance(UserManager);
LibraryManager = new LibraryManager(Logger, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
RegisterSingleInstance(LibraryManager);
var musicManager = new MusicManager(LibraryManager);
RegisterSingleInstance(new MusicManager(LibraryManager));
LibraryMonitor = new LibraryMonitor(LogManager, TaskManager, LibraryManager, ServerConfigurationManager, FileSystemManager, TimerFactory, SystemEvents, EnvironmentInfo);
RegisterSingleInstance(LibraryMonitor);
ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, LibraryMonitor, LogManager, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer, MemoryStreamFactory);
RegisterSingleInstance(ProviderManager);
RegisterSingleInstance(() => new SearchEngine(LogManager, LibraryManager, UserManager));
CertificateInfo = GetCertificateInfo(true);
Certificate = GetCertificate(CertificateInfo);
HttpServer = HttpServerFactory.CreateServer(this, LogManager, ServerConfigurationManager, NetworkManager, MemoryStreamFactory, "Emby", "web/index.html", textEncoding, SocketFactory, CryptographyProvider, JsonSerializer, XmlSerializer, EnvironmentInfo, Certificate, FileSystemManager, SupportsDualModeSockets);
HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
RegisterSingleInstance(HttpServer, false);
progress.Report(10);
ServerManager = new ServerManager.ServerManager(this, JsonSerializer, LogManager.GetLogger("ServerManager"), ServerConfigurationManager, MemoryStreamFactory, textEncoding);
RegisterSingleInstance(ServerManager);
var innerProgress = new ActionableProgress();
innerProgress.RegisterAction(p => progress.Report((.75 * p) + 15));
ImageProcessor = GetImageProcessor();
RegisterSingleInstance(ImageProcessor);
TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
RegisterSingleInstance(TVSeriesManager);
SyncManager = CreateSyncManager();
RegisterSingleInstance(SyncManager);
DtoService = new DtoService(LogManager.GetLogger("DtoService"), LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ServerConfigurationManager, FileSystemManager, ProviderManager, () => ChannelManager, SyncManager, this, () => DeviceManager, () => MediaSourceManager, () => LiveTvManager);
RegisterSingleInstance(DtoService);
var encryptionManager = new EncryptionManager();
RegisterSingleInstance(encryptionManager);
ConnectManager = CreateConnectManager();
RegisterSingleInstance(ConnectManager);
var deviceRepo = new SqliteDeviceRepository(LogManager.GetLogger("DeviceManager"), ServerConfigurationManager, FileSystemManager, JsonSerializer);
deviceRepo.Initialize();
DeviceManager = new DeviceManager(deviceRepo, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager, LogManager.GetLogger("DeviceManager"), NetworkManager);
RegisterSingleInstance(deviceRepo);
RegisterSingleInstance(DeviceManager);
var newsService = new Emby.Server.Implementations.News.NewsService(ApplicationPaths, JsonSerializer);
RegisterSingleInstance(newsService);
progress.Report(15);
ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LogManager.GetLogger("ChannelManager"), ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
RegisterSingleInstance(ChannelManager);
MediaSourceManager = new MediaSourceManager(ItemRepository, UserManager, LibraryManager, LogManager.GetLogger("MediaSourceManager"), JsonSerializer, FileSystemManager, UserDataManager, TimerFactory);
RegisterSingleInstance(MediaSourceManager);
SessionManager = new SessionManager(UserDataManager, LogManager.GetLogger("SessionManager"), LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager, TimerFactory);
RegisterSingleInstance(SessionManager);
var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LogManager.GetLogger("Dlna"), JsonSerializer, this, assemblyInfo);
RegisterSingleInstance(dlnaManager);
var connectionManager = new ConnectionManager(dlnaManager, ServerConfigurationManager, LogManager.GetLogger("UpnpConnectionManager"), HttpClient, new XmlReaderSettingsFactory());
RegisterSingleInstance(connectionManager);
CollectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("CollectionManager"), ProviderManager);
RegisterSingleInstance(CollectionManager);
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LogManager.GetLogger("PlaylistManager"), UserManager, ProviderManager);
RegisterSingleInstance(PlaylistManager);
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, Logger, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, SecurityManager);
RegisterSingleInstance(LiveTvManager);
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
RegisterSingleInstance(UserViewManager);
var contentDirectory = new ContentDirectory(dlnaManager, UserDataManager, ImageProcessor, LibraryManager, ServerConfigurationManager, UserManager, LogManager.GetLogger("UpnpContentDirectory"), HttpClient, LocalizationManager, ChannelManager, MediaSourceManager, UserViewManager, () => MediaEncoder, new XmlReaderSettingsFactory(), TVSeriesManager);
RegisterSingleInstance(contentDirectory);
var mediaRegistrar = new MediaReceiverRegistrar(LogManager.GetLogger("MediaReceiverRegistrar"), HttpClient, ServerConfigurationManager, new XmlReaderSettingsFactory());
RegisterSingleInstance(mediaRegistrar);
NotificationManager = new NotificationManager(LogManager, UserManager, ServerConfigurationManager);
RegisterSingleInstance(NotificationManager);
SubtitleManager = new SubtitleManager(LogManager.GetLogger("SubtitleManager"), FileSystemManager, LibraryMonitor, LibraryManager, MediaSourceManager, ServerConfigurationManager);
RegisterSingleInstance(SubtitleManager);
RegisterSingleInstance(new DeviceDiscovery(LogManager.GetLogger("IDeviceDiscovery"), ServerConfigurationManager, SocketFactory, TimerFactory));
ChapterManager = new ChapterManager(LibraryManager, LogManager.GetLogger("ChapterManager"), ServerConfigurationManager, ItemRepository);
RegisterSingleInstance(ChapterManager);
await RegisterMediaEncoder(innerProgress).ConfigureAwait(false);
progress.Report(90);
EncodingManager = new EncodingManager(FileSystemManager, Logger, MediaEncoder, ChapterManager, LibraryManager);
RegisterSingleInstance(EncodingManager);
var sharingRepo = new SharingRepository(LogManager.GetLogger("SharingRepository"), ApplicationPaths, FileSystemManager);
sharingRepo.Initialize();
// This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
RegisterSingleInstance(sharingRepo);
RegisterSingleInstance(new SharingManager(sharingRepo, ServerConfigurationManager, LibraryManager, this));
var activityLogRepo = GetActivityLogRepository();
RegisterSingleInstance(activityLogRepo);
RegisterSingleInstance(new ActivityManager(LogManager.GetLogger("ActivityManager"), activityLogRepo, UserManager));
var authContext = new AuthorizationContext(AuthenticationRepository, ConnectManager);
RegisterSingleInstance(authContext);
RegisterSingleInstance(new SessionContext(UserManager, authContext, SessionManager));
AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, ConnectManager, SessionManager, DeviceManager);
RegisterSingleInstance(AuthService);
SubtitleEncoder = new SubtitleEncoder(LibraryManager, LogManager.GetLogger("SubtitleEncoder"), ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, MemoryStreamFactory, ProcessFactory, textEncoding);
RegisterSingleInstance(SubtitleEncoder);
displayPreferencesRepo.Initialize();
var userDataRepo = new SqliteUserDataRepository(LogManager.GetLogger("SqliteUserDataRepository"), ApplicationPaths, FileSystemManager);
((UserDataManager)UserDataManager).Repository = userDataRepo;
itemRepo.Initialize(userDataRepo);
((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
ConfigureNotificationsRepository();
progress.Report(100);
SetStaticProperties();
((UserManager)UserManager).Initialize();
}
public virtual string PackageRuntime
{
get
{
return "netframework";
}
}
public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, bool isStartup)
{
logger.LogMultiline("Emby", LogSeverity.Info, GetBaseExceptionMessage(appPaths));
}
protected static StringBuilder GetBaseExceptionMessage(IApplicationPaths appPaths)
{
var builder = new StringBuilder();
builder.AppendLine(string.Format("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs())));
builder.AppendLine(string.Format("Operating system: {0}", Environment.OSVersion));
builder.AppendLine(string.Format("64-Bit OS: {0}", Environment.Is64BitOperatingSystem));
builder.AppendLine(string.Format("64-Bit Process: {0}", Environment.Is64BitProcess));
builder.AppendLine(string.Format("User Interactive: {0}", Environment.UserInteractive));
Type type = Type.GetType("Mono.Runtime");
if (type != null)
{
MethodInfo displayName = type.GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static);
if (displayName != null)
{
builder.AppendLine("Mono: " + displayName.Invoke(null, null));
}
}
builder.AppendLine(string.Format("Processor count: {0}", Environment.ProcessorCount));
builder.AppendLine(string.Format("Program data path: {0}", appPaths.ProgramDataPath));
builder.AppendLine(string.Format("Application directory: {0}", appPaths.ProgramSystemPath));
return builder;
}
private void SetHttpLimit()
{
try
{
// Increase the max http request limit
ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
}
catch (Exception ex)
{
Logger.ErrorException("Error setting http limit", ex);
}
}
///
/// Installs the iso mounters.
///
/// The cancellation token.
/// Task.
private async Task InstallIsoMounters(CancellationToken cancellationToken)
{
var list = new List();
foreach (var isoMounter in GetExports())
{
try
{
if (isoMounter.RequiresInstallation && !isoMounter.IsInstalled)
{
Logger.Info("Installing {0}", isoMounter.Name);
await isoMounter.Install(cancellationToken).ConfigureAwait(false);
}
list.Add(isoMounter);
}
catch (Exception ex)
{
Logger.ErrorException("{0} failed to load.", ex, isoMounter.Name);
}
}
IsoManager.AddParts(list);
}
protected string GetDefaultUserAgent()
{
var name = FormatAttribute(Name);
return name + "/" + ApplicationVersion;
}
private string FormatAttribute(string str)
{
var arr = str.ToCharArray();
arr = Array.FindAll(arr, (c => (char.IsLetterOrDigit(c)
|| char.IsWhiteSpace(c))));
var result = new string(arr);
if (string.IsNullOrWhiteSpace(result))
{
result = "Emby";
}
return result;
}
protected virtual bool SupportsDualModeSockets
{
get
{
return true;
}
}
private X509Certificate GetCertificate(CertificateInfo info)
{
var certificateLocation = info == null ? null : info.Path;
if (string.IsNullOrWhiteSpace(certificateLocation))
{
return null;
}
try
{
if (!FileSystemManager.FileExists(certificateLocation))
{
return null;
}
// Don't use an empty string password
var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password;
X509Certificate2 localCert = new X509Certificate2(certificateLocation, password);
//localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
if (!localCert.HasPrivateKey)
{
//throw new FileNotFoundException("Secure requested, no private key included", certificateLocation);
return null;
}
return localCert;
}
catch (Exception ex)
{
Logger.ErrorException("Error loading cert from {0}", ex, certificateLocation);
return null;
}
}
private IImageProcessor GetImageProcessor()
{
return new ImageProcessor(LogManager.GetLogger("ImageProcessor"), ServerConfigurationManager.ApplicationPaths, FileSystemManager, JsonSerializer, ImageEncoder, () => LibraryManager, TimerFactory, () => MediaEncoder);
}
protected virtual FFMpegInstallInfo GetFfmpegInstallInfo()
{
var info = new FFMpegInstallInfo();
// Windows builds: http://ffmpeg.zeranoe.com/builds/
// Linux builds: http://johnvansickle.com/ffmpeg/
// OS X builds: http://ffmpegmac.net/
// OS X x64: http://www.evermeet.cx/ffmpeg/
if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Linux)
{
info.FFMpegFilename = "ffmpeg";
info.FFProbeFilename = "ffprobe";
info.ArchiveType = "7z";
info.Version = "20170308";
info.DownloadUrls = GetLinuxDownloadUrls();
}
else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
{
info.FFMpegFilename = "ffmpeg.exe";
info.FFProbeFilename = "ffprobe.exe";
info.Version = "20170308";
info.ArchiveType = "7z";
info.DownloadUrls = GetWindowsDownloadUrls();
}
else if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
{
info.FFMpegFilename = "ffmpeg";
info.FFProbeFilename = "ffprobe";
info.ArchiveType = "7z";
info.Version = "20170308";
info.DownloadUrls = GetMacDownloadUrls();
}
else
{
// No version available - user requirement
info.DownloadUrls = new string[] { };
}
return info;
}
private string[] GetMacDownloadUrls()
{
switch (EnvironmentInfo.SystemArchitecture)
{
case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
"https://embydata.com/downloads/ffmpeg/osx/ffmpeg-x64-20170308.7z"
};
}
return new string[] { };
}
private string[] GetWindowsDownloadUrls()
{
switch (EnvironmentInfo.SystemArchitecture)
{
case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
"https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win64.7z"
};
case MediaBrowser.Model.System.Architecture.X86:
return new[]
{
"https://embydata.com/downloads/ffmpeg/windows/ffmpeg-20170308-win32.7z"
};
}
return new string[] { };
}
private string[] GetLinuxDownloadUrls()
{
switch (EnvironmentInfo.SystemArchitecture)
{
case MediaBrowser.Model.System.Architecture.X64:
return new[]
{
"https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-64bit-static.7z"
};
case MediaBrowser.Model.System.Architecture.X86:
return new[]
{
"https://embydata.com/downloads/ffmpeg/linux/ffmpeg-git-20170301-32bit-static.7z"
};
}
return new string[] { };
}
///
/// Registers the media encoder.
///
/// Task.
private async Task RegisterMediaEncoder(IProgress progress)
{
string encoderPath = null;
string probePath = null;
var info = await new FFMpegLoader(Logger, ApplicationPaths, HttpClient, ZipClient, FileSystemManager, GetFfmpegInstallInfo())
.GetFFMpegInfo(StartupOptions, progress).ConfigureAwait(false);
encoderPath = info.EncoderPath;
probePath = info.ProbePath;
var hasExternalEncoder = string.Equals(info.Version, "external", StringComparison.OrdinalIgnoreCase);
var mediaEncoder = new MediaEncoding.Encoder.MediaEncoder(LogManager.GetLogger("MediaEncoder"),
JsonSerializer,
encoderPath,
probePath,
hasExternalEncoder,
ServerConfigurationManager,
FileSystemManager,
LiveTvManager,
IsoManager,
LibraryManager,
ChannelManager,
SessionManager,
() => SubtitleEncoder,
() => MediaSourceManager,
HttpClient,
ZipClient,
MemoryStreamFactory,
ProcessFactory,
(Environment.ProcessorCount > 2 ? 14000 : 40000),
EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows,
EnvironmentInfo,
BlurayExaminer);
MediaEncoder = mediaEncoder;
RegisterSingleInstance(MediaEncoder);
}
///
/// Gets the user repository.
///
/// Task{IUserRepository}.
private IUserRepository GetUserRepository()
{
var repo = new SqliteUserRepository(LogManager.GetLogger("SqliteUserRepository"), ApplicationPaths, JsonSerializer, MemoryStreamFactory);
repo.Initialize();
return repo;
}
private IAuthenticationRepository GetAuthenticationRepository()
{
var repo = new AuthenticationRepository(LogManager.GetLogger("AuthenticationRepository"), ServerConfigurationManager.ApplicationPaths);
repo.Initialize();
return repo;
}
private IActivityRepository GetActivityLogRepository()
{
var repo = new ActivityRepository(LogManager.GetLogger("ActivityRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
repo.Initialize();
return repo;
}
///
/// Configures the repositories.
///
private void ConfigureNotificationsRepository()
{
var repo = new SqliteNotificationsRepository(LogManager.GetLogger("SqliteNotificationsRepository"), ServerConfigurationManager.ApplicationPaths, FileSystemManager);
repo.Initialize();
NotificationsRepository = repo;
RegisterSingleInstance(NotificationsRepository);
}
///
/// Dirty hacks
///
private void SetStaticProperties()
{
// For now there's no real way to inject these properly
BaseItem.Logger = LogManager.GetLogger("BaseItem");
BaseItem.ConfigurationManager = ServerConfigurationManager;
BaseItem.LibraryManager = LibraryManager;
BaseItem.ProviderManager = ProviderManager;
BaseItem.LocalizationManager = LocalizationManager;
BaseItem.ItemRepository = ItemRepository;
User.XmlSerializer = XmlSerializer;
User.UserManager = UserManager;
Folder.UserManager = UserManager;
BaseItem.FileSystem = FileSystemManager;
BaseItem.UserDataManager = UserDataManager;
BaseItem.ChannelManager = ChannelManager;
BaseItem.LiveTvManager = LiveTvManager;
Folder.UserViewManager = UserViewManager;
UserView.TVSeriesManager = TVSeriesManager;
UserView.PlaylistManager = PlaylistManager;
BaseItem.CollectionManager = CollectionManager;
BaseItem.MediaSourceManager = MediaSourceManager;
CollectionFolder.XmlSerializer = XmlSerializer;
Utilities.CryptographyProvider = CryptographyProvider;
AuthenticatedAttribute.AuthService = AuthService;
}
///
/// Finds the parts.
///
protected void FindParts()
{
if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
{
RegisterServerWithAdministratorAccess();
ServerConfigurationManager.Configuration.IsPortAuthorized = true;
ConfigurationManager.SaveConfiguration();
}
RegisterModules();
ConfigurationManager.AddParts(GetExports());
Plugins = GetExports().Select(LoadPlugin).Where(i => i != null).ToArray();
HttpServer.Init(GetExports(false));
ServerManager.AddWebSocketListeners(GetExports(false));
StartServer();
LibraryManager.AddParts(GetExports(),
GetExports(),
GetExports(),
GetExports(),
GetExports(),
GetExports());
ProviderManager.AddParts(GetExports(),
GetExports(),
GetExports(),
GetExports(),
GetExports());
ImageProcessor.AddParts(GetExports());
LiveTvManager.AddParts(GetExports(), GetExports(), GetExports());
SubtitleManager.AddParts(GetExports());
SessionManager.AddParts(GetExports());
ChannelManager.AddParts(GetExports());
MediaSourceManager.AddParts(GetExports());
NotificationManager.AddParts(GetExports(), GetExports());
SyncManager.AddParts(GetExports());
}
private IPlugin LoadPlugin(IPlugin plugin)
{
try
{
var assemblyPlugin = plugin as IPluginAssembly;
if (assemblyPlugin != null)
{
var assembly = plugin.GetType().Assembly;
var assemblyName = assembly.GetName();
var assemblyFileName = assemblyName.Name + ".dll";
var assemblyFilePath = Path.Combine(ApplicationPaths.PluginsPath, assemblyFileName);
assemblyPlugin.SetAttributes(assemblyFilePath, assemblyFileName, 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.ErrorException("Error getting plugin Id from {0}.", ex, plugin.GetType().FullName);
}
}
var isFirstRun = !File.Exists(plugin.ConfigurationFilePath);
plugin.SetStartupInfo(isFirstRun, File.GetLastWriteTimeUtc, s => Directory.CreateDirectory(s));
}
catch (Exception ex)
{
Logger.ErrorException("Error loading plugin {0}", ex, plugin.GetType().FullName);
return null;
}
return plugin;
}
///
/// Discovers the types.
///
protected void DiscoverTypes()
{
FailedAssemblies.Clear();
var assemblies = GetComposablePartAssemblies().ToList();
foreach (var assembly in assemblies)
{
Logger.Info("Loading {0}", assembly.FullName);
}
AllConcreteTypes = assemblies
.SelectMany(GetTypes)
.Where(t => t.IsClass && !t.IsAbstract && !t.IsInterface && !t.IsGenericType)
.ToArray();
}
///
/// Gets a list of types within an assembly
/// This will handle situations that would normally throw an exception - such as a type within the assembly that depends on some other non-existant reference
///
/// The assembly.
/// IEnumerable{Type}.
/// assembly
protected List GetTypes(Assembly assembly)
{
if (assembly == null)
{
return new List();
}
try
{
// This null checking really shouldn't be needed but adding it due to some
// unhandled exceptions in mono 5.0 that are a little hard to hunt down
var types = assembly.GetTypes() ?? new Type[] { };
return types.Where(t => t != null).ToList();
}
catch (ReflectionTypeLoadException ex)
{
if (ex.LoaderExceptions != null)
{
foreach (var loaderException in ex.LoaderExceptions)
{
if (loaderException != null)
{
Logger.Error("LoaderException: " + loaderException.Message);
}
}
}
// If it fails we can still get a list of the Types it was able to resolve
var types = ex.Types ?? new Type[] { };
return types.Where(t => t != null).ToList();
}
catch (Exception ex)
{
Logger.ErrorException("Error loading types from assembly", ex);
return new List();
}
}
private CertificateInfo CertificateInfo { get; set; }
private X509Certificate Certificate { get; set; }
private IEnumerable GetUrlPrefixes()
{
var hosts = new List();
hosts.Add("+");
return hosts.SelectMany(i =>
{
var prefixes = new List
{
"http://"+i+":" + HttpPort + "/"
};
if (CertificateInfo != null)
{
prefixes.Add("https://" + i + ":" + HttpsPort + "/");
}
return prefixes;
});
}
///
/// Starts the server.
///
private void StartServer()
{
try
{
ServerManager.Start(GetUrlPrefixes().ToArray());
return;
}
catch (Exception ex)
{
Logger.ErrorException("Error starting http server", ex);
if (HttpPort == ServerConfiguration.DefaultHttpPort)
{
throw;
}
}
HttpPort = ServerConfiguration.DefaultHttpPort;
try
{
ServerManager.Start(GetUrlPrefixes().ToArray());
}
catch (Exception ex)
{
Logger.ErrorException("Error starting http server", ex);
throw;
}
}
private CertificateInfo GetCertificateInfo(bool generateCertificate)
{
if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath))
{
// Custom cert
return new CertificateInfo
{
Path = ServerConfigurationManager.Configuration.CertificatePath,
Password = ServerConfigurationManager.Configuration.CertificatePassword
};
}
// Generate self-signed cert
var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx");
var password = "embycert";
//if (generateCertificate)
//{
// if (!FileSystemManager.FileExists(certPath))
// {
// FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath));
// try
// {
// CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
// }
// catch (Exception ex)
// {
// Logger.ErrorException("Error creating ssl cert", ex);
// return null;
// }
// }
//}
return new CertificateInfo
{
Path = certPath,
Password = password
};
}
///
/// Called when [configuration updated].
///
/// The sender.
/// The instance containing the event data.
protected void OnConfigurationUpdated(object sender, EventArgs e)
{
ConfigureAutorun();
var requiresRestart = false;
// Don't do anything if these haven't been set yet
if (HttpPort != 0 && HttpsPort != 0)
{
// Need to restart if ports have changed
if (ServerConfigurationManager.Configuration.HttpServerPortNumber != HttpPort ||
ServerConfigurationManager.Configuration.HttpsPortNumber != HttpsPort)
{
if (ServerConfigurationManager.Configuration.IsPortAuthorized)
{
ServerConfigurationManager.Configuration.IsPortAuthorized = false;
ServerConfigurationManager.SaveConfiguration();
requiresRestart = true;
}
}
}
if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
{
requiresRestart = true;
}
var currentCertPath = CertificateInfo == null ? null : CertificateInfo.Path;
var newCertInfo = GetCertificateInfo(false);
var newCertPath = newCertInfo == null ? null : newCertInfo.Path;
if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase))
{
requiresRestart = true;
}
if (requiresRestart)
{
Logger.Info("App needs to be restarted due to configuration change.");
NotifyPendingRestart();
}
}
///
/// Notifies that the kernel that a change has been made that requires a restart
///
public void NotifyPendingRestart()
{
Logger.Info("App needs to be restarted.");
var changed = !HasPendingRestart;
HasPendingRestart = true;
if (changed)
{
EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
}
}
///
/// Restarts this instance.
///
public void Restart()
{
if (!CanSelfRestart)
{
throw new PlatformNotSupportedException("The server is unable to self-restart. Please restart manually.");
}
if (IsShuttingDown)
{
return;
}
IsShuttingDown = true;
Task.Run(async () =>
{
try
{
await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error sending server restart notification", ex);
}
Logger.Info("Calling RestartInternal");
RestartInternal();
});
}
protected abstract void RestartInternal();
///
/// Gets the composable part assemblies.
///
/// IEnumerable{Assembly}.
protected IEnumerable GetComposablePartAssemblies()
{
var list = GetPluginAssemblies()
.ToList();
// Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
// This will prevent the .dll file from getting locked, and allow us to replace it when needed
// Include composable parts in the Api assembly
list.Add(GetAssembly(typeof(ApiEntryPoint)));
// Include composable parts in the Dashboard assembly
list.Add(GetAssembly(typeof(DashboardService)));
// Include composable parts in the Model assembly
list.Add(GetAssembly(typeof(SystemInfo)));
// Include composable parts in the Common assembly
list.Add(GetAssembly(typeof(IApplicationHost)));
// Include composable parts in the Controller assembly
list.Add(GetAssembly(typeof(IServerApplicationHost)));
// Include composable parts in the Providers assembly
list.Add(GetAssembly(typeof(ProviderUtils)));
// Include composable parts in the Photos assembly
list.Add(GetAssembly(typeof(PhotoProvider)));
// Emby.Server implementations
list.Add(GetAssembly(typeof(InstallationManager)));
// MediaEncoding
list.Add(GetAssembly(typeof(MediaEncoding.Encoder.MediaEncoder)));
// Dlna
list.Add(GetAssembly(typeof(DlnaEntryPoint)));
// Local metadata
list.Add(GetAssembly(typeof(BoxSetXmlSaver)));
// Xbmc
list.Add(GetAssembly(typeof(ArtistNfoProvider)));
list.AddRange(GetAssembliesWithPartsInternal());
return list.ToList();
}
protected abstract List GetAssembliesWithPartsInternal();
///
/// Gets the plugin assemblies.
///
/// IEnumerable{Assembly}.
private IEnumerable GetPluginAssemblies()
{
try
{
return Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly)
.Where(EnablePlugin)
.Select(LoadAssembly)
.Where(a => a != null)
.ToList();
}
catch (DirectoryNotFoundException)
{
return new List();
}
}
private bool EnablePlugin(string path)
{
var filename = Path.GetFileName(path);
var exclude = new[]
{
"mbplus.dll",
"mbintros.dll",
"embytv.dll",
"Messenger.dll",
"MediaBrowser.Plugins.TvMazeProvider.dll",
"MBBookshelf.dll",
"MediaBrowser.Channels.Adult.YouJizz.dll",
"MediaBrowser.Channels.Vine-co.dll",
"MediaBrowser.Plugins.Vimeo.dll",
"MediaBrowser.Channels.Vevo.dll",
"MediaBrowser.Plugins.Twitch.dll",
"MediaBrowser.Channels.SvtPlay.dll",
"MediaBrowser.Plugins.SoundCloud.dll",
"MediaBrowser.Plugins.SnesBox.dll",
"MediaBrowser.Plugins.RottenTomatoes.dll",
"MediaBrowser.Plugins.Revision3.dll",
"MediaBrowser.Plugins.NesBox.dll",
"MBChapters.dll",
"MediaBrowser.Channels.LeagueOfLegends.dll",
"MediaBrowser.Plugins.ADEProvider.dll",
"MediaBrowser.Channels.BallStreams.dll",
"MediaBrowser.Channels.Adult.Beeg.dll",
"ChannelDownloader.dll",
"Hamstercat.Emby.EmbyBands.dll",
"EmbyTV.dll",
"MediaBrowser.Channels.HitboxTV.dll",
"MediaBrowser.Channels.HockeyStreams.dll",
"MediaBrowser.Plugins.ITV.dll",
"MediaBrowser.Plugins.Lastfm.dll"
};
return !exclude.Contains(filename ?? string.Empty, StringComparer.OrdinalIgnoreCase);
}
///
/// Gets the system status.
///
/// SystemInfo.
public async Task GetSystemInfo(CancellationToken cancellationToken)
{
var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
return new SystemInfo
{
HasPendingRestart = HasPendingRestart,
IsShuttingDown = IsShuttingDown,
Version = ApplicationVersion.ToString(),
WebSocketPortNumber = HttpPort,
FailedPluginAssemblies = FailedAssemblies.ToArray(),
InProgressInstallations = InstallationManager.CurrentInstallations.Select(i => i.Item1).ToArray(),
CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
Id = SystemId,
ProgramDataPath = ApplicationPaths.ProgramDataPath,
LogPath = ApplicationPaths.LogDirectoryPath,
ItemsByNamePath = ApplicationPaths.ItemsByNamePath,
InternalMetadataPath = ApplicationPaths.InternalMetadataPath,
CachePath = ApplicationPaths.CachePath,
MacAddress = GetMacAddress(),
HttpServerPortNumber = HttpPort,
SupportsHttps = SupportsHttps,
HttpsPortNumber = HttpsPort,
OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
OperatingSystemDisplayName = OperatingSystemDisplayName,
CanSelfRestart = CanSelfRestart,
CanSelfUpdate = CanSelfUpdate,
WanAddress = ConnectManager.WanApiAddress,
HasUpdateAvailable = HasUpdateAvailable,
SupportsAutoRunAtStartup = SupportsAutoRunAtStartup,
TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
ServerName = FriendlyName,
LocalAddress = localAddress,
SupportsLibraryMonitor = true,
EncoderLocationType = MediaEncoder.EncoderLocationType,
SystemArchitecture = EnvironmentInfo.SystemArchitecture,
SystemUpdateLevel = SystemUpdateLevel,
PackageName = StartupOptions.GetOption("-package")
};
}
public bool EnableHttps
{
get
{
return SupportsHttps && (ServerConfigurationManager.Configuration.EnableHttps || ServerConfigurationManager.Configuration.RequireHttps);
}
}
public bool SupportsHttps
{
get { return Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy; }
}
public async Task GetLocalApiUrl(CancellationToken cancellationToken)
{
try
{
// Return the first matched address, if found, or the first known local address
var address = (await GetLocalIpAddresses(cancellationToken).ConfigureAwait(false)).FirstOrDefault(i => !i.Equals(IpAddressInfo.Loopback) && !i.Equals(IpAddressInfo.IPv6Loopback));
if (address != null)
{
return GetLocalApiUrl(address);
}
return null;
}
catch (Exception ex)
{
Logger.ErrorException("Error getting local Ip address information", ex);
}
return null;
}
public string GetLocalApiUrl(IpAddressInfo ipAddress)
{
if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
{
return GetLocalApiUrl("[" + ipAddress.Address + "]");
}
return GetLocalApiUrl(ipAddress.Address);
}
public string GetLocalApiUrl(string host)
{
return string.Format("http://{0}:{1}",
host,
HttpPort.ToString(CultureInfo.InvariantCulture));
}
public async Task> GetLocalIpAddresses(CancellationToken cancellationToken)
{
var addresses = ServerConfigurationManager
.Configuration
.LocalNetworkAddresses
.Select(NormalizeConfiguredLocalAddress)
.Where(i => i != null)
.ToList();
if (addresses.Count == 0)
{
addresses.AddRange(NetworkManager.GetLocalIpAddresses());
var list = new List();
foreach (var address in addresses)
{
var valid = await IsIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false);
if (valid)
{
list.Add(address);
}
}
addresses = list;
}
return addresses;
}
private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
{
var index = address.Trim('/').IndexOf('/');
if (index != -1)
{
address = address.Substring(index + 1);
}
IpAddressInfo result;
if (NetworkManager.TryParseIpAddress(address.Trim('/'), out result))
{
return result;
}
return null;
}
private readonly ConcurrentDictionary _validAddressResults = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
private DateTime _lastAddressCacheClear;
private async Task IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken)
{
if (address.Equals(IpAddressInfo.Loopback) ||
address.Equals(IpAddressInfo.IPv6Loopback))
{
return true;
}
var apiUrl = GetLocalApiUrl(address);
apiUrl += "/system/ping";
if ((DateTime.UtcNow - _lastAddressCacheClear).TotalMinutes >= 15)
{
_lastAddressCacheClear = DateTime.UtcNow;
_validAddressResults.Clear();
}
bool cachedResult;
if (_validAddressResults.TryGetValue(apiUrl, out cachedResult))
{
return cachedResult;
}
try
{
using (var response = await HttpClient.SendAsync(new HttpRequestOptions
{
Url = apiUrl,
LogErrorResponseBody = false,
LogErrors = false,
LogRequest = false,
TimeoutMs = 30000,
BufferContent = false,
CancellationToken = cancellationToken
}, "POST").ConfigureAwait(false))
{
using (var reader = new StreamReader(response.Content))
{
var result = reader.ReadToEnd();
var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
_validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
//Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, valid);
return valid;
}
}
}
catch (OperationCanceledException)
{
throw;
}
catch
{
//Logger.Debug("Ping test result to {0}. Success: {1}", apiUrl, false);
_validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
return false;
}
}
public string FriendlyName
{
get
{
return string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.ServerName)
? Environment.MachineName
: ServerConfigurationManager.Configuration.ServerName;
}
}
public int HttpPort { get; private set; }
public int HttpsPort { get; private set; }
///
/// Gets the mac address.
///
/// System.String.
private string GetMacAddress()
{
try
{
return NetworkManager.GetMacAddress();
}
catch (Exception ex)
{
Logger.ErrorException("Error getting mac address", ex);
return null;
}
}
///
/// Shuts down.
///
public async Task Shutdown()
{
if (IsShuttingDown)
{
return;
}
IsShuttingDown = true;
try
{
await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error sending server shutdown notification", ex);
}
ShutdownInternal();
}
protected abstract void ShutdownInternal();
///
/// Registers the server with administrator access.
///
private void RegisterServerWithAdministratorAccess()
{
Logger.Info("Requesting administrative access to authorize http server");
try
{
AuthorizeServer();
}
catch (NotImplementedException)
{
}
catch (Exception ex)
{
Logger.ErrorException("Error authorizing server", ex);
}
}
protected virtual void AuthorizeServer()
{
throw new NotImplementedException();
}
public event EventHandler HasUpdateAvailableChanged;
private bool _hasUpdateAvailable;
public bool HasUpdateAvailable
{
get { return _hasUpdateAvailable; }
set
{
var fireEvent = value && !_hasUpdateAvailable;
_hasUpdateAvailable = value;
if (fireEvent)
{
EventHelper.FireEventIfNotNull(HasUpdateAvailableChanged, this, EventArgs.Empty, Logger);
}
}
}
///
/// Removes the plugin.
///
/// The plugin.
public void RemovePlugin(IPlugin plugin)
{
var list = Plugins.ToList();
list.Remove(plugin);
Plugins = list.ToArray();
}
///
/// Checks for update.
///
/// The cancellation token.
/// The progress.
/// Task{CheckForUpdateResult}.
public async Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress)
{
var updateLevel = SystemUpdateLevel;
var cacheLength = updateLevel == PackageVersionClass.Release ?
TimeSpan.FromHours(12) :
TimeSpan.FromMinutes(5);
try
{
var result = await new GithubUpdater(HttpClient, JsonSerializer).CheckForUpdateResult("MediaBrowser",
"Emby",
ApplicationVersion,
updateLevel,
ReleaseAssetFilename,
"MBServer",
UpdateTargetFileName,
cacheLength,
cancellationToken).ConfigureAwait(false);
HasUpdateAvailable = result.IsUpdateAvailable;
return result;
}
catch (HttpException ex)
{
// users are overreacting to this occasionally failing
if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.Forbidden)
{
HasUpdateAvailable = false;
return new CheckForUpdateResult
{
IsUpdateAvailable = false
};
}
throw;
}
}
protected virtual string UpdateTargetFileName
{
get { return "Mbserver.zip"; }
}
///
/// Updates the application.
///
/// The package that contains the update
/// The cancellation token.
/// The progress.
public async Task UpdateApplication(PackageVersionInfo package, CancellationToken cancellationToken, IProgress progress)
{
await InstallationManager.InstallPackage(package, false, progress, cancellationToken).ConfigureAwait(false);
HasUpdateAvailable = false;
OnApplicationUpdated(package);
}
///
/// Configures the automatic run at startup.
///
/// if set to true [autorun].
protected void ConfigureAutoRunAtStartup(bool autorun)
{
if (SupportsAutoRunAtStartup)
{
ConfigureAutoRunInternal(autorun);
}
}
protected virtual void ConfigureAutoRunInternal(bool autorun)
{
throw new NotImplementedException();
}
///
/// This returns localhost in the case of no external dns, and the hostname if the
/// dns is prefixed with a valid Uri prefix.
///
/// The external dns prefix to get the hostname of.
/// The hostname in
private static string GetHostnameFromExternalDns(string externalDns)
{
if (string.IsNullOrWhiteSpace(externalDns))
{
return "localhost";
}
try
{
return new Uri(externalDns).Host;
}
catch
{
return externalDns;
}
}
public virtual void LaunchUrl(string url)
{
if (EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.Windows &&
EnvironmentInfo.OperatingSystem != MediaBrowser.Model.System.OperatingSystem.OSX)
{
throw new NotSupportedException();
}
if (!Environment.UserInteractive)
{
throw new NotSupportedException();
}
var process = ProcessFactory.Create(new ProcessOptions
{
FileName = url,
//EnableRaisingEvents = true,
UseShellExecute = true,
ErrorDialog = false
});
process.Exited += ProcessExited;
try
{
process.Start();
}
catch (Exception ex)
{
Console.WriteLine("Error launching url: {0}", url);
Logger.ErrorException("Error launching url: {0}", ex, url);
throw;
}
}
private static void ProcessExited(object sender, EventArgs e)
{
((IProcess)sender).Dispose();
}
public virtual void EnableLoopback(string appName)
{
}
private void RegisterModules()
{
var moduleTypes = GetExportTypes();
foreach (var type in moduleTypes)
{
try
{
var instance = Activator.CreateInstance(type) as IDependencyModule;
if (instance != null)
instance.BindDependencies(this);
}
catch (Exception ex)
{
Logger.ErrorException("Error setting up dependency bindings for " + type.Name, ex);
}
}
}
///
/// Called when [application updated].
///
/// The package.
protected void OnApplicationUpdated(PackageVersionInfo package)
{
Logger.Info("Application has been updated to version {0}", package.versionStr);
EventHelper.FireEventIfNotNull(ApplicationUpdated, this, new GenericEventArgs
{
Argument = package
}, Logger);
NotifyPendingRestart();
}
private bool _disposed;
///
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///
public void Dispose()
{
if (!_disposed)
{
_disposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
}
///
/// Releases unmanaged and - optionally - managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected virtual void Dispose(bool dispose)
{
if (dispose)
{
var type = GetType();
LogManager.AddConsoleOutput();
Logger.Info("Disposing " + type.Name);
var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
DisposableParts.Clear();
foreach (var part in parts)
{
Logger.Info("Disposing " + part.GetType().Name);
try
{
part.Dispose();
}
catch (Exception ex)
{
Logger.ErrorException("Error disposing {0}", ex, part.GetType().Name);
}
}
}
}
void IDependencyContainer.RegisterSingleInstance(T obj, bool manageLifetime)
{
RegisterSingleInstance(obj, manageLifetime);
}
void IDependencyContainer.RegisterSingleInstance(Func func)
{
RegisterSingleInstance(func);
}
void IDependencyContainer.Register(Type typeInterface, Type typeImplementation)
{
Container.Register(typeInterface, typeImplementation);
}
}
internal class CertificateInfo
{
public string Path { get; set; }
public string Password { get; set; }
}
}