@ -1,11 +1,5 @@
using Emby.Common.Implementations ;
using Emby.Common.Implementations.Archiving ;
using Emby.Common.Implementations.IO ;
using Emby.Common.Implementations.Reflection ;
using Emby.Common.Implementations.ScheduledTasks ;
using Emby.Common.Implementations.Serialization ;
using Emby.Common.Implementations.TextEncoding ;
using Emby.Common.Implementations.Xml ;
using Emby.Dlna ;
using Emby.Dlna.ConnectionManager ;
using Emby.Dlna.ContentDirectory ;
@ -110,12 +104,28 @@ 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 Emby.Server.Implementations.Archiving ;
using Emby.Server.Implementations.Cryptography ;
using Emby.Server.Implementations.Diagnostics ;
using Emby.Server.Implementations.Net ;
using Emby.Server.Implementations.Reflection ;
using Emby.Server.Implementations.ScheduledTasks ;
using Emby.Server.Implementations.Serialization ;
using Emby.Server.Implementations.Threading ;
using Emby.Server.Implementations.Xml ;
using Emby.Server.MediaEncoding.Subtitles ;
using MediaBrowser.MediaEncoding.BdInfo ;
using MediaBrowser.Model.Cryptography ;
using MediaBrowser.Model.Events ;
using MediaBrowser.Model.Tasks ;
using MediaBrowser.Model.Threading ;
using StringExtensions = MediaBrowser . Controller . Extensions . StringExtensions ;
namespace Emby.Server.Implementations
@ -123,8 +133,124 @@ namespace Emby.Server.Implementations
/// <summary>
/// Class CompositionRoot
/// </summary>
public abstract class ApplicationHost : BaseApplicationHost< ServerApplicationPaths > , IServerApplicationHost, IDependencyContainer
public abstract class ApplicationHost : IServerApplicationHost, IDependencyContainer
{
/// <summary>
/// Gets a value indicating whether this instance can self restart.
/// </summary>
/// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
public abstract bool CanSelfRestart { get ; }
/// <summary>
/// Gets or sets a value indicating whether this instance can self update.
/// </summary>
/// <value><c>true</c> if this instance can self update; otherwise, <c>false</c>.</value>
public virtual bool CanSelfUpdate
{
get
{
return false ;
}
}
/// <summary>
/// Occurs when [has pending restart changed].
/// </summary>
public event EventHandler HasPendingRestartChanged ;
/// <summary>
/// Occurs when [application updated].
/// </summary>
public event EventHandler < GenericEventArgs < PackageVersionInfo > > ApplicationUpdated ;
/// <summary>
/// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
/// </summary>
/// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
public bool HasPendingRestart { get ; private set ; }
/// <summary>
/// Gets or sets the logger.
/// </summary>
/// <value>The logger.</value>
protected ILogger Logger { get ; set ; }
/// <summary>
/// Gets or sets the plugins.
/// </summary>
/// <value>The plugins.</value>
public IPlugin [ ] Plugins { get ; protected set ; }
/// <summary>
/// Gets or sets the log manager.
/// </summary>
/// <value>The log manager.</value>
public ILogManager LogManager { get ; protected set ; }
/// <summary>
/// Gets the application paths.
/// </summary>
/// <value>The application paths.</value>
protected ServerApplicationPaths ApplicationPaths { get ; set ; }
/// <summary>
/// Gets assemblies that failed to load
/// </summary>
/// <value>The failed assemblies.</value>
public List < string > FailedAssemblies { get ; protected set ; }
/// <summary>
/// Gets all concrete types.
/// </summary>
/// <value>All concrete types.</value>
public Type [ ] AllConcreteTypes { get ; protected set ; }
/// <summary>
/// The disposable parts
/// </summary>
protected readonly List < IDisposable > DisposableParts = new List < IDisposable > ( ) ;
/// <summary>
/// Gets a value indicating whether this instance is first run.
/// </summary>
/// <value><c>true</c> if this instance is first run; otherwise, <c>false</c>.</value>
public bool IsFirstRun { get ; private set ; }
/// <summary>
/// Gets the configuration manager.
/// </summary>
/// <value>The configuration manager.</value>
protected IConfigurationManager ConfigurationManager { get ; set ; }
public IFileSystem FileSystemManager { get ; set ; }
protected IEnvironmentInfo EnvironmentInfo { get ; set ; }
public PackageVersionClass SystemUpdateLevel
{
get
{
#if BETA
return PackageVersionClass . Beta ;
# endif
return PackageVersionClass . Release ;
}
}
public virtual string OperatingSystemDisplayName
{
get { return EnvironmentInfo . OperatingSystemName ; }
}
/// <summary>
/// The container
/// </summary>
protected readonly SimpleInjector . Container Container = new SimpleInjector . Container ( ) ;
protected ISystemEvents SystemEvents { get ; set ; }
protected IMemoryStreamFactory MemoryStreamFactory { get ; set ; }
/// <summary>
/// Gets the server configuration manager.
/// </summary>
@ -138,7 +264,7 @@ namespace Emby.Server.Implementations
/// Gets the configuration manager.
/// </summary>
/// <returns>IConfigurationManager.</returns>
protected override IConfigurationManager GetConfigurationManager ( )
protected IConfigurationManager GetConfigurationManager ( )
{
return new ServerConfigurationManager ( ApplicationPaths , LogManager , XmlSerializer , FileSystemManager ) ;
}
@ -244,6 +370,17 @@ namespace Emby.Server.Implementations
private readonly Action < string , string , string > _certificateGenerator ;
private readonly Func < string > _defaultUserNameFactory ;
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 ; }
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost" /> class.
@ -261,14 +398,28 @@ namespace Emby.Server.Implementations
INetworkManager networkManager ,
Action < string , string , string > certificateGenerator ,
Func < string > defaultUsernameFactory )
: base ( applicationPaths ,
logManager ,
fileSystem ,
environmentInfo ,
systemEvents ,
memoryStreamFactory ,
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 = memoryStreamFactory ;
FailedAssemblies = new List < string > ( ) ;
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 ;
_certificateGenerator = certificateGenerator ;
_releaseAssetFilename = releaseAssetFilename ;
@ -292,7 +443,7 @@ namespace Emby.Server.Implementations
/// Gets the current application version
/// </summary>
/// <value>The application version.</value>
public override Version ApplicationVersion
public Version ApplicationVersion
{
get
{
@ -308,11 +459,25 @@ namespace Emby.Server.Implementations
}
}
private DeviceId _deviceId ;
public string SystemId
{
get
{
if ( _deviceId = = null )
{
_deviceId = new DeviceId ( ApplicationPaths , LogManager . GetLogger ( "SystemId" ) , FileSystemManager ) ;
}
return _deviceId . Value ;
}
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public override string Name
public string Name
{
get
{
@ -341,6 +506,159 @@ namespace Emby.Server.Implementations
}
}
/// <summary>
/// Creates an instance of type and resolves all constructor dependancies
/// </summary>
/// <param name="type">The type.</param>
/// <returns>System.Object.</returns>
public object CreateInstance ( Type type )
{
try
{
return Container . GetInstance ( type ) ;
}
catch ( Exception ex )
{
Logger . ErrorException ( "Error creating {0}" , ex , type . FullName ) ;
throw ;
}
}
/// <summary>
/// Creates the instance safe.
/// </summary>
/// <param name="type">The type.</param>
/// <returns>System.Object.</returns>
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 ;
}
}
/// <summary>
/// Registers the specified obj.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj">The obj.</param>
/// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
protected void RegisterSingleInstance < T > ( T obj , bool manageLifetime = true )
where T : class
{
Container . RegisterSingleton ( obj ) ;
if ( manageLifetime )
{
var disposable = obj as IDisposable ;
if ( disposable ! = null )
{
DisposableParts . Add ( disposable ) ;
}
}
}
/// <summary>
/// Registers the single instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func">The func.</param>
protected void RegisterSingleInstance < T > ( Func < T > func )
where T : class
{
Container . RegisterSingleton ( func ) ;
}
/// <summary>
/// Resolves this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>``0.</returns>
public T Resolve < T > ( )
{
return ( T ) Container . GetRegistration ( typeof ( T ) , true ) . GetInstance ( ) ;
}
/// <summary>
/// Resolves this instance.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>``0.</returns>
public T TryResolve < T > ( )
{
var result = Container . GetRegistration ( typeof ( T ) , false ) ;
if ( result = = null )
{
return default ( T ) ;
}
return ( T ) result . GetInstance ( ) ;
}
/// <summary>
/// Loads the assembly.
/// </summary>
/// <param name="file">The file.</param>
/// <returns>Assembly.</returns>
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 ;
}
}
/// <summary>
/// Gets the export types.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns>IEnumerable{Type}.</returns>
public IEnumerable < Type > GetExportTypes < T > ( )
{
var currentType = typeof ( T ) ;
return AllConcreteTypes . Where ( currentType . IsAssignableFrom ) ;
}
/// <summary>
/// Gets the exports.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="manageLiftime">if set to <c>true</c> [manage liftime].</param>
/// <returns>IEnumerable{``0}.</returns>
public IEnumerable < T > GetExports < T > ( bool manageLiftime = true )
{
var parts = GetExportTypes < T > ( )
. Select ( CreateInstanceSafe )
. Where ( i = > i ! = null )
. Cast < T > ( )
. ToList ( ) ;
if ( manageLiftime )
{
lock ( DisposableParts )
{
DisposableParts . AddRange ( parts . OfType < IDisposable > ( ) ) ;
}
}
return parts ;
}
private void SetBaseExceptionMessage ( )
{
var builder = GetBaseExceptionMessage ( ApplicationPaths ) ;
@ -354,9 +672,13 @@ namespace Emby.Server.Implementations
/// <summary>
/// Runs the startup tasks.
/// </summary>
public override async Task RunStartupTasks ( )
public async Task RunStartupTasks ( )
{
await base . RunStartupTasks ( ) . ConfigureAwait ( false ) ;
Resolve < ITaskManager > ( ) . AddTasks ( GetExports < IScheduledTask > ( false ) ) ;
ConfigureAutorun ( ) ;
ConfigurationManager . ConfigurationUpdated + = OnConfigurationUpdated ;
await MediaEncoder . Init ( ) . ConfigureAwait ( false ) ;
@ -395,7 +717,22 @@ namespace Emby.Server.Implementations
LogManager . RemoveConsoleOutput ( ) ;
}
protected override IJsonSerializer CreateJsonSerializer ( )
/// <summary>
/// Configures the autorun.
/// </summary>
private void ConfigureAutorun ( )
{
try
{
ConfigureAutoRunAtStartup ( ConfigurationManager . CommonConfiguration . RunAtStartup ) ;
}
catch ( Exception ex )
{
Logger . ErrorException ( "Error configuring autorun" , ex ) ;
}
}
private IJsonSerializer CreateJsonSerializer ( )
{
try
{
@ -410,7 +747,7 @@ namespace Emby.Server.Implementations
return new JsonSerializer ( FileSystemManager , LogManager . GetLogger ( "JsonSerializer" ) ) ;
}
public override Task Init ( IProgress < double > progress )
public async Task Init ( IProgress < double > progress )
{
HttpPort = ServerConfigurationManager . Configuration . HttpServerPortNumber ;
HttpsPort = ServerConfigurationManager . Configuration . HttpsPortNumber ;
@ -422,7 +759,64 @@ namespace Emby.Server.Implementations
HttpsPort = ServerConfiguration . DefaultHttpsPort ;
}
return base . Init ( progress ) ;
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 < double > ( ) ;
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
Logger . LogMultiline ( "Application configuration:" , LogSeverity . Info , new StringBuilder ( JsonSerializer . SerializeToString ( ConfigurationManager . CommonConfiguration ) ) ) ;
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 ( ) ;
@ -431,9 +825,47 @@ namespace Emby.Server.Implementations
/// <summary>
/// Registers resources that classes will depend on
/// </summary>
protected override async Task RegisterResources ( IProgress < double > progress )
protected async Task RegisterResources ( IProgress < double > progress )
{
await base . RegisterResources ( progress ) . ConfigureAwait ( false ) ;
RegisterSingleInstance ( ConfigurationManager ) ;
RegisterSingleInstance < IApplicationHost > ( this ) ;
RegisterSingleInstance < IApplicationPaths > ( ApplicationPaths ) ;
RegisterSingleInstance ( JsonSerializer ) ;
RegisterSingleInstance ( MemoryStreamFactory ) ;
RegisterSingleInstance ( SystemEvents ) ;
RegisterSingleInstance ( LogManager ) ;
RegisterSingleInstance ( Logger ) ;
RegisterSingleInstance ( EnvironmentInfo ) ;
RegisterSingleInstance ( FileSystemManager ) ;
HttpClient = new HttpClientManager . HttpClientManager ( ApplicationPaths , LogManager . GetLogger ( "HttpClient" ) , FileSystemManager , MemoryStreamFactory , GetDefaultUserAgent ) ;
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 ) ;
@ -460,7 +892,7 @@ namespace Emby.Server.Implementations
StringExtensions . LocalizationManager = LocalizationManager ;
RegisterSingleInstance ( LocalizationManager ) ;
ITextEncoding textEncoding = new TextEncoding (FileSystemManager , LogManager . GetLogger ( "TextEncoding" ) , JsonSerializer ) ;
ITextEncoding textEncoding = new TextEncoding .TextEncoding (FileSystemManager , LogManager . GetLogger ( "TextEncoding" ) , JsonSerializer ) ;
RegisterSingleInstance ( textEncoding ) ;
Utilities . EncodingHelper = textEncoding ;
RegisterSingleInstance < IBlurayExaminer > ( ( ) = > new BdInfoExaminer ( FileSystemManager , textEncoding ) ) ;
@ -627,6 +1059,106 @@ namespace Emby.Server.Implementations
await ( ( UserManager ) UserManager ) . Initialize ( ) . ConfigureAwait ( false ) ;
}
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 ) ) ;
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 ) ;
}
}
/// <summary>
/// Installs the iso mounters.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
private async Task InstallIsoMounters ( CancellationToken cancellationToken )
{
var list = new List < IIsoMounter > ( ) ;
foreach ( var isoMounter in GetExports < IIsoMounter > ( ) )
{
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 ) ;
}
private string GetDefaultUserAgent ( )
{
var name = FormatAttribute ( Name ) ;
return name + "/" + ApplicationVersion ;
}
private string FormatAttribute ( string str )
{
var arr = str . ToCharArray ( ) ;
arr = Array . FindAll < char > ( 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
@ -889,7 +1421,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Finds the parts.
/// </summary>
protected override void FindParts ( )
protected void FindParts ( )
{
if ( ! ServerConfigurationManager . Configuration . IsPortAuthorized )
{
@ -900,7 +1432,8 @@ namespace Emby.Server.Implementations
RegisterModules ( ) ;
base . FindParts ( ) ;
ConfigurationManager . AddParts ( GetExports < IConfigurationFactory > ( ) ) ;
Plugins = GetExports < IPlugin > ( ) . Select ( LoadPlugin ) . Where ( i = > i ! = null ) . ToArray ( ) ;
HttpServer . Init ( GetExports < IService > ( false ) ) ;
@ -937,6 +1470,104 @@ namespace Emby.Server.Implementations
SyncManager . AddParts ( GetExports < ISyncProvider > ( ) ) ;
}
private IPlugin LoadPlugin ( IPlugin plugin )
{
try
{
var assemblyPlugin = plugin as IPluginAssembly ;
if ( assemblyPlugin ! = null )
{
var assembly = plugin . GetType ( ) . Assembly ;
var assemblyName = assembly . GetName ( ) ;
var attribute = ( GuidAttribute ) assembly . GetCustomAttributes ( typeof ( GuidAttribute ) , true ) [ 0 ] ;
var assemblyId = new Guid ( attribute . Value ) ;
var assemblyFileName = assemblyName . Name + ".dll" ;
var assemblyFilePath = Path . Combine ( ApplicationPaths . PluginsPath , assemblyFileName ) ;
assemblyPlugin . SetAttributes ( assemblyFilePath , assemblyFileName , assemblyName . Version , assemblyId ) ;
}
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 ;
}
/// <summary>
/// Discovers the types.
/// </summary>
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 ( ) ;
}
/// <summary>
/// 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
/// </summary>
/// <param name="assembly">The assembly.</param>
/// <returns>IEnumerable{Type}.</returns>
/// <exception cref="System.ArgumentNullException">assembly</exception>
protected List < Type > GetTypes ( Assembly assembly )
{
if ( assembly = = null )
{
return new List < Type > ( ) ;
}
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 < Type > ( ) ;
}
}
private CertificateInfo CertificateInfo { get ; set ; }
private ICertificate Certificate { get ; set ; }
@ -1043,9 +1674,9 @@ namespace Emby.Server.Implementations
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
protected override void OnConfigurationUpdated ( object sender , EventArgs e )
protected void OnConfigurationUpdated ( object sender , EventArgs e )
{
base . OnConfigurationUpdated ( sender , e ) ;
ConfigureAutorun ( ) ;
var requiresRestart = false ;
@ -1088,10 +1719,27 @@ namespace Emby.Server.Implementations
}
}
/// <summary>
/// Notifies that the kernel that a change has been made that requires a restart
/// </summary>
public void NotifyPendingRestart ( )
{
Logger . Info ( "App needs to be restarted." ) ;
var changed = ! HasPendingRestart ;
HasPendingRestart = true ;
if ( changed )
{
EventHelper . QueueEventIfNotNull ( HasPendingRestartChanged , this , EventArgs . Empty , Logger ) ;
}
}
/// <summary>
/// Restarts this instance.
/// </summary>
public override async Task Restart ( )
public async Task Restart ( )
{
if ( ! CanSelfRestart )
{
@ -1118,7 +1766,7 @@ namespace Emby.Server.Implementations
/// Gets the composable part assemblies.
/// </summary>
/// <returns>IEnumerable{Assembly}.</returns>
protected override IEnumerable < Assembly > GetComposablePartAssemblies ( )
protected IEnumerable < Assembly > GetComposablePartAssemblies ( )
{
var list = GetPluginAssemblies ( )
. ToList ( ) ;
@ -1442,7 +2090,7 @@ namespace Emby.Server.Implementations
/// <summary>
/// Shuts down.
/// </summary>
public override async Task Shutdown ( )
public async Task Shutdown ( )
{
try
{
@ -1503,13 +2151,24 @@ namespace Emby.Server.Implementations
}
}
/// <summary>
/// Removes the plugin.
/// </summary>
/// <param name="plugin">The plugin.</param>
public void RemovePlugin ( IPlugin plugin )
{
var list = Plugins . ToList ( ) ;
list . Remove ( plugin ) ;
Plugins = list . ToArray ( ) ;
}
/// <summary>
/// Checks for update.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
/// <returns>Task{CheckForUpdateResult}.</returns>
public override async Task < CheckForUpdateResult > CheckForApplicationUpdate ( CancellationToken cancellationToken , IProgress < double > progress )
public async Task < CheckForUpdateResult > CheckForApplicationUpdate ( CancellationToken cancellationToken , IProgress < double > progress )
{
var cacheLength = TimeSpan . FromHours ( 1 ) ;
var updateLevel = SystemUpdateLevel ;
@ -1533,7 +2192,7 @@ namespace Emby.Server.Implementations
/// <param name="package">The package that contains the update</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
public override async Task UpdateApplication ( PackageVersionInfo package , CancellationToken cancellationToken , IProgress < double > progress )
public async Task UpdateApplication ( PackageVersionInfo package , CancellationToken cancellationToken , IProgress < double > progress )
{
await InstallationManager . InstallPackage ( package , false , progress , cancellationToken ) . ConfigureAwait ( false ) ;
@ -1546,7 +2205,7 @@ namespace Emby.Server.Implementations
/// Configures the automatic run at startup.
/// </summary>
/// <param name="autorun">if set to <c>true</c> [autorun].</param>
protected override void ConfigureAutoRunAtStartup ( bool autorun )
protected void ConfigureAutoRunAtStartup ( bool autorun )
{
if ( SupportsAutoRunAtStartup )
{
@ -1641,6 +2300,62 @@ namespace Emby.Server.Implementations
}
}
/// <summary>
/// Called when [application updated].
/// </summary>
/// <param name="package">The package.</param>
protected void OnApplicationUpdated ( PackageVersionInfo package )
{
Logger . Info ( "Application has been updated to version {0}" , package . versionStr ) ;
EventHelper . FireEventIfNotNull ( ApplicationUpdated , this , new GenericEventArgs < PackageVersionInfo >
{
Argument = package
} , Logger ) ;
NotifyPendingRestart ( ) ;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose ( )
{
Dispose ( true ) ;
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose ( bool dispose )
{
if ( dispose )
{
var type = GetType ( ) ;
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 > ( T obj , bool manageLifetime )
{
RegisterSingleInstance ( obj , manageLifetime ) ;