ApplicationHost.cs 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Reflection;
  10. using System.Runtime.InteropServices;
  11. using System.Security.Cryptography.X509Certificates;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using Emby.Dlna;
  16. using Emby.Dlna.Main;
  17. using Emby.Dlna.Ssdp;
  18. using Emby.Drawing;
  19. using Emby.Notifications;
  20. using Emby.Photos;
  21. using Emby.Server.Implementations.Activity;
  22. using Emby.Server.Implementations.Archiving;
  23. using Emby.Server.Implementations.Channels;
  24. using Emby.Server.Implementations.Collections;
  25. using Emby.Server.Implementations.Configuration;
  26. using Emby.Server.Implementations.Cryptography;
  27. using Emby.Server.Implementations.Data;
  28. using Emby.Server.Implementations.Devices;
  29. using Emby.Server.Implementations.Diagnostics;
  30. using Emby.Server.Implementations.Dto;
  31. using Emby.Server.Implementations.HttpServer;
  32. using Emby.Server.Implementations.HttpServer.Security;
  33. using Emby.Server.Implementations.IO;
  34. using Emby.Server.Implementations.Library;
  35. using Emby.Server.Implementations.LiveTv;
  36. using Emby.Server.Implementations.Localization;
  37. using Emby.Server.Implementations.Middleware;
  38. using Emby.Server.Implementations.Net;
  39. using Emby.Server.Implementations.Playlists;
  40. using Emby.Server.Implementations.Reflection;
  41. using Emby.Server.Implementations.ScheduledTasks;
  42. using Emby.Server.Implementations.Security;
  43. using Emby.Server.Implementations.Serialization;
  44. using Emby.Server.Implementations.Session;
  45. using Emby.Server.Implementations.SocketSharp;
  46. using Emby.Server.Implementations.TV;
  47. using Emby.Server.Implementations.Updates;
  48. using Emby.Server.Implementations.Xml;
  49. using MediaBrowser.Api;
  50. using MediaBrowser.Common;
  51. using MediaBrowser.Common.Configuration;
  52. using MediaBrowser.Common.Events;
  53. using MediaBrowser.Common.Extensions;
  54. using MediaBrowser.Common.Net;
  55. using MediaBrowser.Common.Plugins;
  56. using MediaBrowser.Common.Updates;
  57. using MediaBrowser.Controller;
  58. using MediaBrowser.Controller.Authentication;
  59. using MediaBrowser.Controller.Channels;
  60. using MediaBrowser.Controller.Chapters;
  61. using MediaBrowser.Controller.Collections;
  62. using MediaBrowser.Controller.Configuration;
  63. using MediaBrowser.Controller.Devices;
  64. using MediaBrowser.Controller.Dlna;
  65. using MediaBrowser.Controller.Drawing;
  66. using MediaBrowser.Controller.Dto;
  67. using MediaBrowser.Controller.Entities;
  68. using MediaBrowser.Controller.Library;
  69. using MediaBrowser.Controller.LiveTv;
  70. using MediaBrowser.Controller.MediaEncoding;
  71. using MediaBrowser.Controller.Net;
  72. using MediaBrowser.Controller.Notifications;
  73. using MediaBrowser.Controller.Persistence;
  74. using MediaBrowser.Controller.Playlists;
  75. using MediaBrowser.Controller.Plugins;
  76. using MediaBrowser.Controller.Providers;
  77. using MediaBrowser.Controller.Resolvers;
  78. using MediaBrowser.Controller.Security;
  79. using MediaBrowser.Controller.Session;
  80. using MediaBrowser.Controller.Sorting;
  81. using MediaBrowser.Controller.Subtitles;
  82. using MediaBrowser.Controller.TV;
  83. using MediaBrowser.LocalMetadata.Savers;
  84. using MediaBrowser.MediaEncoding.BdInfo;
  85. using MediaBrowser.Model.Activity;
  86. using MediaBrowser.Model.Configuration;
  87. using MediaBrowser.Model.Cryptography;
  88. using MediaBrowser.Model.Diagnostics;
  89. using MediaBrowser.Model.Dlna;
  90. using MediaBrowser.Model.Events;
  91. using MediaBrowser.Model.Extensions;
  92. using MediaBrowser.Model.Globalization;
  93. using MediaBrowser.Model.IO;
  94. using MediaBrowser.Model.MediaInfo;
  95. using MediaBrowser.Model.Net;
  96. using MediaBrowser.Model.Reflection;
  97. using MediaBrowser.Model.Serialization;
  98. using MediaBrowser.Model.Services;
  99. using MediaBrowser.Model.System;
  100. using MediaBrowser.Model.Tasks;
  101. using MediaBrowser.Model.Updates;
  102. using MediaBrowser.Model.Xml;
  103. using MediaBrowser.Providers.Chapters;
  104. using MediaBrowser.Providers.Manager;
  105. using MediaBrowser.Providers.Subtitles;
  106. using MediaBrowser.Providers.TV.TheTVDB;
  107. using MediaBrowser.WebDashboard.Api;
  108. using MediaBrowser.XbmcMetadata.Providers;
  109. using Microsoft.AspNetCore.Builder;
  110. using Microsoft.AspNetCore.Hosting;
  111. using Microsoft.AspNetCore.Http;
  112. using Microsoft.AspNetCore.Http.Extensions;
  113. using Microsoft.Extensions.Configuration;
  114. using Microsoft.Extensions.Logging;
  115. using Microsoft.Extensions.DependencyInjection;
  116. using Microsoft.Extensions.DependencyInjection.Extensions;
  117. using ServiceStack;
  118. namespace Emby.Server.Implementations
  119. {
  120. /// <summary>
  121. /// Class CompositionRoot
  122. /// </summary>
  123. public abstract class ApplicationHost : IServerApplicationHost, IDisposable
  124. {
  125. /// <summary>
  126. /// Gets a value indicating whether this instance can self restart.
  127. /// </summary>
  128. /// <value><c>true</c> if this instance can self restart; otherwise, <c>false</c>.</value>
  129. public abstract bool CanSelfRestart { get; }
  130. public virtual bool CanLaunchWebBrowser
  131. {
  132. get
  133. {
  134. if (!Environment.UserInteractive)
  135. {
  136. return false;
  137. }
  138. if (StartupOptions.IsService)
  139. {
  140. return false;
  141. }
  142. if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.Windows)
  143. {
  144. return true;
  145. }
  146. if (EnvironmentInfo.OperatingSystem == MediaBrowser.Model.System.OperatingSystem.OSX)
  147. {
  148. return true;
  149. }
  150. return false;
  151. }
  152. }
  153. /// <summary>
  154. /// Occurs when [has pending restart changed].
  155. /// </summary>
  156. public event EventHandler HasPendingRestartChanged;
  157. /// <summary>
  158. /// Occurs when [application updated].
  159. /// </summary>
  160. public event EventHandler<GenericEventArgs<PackageVersionInfo>> ApplicationUpdated;
  161. /// <summary>
  162. /// Gets or sets a value indicating whether this instance has changes that require the entire application to restart.
  163. /// </summary>
  164. /// <value><c>true</c> if this instance has pending application restart; otherwise, <c>false</c>.</value>
  165. public bool HasPendingRestart { get; private set; }
  166. public bool IsShuttingDown { get; private set; }
  167. /// <summary>
  168. /// Gets or sets the logger.
  169. /// </summary>
  170. /// <value>The logger.</value>
  171. protected ILogger Logger { get; set; }
  172. /// <summary>
  173. /// Gets or sets the plugins.
  174. /// </summary>
  175. /// <value>The plugins.</value>
  176. public IPlugin[] Plugins { get; protected set; }
  177. /// <summary>
  178. /// Gets or sets the logger factory.
  179. /// </summary>
  180. /// <value>The logger factory.</value>
  181. public ILoggerFactory LoggerFactory { get; protected set; }
  182. /// <summary>
  183. /// Gets the application paths.
  184. /// </summary>
  185. /// <value>The application paths.</value>
  186. protected ServerApplicationPaths ApplicationPaths { get; set; }
  187. /// <summary>
  188. /// Gets all concrete types.
  189. /// </summary>
  190. /// <value>All concrete types.</value>
  191. public Type[] AllConcreteTypes { get; protected set; }
  192. /// <summary>
  193. /// The disposable parts
  194. /// </summary>
  195. protected readonly List<IDisposable> DisposableParts = new List<IDisposable>();
  196. /// <summary>
  197. /// Gets the configuration manager.
  198. /// </summary>
  199. /// <value>The configuration manager.</value>
  200. protected IConfigurationManager ConfigurationManager { get; set; }
  201. public IFileSystem FileSystemManager { get; set; }
  202. protected IEnvironmentInfo EnvironmentInfo { get; set; }
  203. public PackageVersionClass SystemUpdateLevel
  204. {
  205. get
  206. {
  207. #if BETA
  208. return PackageVersionClass.Beta;
  209. #endif
  210. return PackageVersionClass.Release;
  211. }
  212. }
  213. protected IServiceProvider _serviceProvider;
  214. /// <summary>
  215. /// Gets the server configuration manager.
  216. /// </summary>
  217. /// <value>The server configuration manager.</value>
  218. public IServerConfigurationManager ServerConfigurationManager => (IServerConfigurationManager)ConfigurationManager;
  219. /// <summary>
  220. /// Gets the configuration manager.
  221. /// </summary>
  222. /// <returns>IConfigurationManager.</returns>
  223. protected IConfigurationManager GetConfigurationManager()
  224. {
  225. return new ServerConfigurationManager(ApplicationPaths, LoggerFactory, XmlSerializer, FileSystemManager);
  226. }
  227. protected virtual IResourceFileManager CreateResourceFileManager()
  228. {
  229. return new ResourceFileManager(HttpResultFactory, LoggerFactory, FileSystemManager);
  230. }
  231. /// <summary>
  232. /// Gets or sets the user manager.
  233. /// </summary>
  234. /// <value>The user manager.</value>
  235. public IUserManager UserManager { get; set; }
  236. /// <summary>
  237. /// Gets or sets the library manager.
  238. /// </summary>
  239. /// <value>The library manager.</value>
  240. internal ILibraryManager LibraryManager { get; set; }
  241. /// <summary>
  242. /// Gets or sets the directory watchers.
  243. /// </summary>
  244. /// <value>The directory watchers.</value>
  245. private ILibraryMonitor LibraryMonitor { get; set; }
  246. /// <summary>
  247. /// Gets or sets the provider manager.
  248. /// </summary>
  249. /// <value>The provider manager.</value>
  250. private IProviderManager ProviderManager { get; set; }
  251. /// <summary>
  252. /// Gets or sets the HTTP server.
  253. /// </summary>
  254. /// <value>The HTTP server.</value>
  255. private IHttpServer HttpServer { get; set; }
  256. private IDtoService DtoService { get; set; }
  257. public IImageProcessor ImageProcessor { get; set; }
  258. /// <summary>
  259. /// Gets or sets the media encoder.
  260. /// </summary>
  261. /// <value>The media encoder.</value>
  262. private IMediaEncoder MediaEncoder { get; set; }
  263. private ISubtitleEncoder SubtitleEncoder { get; set; }
  264. private ISessionManager SessionManager { get; set; }
  265. private ILiveTvManager LiveTvManager { get; set; }
  266. public LocalizationManager LocalizationManager { get; set; }
  267. private IEncodingManager EncodingManager { get; set; }
  268. private IChannelManager ChannelManager { get; set; }
  269. /// <summary>
  270. /// Gets or sets the user data repository.
  271. /// </summary>
  272. /// <value>The user data repository.</value>
  273. private IUserDataManager UserDataManager { get; set; }
  274. private IUserRepository UserRepository { get; set; }
  275. internal SqliteItemRepository ItemRepository { get; set; }
  276. private INotificationManager NotificationManager { get; set; }
  277. private ISubtitleManager SubtitleManager { get; set; }
  278. private IChapterManager ChapterManager { get; set; }
  279. private IDeviceManager DeviceManager { get; set; }
  280. internal IUserViewManager UserViewManager { get; set; }
  281. private IAuthenticationRepository AuthenticationRepository { get; set; }
  282. private ITVSeriesManager TVSeriesManager { get; set; }
  283. private ICollectionManager CollectionManager { get; set; }
  284. private IMediaSourceManager MediaSourceManager { get; set; }
  285. private IPlaylistManager PlaylistManager { get; set; }
  286. private readonly IConfiguration _configuration;
  287. /// <summary>
  288. /// Gets or sets the installation manager.
  289. /// </summary>
  290. /// <value>The installation manager.</value>
  291. protected IInstallationManager InstallationManager { get; private set; }
  292. /// <summary>
  293. /// Gets or sets the zip client.
  294. /// </summary>
  295. /// <value>The zip client.</value>
  296. protected IZipClient ZipClient { get; private set; }
  297. protected IHttpResultFactory HttpResultFactory { get; private set; }
  298. protected IAuthService AuthService { get; private set; }
  299. public IStartupOptions StartupOptions { get; private set; }
  300. internal IImageEncoder ImageEncoder { get; private set; }
  301. protected IProcessFactory ProcessFactory { get; private set; }
  302. protected ICryptoProvider CryptographyProvider = new CryptographyProvider();
  303. protected readonly IXmlSerializer XmlSerializer;
  304. protected ISocketFactory SocketFactory { get; private set; }
  305. protected ITaskManager TaskManager { get; private set; }
  306. public IHttpClient HttpClient { get; private set; }
  307. protected INetworkManager NetworkManager { get; set; }
  308. public IJsonSerializer JsonSerializer { get; private set; }
  309. protected IIsoManager IsoManager { get; private set; }
  310. /// <summary>
  311. /// Initializes a new instance of the <see cref="ApplicationHost" /> class.
  312. /// </summary>
  313. public ApplicationHost(ServerApplicationPaths applicationPaths,
  314. ILoggerFactory loggerFactory,
  315. IStartupOptions options,
  316. IFileSystem fileSystem,
  317. IEnvironmentInfo environmentInfo,
  318. IImageEncoder imageEncoder,
  319. INetworkManager networkManager,
  320. IConfiguration configuration)
  321. {
  322. _configuration = configuration;
  323. // hack alert, until common can target .net core
  324. BaseExtensions.CryptographyProvider = CryptographyProvider;
  325. XmlSerializer = new MyXmlSerializer(fileSystem, loggerFactory);
  326. NetworkManager = networkManager;
  327. networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
  328. EnvironmentInfo = environmentInfo;
  329. ApplicationPaths = applicationPaths;
  330. LoggerFactory = loggerFactory;
  331. FileSystemManager = fileSystem;
  332. ConfigurationManager = GetConfigurationManager();
  333. Logger = LoggerFactory.CreateLogger("App");
  334. StartupOptions = options;
  335. ImageEncoder = imageEncoder;
  336. fileSystem.AddShortcutHandler(new MbLinkShortcutHandler(fileSystem));
  337. NetworkManager.NetworkChanged += NetworkManager_NetworkChanged;
  338. }
  339. public string ExpandVirtualPath(string path)
  340. {
  341. var appPaths = ApplicationPaths;
  342. return path.Replace(appPaths.VirtualDataPath, appPaths.DataPath, StringComparison.OrdinalIgnoreCase)
  343. .Replace(appPaths.VirtualInternalMetadataPath, appPaths.InternalMetadataPath, StringComparison.OrdinalIgnoreCase);
  344. }
  345. public string ReverseVirtualPath(string path)
  346. {
  347. var appPaths = ApplicationPaths;
  348. return path.Replace(appPaths.DataPath, appPaths.VirtualDataPath, StringComparison.OrdinalIgnoreCase)
  349. .Replace(appPaths.InternalMetadataPath, appPaths.VirtualInternalMetadataPath, StringComparison.OrdinalIgnoreCase);
  350. }
  351. private string[] GetConfiguredLocalSubnets()
  352. {
  353. return ServerConfigurationManager.Configuration.LocalNetworkSubnets;
  354. }
  355. private void NetworkManager_NetworkChanged(object sender, EventArgs e)
  356. {
  357. _validAddressResults.Clear();
  358. }
  359. public string ApplicationVersion => typeof(ApplicationHost).Assembly.GetName().Version.ToString(3);
  360. /// <summary>
  361. /// Gets the current application user agent
  362. /// </summary>
  363. /// <value>The application user agent.</value>
  364. public string ApplicationUserAgent => Name.Replace(' ','-') + "/" + ApplicationVersion;
  365. private string _productName;
  366. /// <summary>
  367. /// Gets the current application name
  368. /// </summary>
  369. /// <value>The application name.</value>
  370. public string ApplicationProductName => _productName ?? (_productName = FileVersionInfo.GetVersionInfo(Assembly.GetEntryAssembly().Location).ProductName);
  371. private DeviceId _deviceId;
  372. public string SystemId
  373. {
  374. get
  375. {
  376. if (_deviceId == null)
  377. {
  378. _deviceId = new DeviceId(ApplicationPaths, LoggerFactory);
  379. }
  380. return _deviceId.Value;
  381. }
  382. }
  383. /// <summary>
  384. /// Gets the name.
  385. /// </summary>
  386. /// <value>The name.</value>
  387. public string Name => ApplicationProductName;
  388. /// <summary>
  389. /// Creates an instance of type and resolves all constructor dependencies
  390. /// </summary>
  391. /// <param name="type">The type.</param>
  392. /// <returns>System.Object.</returns>
  393. public object CreateInstance(Type type)
  394. => ActivatorUtilities.CreateInstance(_serviceProvider, type);
  395. /// <summary>
  396. /// Creates an instance of type and resolves all constructor dependencies
  397. /// </summary>
  398. /// <param name="type">The type.</param>
  399. /// <returns>System.Object.</returns>
  400. public T CreateInstance<T>()
  401. => ActivatorUtilities.CreateInstance<T>(_serviceProvider);
  402. /// <summary>
  403. /// Creates the instance safe.
  404. /// </summary>
  405. /// <param name="typeInfo">The type information.</param>
  406. /// <returns>System.Object.</returns>
  407. protected object CreateInstanceSafe(Type type)
  408. {
  409. try
  410. {
  411. Logger.LogDebug("Creating instance of {Type}", type);
  412. return ActivatorUtilities.CreateInstance(_serviceProvider, type);
  413. }
  414. catch (Exception ex)
  415. {
  416. Logger.LogError(ex, "Error creating {Type}", type);
  417. return null;
  418. }
  419. }
  420. /// <summary>
  421. /// Resolves this instance.
  422. /// </summary>
  423. /// <typeparam name="T"></typeparam>
  424. /// <returns>``0.</returns>
  425. public T Resolve<T>() => _serviceProvider.GetService<T>();
  426. /// <summary>
  427. /// Gets the export types.
  428. /// </summary>
  429. /// <typeparam name="T"></typeparam>
  430. /// <returns>IEnumerable{Type}.</returns>
  431. public IEnumerable<Type> GetExportTypes<T>()
  432. {
  433. var currentType = typeof(T);
  434. return AllConcreteTypes.Where(i => currentType.IsAssignableFrom(i));
  435. }
  436. /// <summary>
  437. /// Gets the exports.
  438. /// </summary>
  439. /// <typeparam name="T"></typeparam>
  440. /// <param name="manageLifetime">if set to <c>true</c> [manage lifetime].</param>
  441. /// <returns>IEnumerable{``0}.</returns>
  442. public IEnumerable<T> GetExports<T>(bool manageLifetime = true)
  443. {
  444. var parts = GetExportTypes<T>()
  445. .Select(x => CreateInstanceSafe(x))
  446. .Where(i => i != null)
  447. .Cast<T>()
  448. .ToList(); // Convert to list so this isn't executed for each iteration
  449. if (manageLifetime)
  450. {
  451. lock (DisposableParts)
  452. {
  453. DisposableParts.AddRange(parts.OfType<IDisposable>());
  454. }
  455. }
  456. return parts;
  457. }
  458. /// <summary>
  459. /// Runs the startup tasks.
  460. /// </summary>
  461. public async Task RunStartupTasks()
  462. {
  463. Logger.LogInformation("Running startup tasks");
  464. Resolve<ITaskManager>().AddTasks(GetExports<IScheduledTask>(false));
  465. ConfigurationManager.ConfigurationUpdated += OnConfigurationUpdated;
  466. MediaEncoder.SetFFmpegPath();
  467. //if (string.IsNullOrWhiteSpace(MediaEncoder.EncoderPath))
  468. //{
  469. // if (ServerConfigurationManager.Configuration.IsStartupWizardCompleted)
  470. // {
  471. // ServerConfigurationManager.Configuration.IsStartupWizardCompleted = false;
  472. // ServerConfigurationManager.SaveConfiguration();
  473. // }
  474. //}
  475. Logger.LogInformation("ServerId: {0}", SystemId);
  476. var entryPoints = GetExports<IServerEntryPoint>();
  477. var stopWatch = new Stopwatch();
  478. stopWatch.Start();
  479. await Task.WhenAll(StartEntryPoints(entryPoints, true));
  480. Logger.LogInformation("Executed all pre-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
  481. Logger.LogInformation("Core startup complete");
  482. HttpServer.GlobalResponse = null;
  483. stopWatch.Restart();
  484. await Task.WhenAll(StartEntryPoints(entryPoints, false));
  485. Logger.LogInformation("Executed all post-startup entry points in {Elapsed:g}", stopWatch.Elapsed);
  486. stopWatch.Stop();
  487. }
  488. private IEnumerable<Task> StartEntryPoints(IEnumerable<IServerEntryPoint> entryPoints, bool isBeforeStartup)
  489. {
  490. foreach (var entryPoint in entryPoints)
  491. {
  492. if (isBeforeStartup != (entryPoint is IRunBeforeStartup))
  493. {
  494. continue;
  495. }
  496. Logger.LogDebug("Starting entry point {Type}", entryPoint.GetType());
  497. yield return entryPoint.RunAsync();
  498. }
  499. }
  500. public async Task Init(IServiceCollection serviceCollection)
  501. {
  502. HttpPort = ServerConfigurationManager.Configuration.HttpServerPortNumber;
  503. HttpsPort = ServerConfigurationManager.Configuration.HttpsPortNumber;
  504. // Safeguard against invalid configuration
  505. if (HttpPort == HttpsPort)
  506. {
  507. HttpPort = ServerConfiguration.DefaultHttpPort;
  508. HttpsPort = ServerConfiguration.DefaultHttpsPort;
  509. }
  510. JsonSerializer = new JsonSerializer(FileSystemManager);
  511. if (Plugins != null)
  512. {
  513. var pluginBuilder = new StringBuilder();
  514. foreach (var plugin in Plugins)
  515. {
  516. pluginBuilder.AppendLine(string.Format("{0} {1}", plugin.Name, plugin.Version));
  517. }
  518. Logger.LogInformation("Plugins: {plugins}", pluginBuilder.ToString());
  519. }
  520. DiscoverTypes();
  521. SetHttpLimit();
  522. await RegisterResources(serviceCollection);
  523. FindParts();
  524. string contentRoot = ServerConfigurationManager.Configuration.DashboardSourcePath;
  525. if (string.IsNullOrEmpty(contentRoot))
  526. {
  527. contentRoot = Path.Combine(ServerConfigurationManager.ApplicationPaths.ApplicationResourcesPath, "jellyfin-web", "src");
  528. }
  529. var host = new WebHostBuilder()
  530. .UseKestrel(options =>
  531. {
  532. options.ListenAnyIP(HttpPort);
  533. if (EnableHttps && Certificate != null)
  534. {
  535. options.ListenAnyIP(HttpsPort, listenOptions => { listenOptions.UseHttps(Certificate); });
  536. }
  537. })
  538. .UseContentRoot(contentRoot)
  539. .ConfigureServices(services =>
  540. {
  541. services.AddResponseCompression();
  542. services.AddHttpContextAccessor();
  543. })
  544. .Configure(app =>
  545. {
  546. app.UseWebSockets();
  547. app.UseResponseCompression();
  548. // TODO app.UseMiddleware<WebSocketMiddleware>();
  549. app.Use(ExecuteWebsocketHandlerAsync);
  550. app.Use(ExecuteHttpHandlerAsync);
  551. })
  552. .Build();
  553. await host.StartAsync();
  554. }
  555. private async Task ExecuteWebsocketHandlerAsync(HttpContext context, Func<Task> next)
  556. {
  557. if (!context.WebSockets.IsWebSocketRequest)
  558. {
  559. await next().ConfigureAwait(false);
  560. return;
  561. }
  562. await HttpServer.ProcessWebSocketRequest(context).ConfigureAwait(false);
  563. }
  564. private async Task ExecuteHttpHandlerAsync(HttpContext context, Func<Task> next)
  565. {
  566. if (context.WebSockets.IsWebSocketRequest)
  567. {
  568. await next().ConfigureAwait(false);
  569. return;
  570. }
  571. var request = context.Request;
  572. var response = context.Response;
  573. var localPath = context.Request.Path.ToString();
  574. var req = new WebSocketSharpRequest(request, response, request.Path, Logger);
  575. await HttpServer.RequestHandler(req, request.GetDisplayUrl(), request.Host.ToString(), localPath, CancellationToken.None).ConfigureAwait(false);
  576. }
  577. protected virtual IHttpClient CreateHttpClient()
  578. {
  579. return new HttpClientManager.HttpClientManager(ApplicationPaths, LoggerFactory, FileSystemManager, () => ApplicationUserAgent);
  580. }
  581. public static IStreamHelper StreamHelper { get; set; }
  582. /// <summary>
  583. /// Registers resources that classes will depend on
  584. /// </summary>
  585. protected async Task RegisterResources(IServiceCollection serviceCollection)
  586. {
  587. serviceCollection.AddMemoryCache();
  588. serviceCollection.AddSingleton(ConfigurationManager);
  589. serviceCollection.AddSingleton<IApplicationHost>(this);
  590. serviceCollection.AddSingleton<IApplicationPaths>(ApplicationPaths);
  591. serviceCollection.AddSingleton<IConfiguration>(_configuration);
  592. serviceCollection.AddSingleton(JsonSerializer);
  593. serviceCollection.AddSingleton(LoggerFactory);
  594. serviceCollection.AddLogging();
  595. serviceCollection.AddSingleton(Logger);
  596. serviceCollection.AddSingleton(EnvironmentInfo);
  597. serviceCollection.AddSingleton(FileSystemManager);
  598. serviceCollection.AddSingleton<TvDbClientManager>();
  599. HttpClient = CreateHttpClient();
  600. serviceCollection.AddSingleton(HttpClient);
  601. serviceCollection.AddSingleton(NetworkManager);
  602. IsoManager = new IsoManager();
  603. serviceCollection.AddSingleton(IsoManager);
  604. TaskManager = new TaskManager(ApplicationPaths, JsonSerializer, LoggerFactory, FileSystemManager);
  605. serviceCollection.AddSingleton(TaskManager);
  606. serviceCollection.AddSingleton(XmlSerializer);
  607. ProcessFactory = new ProcessFactory();
  608. serviceCollection.AddSingleton(ProcessFactory);
  609. ApplicationHost.StreamHelper = new StreamHelper();
  610. serviceCollection.AddSingleton(StreamHelper);
  611. serviceCollection.AddSingleton(CryptographyProvider);
  612. SocketFactory = new SocketFactory();
  613. serviceCollection.AddSingleton(SocketFactory);
  614. InstallationManager = new InstallationManager(LoggerFactory, this, ApplicationPaths, HttpClient, JsonSerializer, ServerConfigurationManager, FileSystemManager, CryptographyProvider, ZipClient, PackageRuntime);
  615. serviceCollection.AddSingleton(InstallationManager);
  616. ZipClient = new ZipClient();
  617. serviceCollection.AddSingleton(ZipClient);
  618. HttpResultFactory = new HttpResultFactory(LoggerFactory, FileSystemManager, JsonSerializer, StreamHelper);
  619. serviceCollection.AddSingleton(HttpResultFactory);
  620. serviceCollection.AddSingleton<IServerApplicationHost>(this);
  621. serviceCollection.AddSingleton<IServerApplicationPaths>(ApplicationPaths);
  622. serviceCollection.AddSingleton(ServerConfigurationManager);
  623. var assemblyInfo = new AssemblyInfo();
  624. serviceCollection.AddSingleton<IAssemblyInfo>(assemblyInfo);
  625. LocalizationManager = new LocalizationManager(ServerConfigurationManager, FileSystemManager, JsonSerializer, LoggerFactory);
  626. await LocalizationManager.LoadAll();
  627. serviceCollection.AddSingleton<ILocalizationManager>(LocalizationManager);
  628. serviceCollection.AddSingleton<IBlurayExaminer>(new BdInfoExaminer(FileSystemManager));
  629. serviceCollection.AddSingleton<IXmlReaderSettingsFactory>(new XmlReaderSettingsFactory());
  630. UserDataManager = new UserDataManager(LoggerFactory, ServerConfigurationManager, () => UserManager);
  631. serviceCollection.AddSingleton(UserDataManager);
  632. UserRepository = GetUserRepository();
  633. // This is only needed for disposal purposes. If removing this, make sure to have the manager handle disposing it
  634. serviceCollection.AddSingleton(UserRepository);
  635. var displayPreferencesRepo = new SqliteDisplayPreferencesRepository(LoggerFactory, JsonSerializer, ApplicationPaths, FileSystemManager);
  636. serviceCollection.AddSingleton<IDisplayPreferencesRepository>(displayPreferencesRepo);
  637. ItemRepository = new SqliteItemRepository(ServerConfigurationManager, this, JsonSerializer, LoggerFactory, assemblyInfo);
  638. serviceCollection.AddSingleton<IItemRepository>(ItemRepository);
  639. AuthenticationRepository = GetAuthenticationRepository();
  640. serviceCollection.AddSingleton(AuthenticationRepository);
  641. UserManager = new UserManager(LoggerFactory, ServerConfigurationManager, UserRepository, XmlSerializer, NetworkManager, () => ImageProcessor, () => DtoService, this, JsonSerializer, FileSystemManager);
  642. serviceCollection.AddSingleton(UserManager);
  643. LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
  644. serviceCollection.AddSingleton(LibraryManager);
  645. // TODO wtaylor: investigate use of second music manager
  646. var musicManager = new MusicManager(LibraryManager);
  647. serviceCollection.AddSingleton<IMusicManager>(new MusicManager(LibraryManager));
  648. LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager, EnvironmentInfo);
  649. serviceCollection.AddSingleton(LibraryMonitor);
  650. serviceCollection.AddSingleton<ISearchEngine>(new SearchEngine(LoggerFactory, LibraryManager, UserManager));
  651. CertificateInfo = GetCertificateInfo(true);
  652. Certificate = GetCertificate(CertificateInfo);
  653. HttpServer = new HttpListenerHost(this,
  654. LoggerFactory,
  655. ServerConfigurationManager,
  656. _configuration,
  657. NetworkManager,
  658. JsonSerializer,
  659. XmlSerializer,
  660. CreateHttpListener());
  661. HttpServer.GlobalResponse = LocalizationManager.GetLocalizedString("StartupEmbyServerIsLoading");
  662. serviceCollection.AddSingleton(HttpServer);
  663. ImageProcessor = GetImageProcessor();
  664. serviceCollection.AddSingleton(ImageProcessor);
  665. TVSeriesManager = new TVSeriesManager(UserManager, UserDataManager, LibraryManager, ServerConfigurationManager);
  666. serviceCollection.AddSingleton(TVSeriesManager);
  667. DeviceManager = new DeviceManager(AuthenticationRepository, JsonSerializer, LibraryManager, LocalizationManager, UserManager, FileSystemManager, LibraryMonitor, ServerConfigurationManager);
  668. serviceCollection.AddSingleton(DeviceManager);
  669. MediaSourceManager = new MediaSourceManager(ItemRepository, ApplicationPaths, LocalizationManager, UserManager, LibraryManager, LoggerFactory, JsonSerializer, FileSystemManager, UserDataManager, () => MediaEncoder);
  670. serviceCollection.AddSingleton(MediaSourceManager);
  671. SubtitleManager = new SubtitleManager(LoggerFactory, FileSystemManager, LibraryMonitor, MediaSourceManager, LocalizationManager);
  672. serviceCollection.AddSingleton(SubtitleManager);
  673. ProviderManager = new ProviderManager(HttpClient, SubtitleManager, ServerConfigurationManager, LibraryMonitor, LoggerFactory, FileSystemManager, ApplicationPaths, () => LibraryManager, JsonSerializer);
  674. serviceCollection.AddSingleton(ProviderManager);
  675. DtoService = new DtoService(LoggerFactory, LibraryManager, UserDataManager, ItemRepository, ImageProcessor, ProviderManager, this, () => MediaSourceManager, () => LiveTvManager);
  676. serviceCollection.AddSingleton(DtoService);
  677. ChannelManager = new ChannelManager(UserManager, DtoService, LibraryManager, LoggerFactory, ServerConfigurationManager, FileSystemManager, UserDataManager, JsonSerializer, LocalizationManager, HttpClient, ProviderManager);
  678. serviceCollection.AddSingleton(ChannelManager);
  679. SessionManager = new SessionManager(UserDataManager, LoggerFactory, LibraryManager, UserManager, musicManager, DtoService, ImageProcessor, JsonSerializer, this, HttpClient, AuthenticationRepository, DeviceManager, MediaSourceManager);
  680. serviceCollection.AddSingleton(SessionManager);
  681. serviceCollection.AddSingleton<IDlnaManager>(
  682. new DlnaManager(XmlSerializer, FileSystemManager, ApplicationPaths, LoggerFactory, JsonSerializer, this));
  683. CollectionManager = new CollectionManager(LibraryManager, ApplicationPaths, LocalizationManager, FileSystemManager, LibraryMonitor, LoggerFactory, ProviderManager);
  684. serviceCollection.AddSingleton(CollectionManager);
  685. PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager);
  686. serviceCollection.AddSingleton(PlaylistManager);
  687. LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
  688. serviceCollection.AddSingleton(LiveTvManager);
  689. UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
  690. serviceCollection.AddSingleton(UserViewManager);
  691. NotificationManager = new NotificationManager(LoggerFactory, UserManager, ServerConfigurationManager);
  692. serviceCollection.AddSingleton(NotificationManager);
  693. serviceCollection.AddSingleton<IDeviceDiscovery>(
  694. new DeviceDiscovery(LoggerFactory, ServerConfigurationManager, SocketFactory));
  695. ChapterManager = new ChapterManager(LibraryManager, LoggerFactory, ServerConfigurationManager, ItemRepository);
  696. serviceCollection.AddSingleton(ChapterManager);
  697. MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
  698. LoggerFactory,
  699. JsonSerializer,
  700. StartupOptions.FFmpegPath,
  701. StartupOptions.FFprobePath,
  702. ServerConfigurationManager,
  703. FileSystemManager,
  704. () => SubtitleEncoder,
  705. () => MediaSourceManager,
  706. ProcessFactory,
  707. 5000);
  708. serviceCollection.AddSingleton(MediaEncoder);
  709. EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
  710. serviceCollection.AddSingleton(EncodingManager);
  711. var activityLogRepo = GetActivityLogRepository();
  712. serviceCollection.AddSingleton(activityLogRepo);
  713. serviceCollection.AddSingleton<IActivityManager>(new ActivityManager(LoggerFactory, activityLogRepo, UserManager));
  714. var authContext = new AuthorizationContext(AuthenticationRepository, UserManager);
  715. serviceCollection.AddSingleton<IAuthorizationContext>(authContext);
  716. serviceCollection.AddSingleton<ISessionContext>(new SessionContext(UserManager, authContext, SessionManager));
  717. AuthService = new AuthService(UserManager, authContext, ServerConfigurationManager, SessionManager, NetworkManager);
  718. serviceCollection.AddSingleton(AuthService);
  719. SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
  720. serviceCollection.AddSingleton(SubtitleEncoder);
  721. serviceCollection.AddSingleton(CreateResourceFileManager());
  722. displayPreferencesRepo.Initialize();
  723. var userDataRepo = new SqliteUserDataRepository(LoggerFactory, ApplicationPaths);
  724. SetStaticProperties();
  725. ((UserManager)UserManager).Initialize();
  726. ((UserDataManager)UserDataManager).Repository = userDataRepo;
  727. ItemRepository.Initialize(userDataRepo, UserManager);
  728. ((LibraryManager)LibraryManager).ItemRepository = ItemRepository;
  729. _serviceProvider = serviceCollection.BuildServiceProvider();
  730. }
  731. public virtual string PackageRuntime => "netcore";
  732. public static void LogEnvironmentInfo(ILogger logger, IApplicationPaths appPaths, EnvironmentInfo.EnvironmentInfo environmentInfo)
  733. {
  734. // Distinct these to prevent users from reporting problems that aren't actually problems
  735. var commandLineArgs = Environment
  736. .GetCommandLineArgs()
  737. .Distinct();
  738. logger.LogInformation("Arguments: {Args}", commandLineArgs);
  739. logger.LogInformation("Operating system: {OS} {OSVersion}", environmentInfo.OperatingSystemName, environmentInfo.OperatingSystemVersion);
  740. logger.LogInformation("Architecture: {Architecture}", environmentInfo.SystemArchitecture);
  741. logger.LogInformation("64-Bit Process: {Is64Bit}", Environment.Is64BitProcess);
  742. logger.LogInformation("User Interactive: {IsUserInteractive}", Environment.UserInteractive);
  743. logger.LogInformation("Processor count: {ProcessorCount}", Environment.ProcessorCount);
  744. logger.LogInformation("Program data path: {ProgramDataPath}", appPaths.ProgramDataPath);
  745. logger.LogInformation("Application directory: {ApplicationPath}", appPaths.ProgramSystemPath);
  746. }
  747. private void SetHttpLimit()
  748. {
  749. try
  750. {
  751. // Increase the max http request limit
  752. ServicePointManager.DefaultConnectionLimit = Math.Max(96, ServicePointManager.DefaultConnectionLimit);
  753. }
  754. catch (Exception ex)
  755. {
  756. Logger.LogError(ex, "Error setting http limit");
  757. }
  758. }
  759. private X509Certificate2 GetCertificate(CertificateInfo info)
  760. {
  761. var certificateLocation = info?.Path;
  762. if (string.IsNullOrWhiteSpace(certificateLocation))
  763. {
  764. return null;
  765. }
  766. try
  767. {
  768. if (!File.Exists(certificateLocation))
  769. {
  770. return null;
  771. }
  772. // Don't use an empty string password
  773. var password = string.IsNullOrWhiteSpace(info.Password) ? null : info.Password;
  774. var localCert = new X509Certificate2(certificateLocation, password);
  775. //localCert.PrivateKey = PrivateKey.CreateFromFile(pvk_file).RSA;
  776. if (!localCert.HasPrivateKey)
  777. {
  778. Logger.LogError("No private key included in SSL cert {CertificateLocation}.", certificateLocation);
  779. return null;
  780. }
  781. return localCert;
  782. }
  783. catch (Exception ex)
  784. {
  785. Logger.LogError(ex, "Error loading cert from {CertificateLocation}", certificateLocation);
  786. return null;
  787. }
  788. }
  789. private IImageProcessor GetImageProcessor()
  790. {
  791. return new ImageProcessor(LoggerFactory, ServerConfigurationManager.ApplicationPaths, FileSystemManager, ImageEncoder, () => LibraryManager, () => MediaEncoder);
  792. }
  793. /// <summary>
  794. /// Gets the user repository.
  795. /// </summary>
  796. /// <returns>Task{IUserRepository}.</returns>
  797. private IUserRepository GetUserRepository()
  798. {
  799. var repo = new SqliteUserRepository(LoggerFactory, ApplicationPaths, JsonSerializer);
  800. repo.Initialize();
  801. return repo;
  802. }
  803. private IAuthenticationRepository GetAuthenticationRepository()
  804. {
  805. var repo = new AuthenticationRepository(LoggerFactory, ServerConfigurationManager);
  806. repo.Initialize();
  807. return repo;
  808. }
  809. private IActivityRepository GetActivityLogRepository()
  810. {
  811. var repo = new ActivityRepository(LoggerFactory, ServerConfigurationManager.ApplicationPaths, FileSystemManager);
  812. repo.Initialize();
  813. return repo;
  814. }
  815. /// <summary>
  816. /// Dirty hacks
  817. /// </summary>
  818. private void SetStaticProperties()
  819. {
  820. ItemRepository.ImageProcessor = ImageProcessor;
  821. // For now there's no real way to inject these properly
  822. BaseItem.Logger = LoggerFactory.CreateLogger("BaseItem");
  823. BaseItem.ConfigurationManager = ServerConfigurationManager;
  824. BaseItem.LibraryManager = LibraryManager;
  825. BaseItem.ProviderManager = ProviderManager;
  826. BaseItem.LocalizationManager = LocalizationManager;
  827. BaseItem.ItemRepository = ItemRepository;
  828. User.UserManager = UserManager;
  829. BaseItem.FileSystem = FileSystemManager;
  830. BaseItem.UserDataManager = UserDataManager;
  831. BaseItem.ChannelManager = ChannelManager;
  832. Video.LiveTvManager = LiveTvManager;
  833. Folder.UserViewManager = UserViewManager;
  834. UserView.TVSeriesManager = TVSeriesManager;
  835. UserView.PlaylistManager = PlaylistManager;
  836. UserView.CollectionManager = CollectionManager;
  837. BaseItem.MediaSourceManager = MediaSourceManager;
  838. CollectionFolder.XmlSerializer = XmlSerializer;
  839. CollectionFolder.JsonSerializer = JsonSerializer;
  840. CollectionFolder.ApplicationHost = this;
  841. AuthenticatedAttribute.AuthService = AuthService;
  842. }
  843. /// <summary>
  844. /// Finds the parts.
  845. /// </summary>
  846. protected void FindParts()
  847. {
  848. if (!ServerConfigurationManager.Configuration.IsPortAuthorized)
  849. {
  850. ServerConfigurationManager.Configuration.IsPortAuthorized = true;
  851. ConfigurationManager.SaveConfiguration();
  852. }
  853. ConfigurationManager.AddParts(GetExports<IConfigurationFactory>());
  854. Plugins = GetExports<IPlugin>()
  855. .Select(LoadPlugin)
  856. .Where(i => i != null)
  857. .ToArray();
  858. HttpServer.Init(GetExports<IService>(false), GetExports<IWebSocketListener>(), GetUrlPrefixes());
  859. LibraryManager.AddParts(GetExports<IResolverIgnoreRule>(),
  860. GetExports<IItemResolver>(),
  861. GetExports<IIntroProvider>(),
  862. GetExports<IBaseItemComparer>(),
  863. GetExports<ILibraryPostScanTask>());
  864. ProviderManager.AddParts(GetExports<IImageProvider>(),
  865. GetExports<IMetadataService>(),
  866. GetExports<IMetadataProvider>(),
  867. GetExports<IMetadataSaver>(),
  868. GetExports<IExternalId>());
  869. ImageProcessor.AddParts(GetExports<IImageEnhancer>());
  870. LiveTvManager.AddParts(GetExports<ILiveTvService>(), GetExports<ITunerHost>(), GetExports<IListingsProvider>());
  871. SubtitleManager.AddParts(GetExports<ISubtitleProvider>());
  872. ChannelManager.AddParts(GetExports<IChannel>());
  873. MediaSourceManager.AddParts(GetExports<IMediaSourceProvider>());
  874. NotificationManager.AddParts(GetExports<INotificationService>(), GetExports<INotificationTypeFactory>());
  875. UserManager.AddParts(GetExports<IAuthenticationProvider>());
  876. IsoManager.AddParts(GetExports<IIsoMounter>());
  877. }
  878. private IPlugin LoadPlugin(IPlugin plugin)
  879. {
  880. try
  881. {
  882. if (plugin is IPluginAssembly assemblyPlugin)
  883. {
  884. var assembly = plugin.GetType().Assembly;
  885. var assemblyName = assembly.GetName();
  886. var assemblyFilePath = assembly.Location;
  887. var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath));
  888. assemblyPlugin.SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version);
  889. try
  890. {
  891. var idAttributes = assembly.GetCustomAttributes(typeof(GuidAttribute), true);
  892. if (idAttributes.Length > 0)
  893. {
  894. var attribute = (GuidAttribute)idAttributes[0];
  895. var assemblyId = new Guid(attribute.Value);
  896. assemblyPlugin.SetId(assemblyId);
  897. }
  898. }
  899. catch (Exception ex)
  900. {
  901. Logger.LogError(ex, "Error getting plugin Id from {PluginName}.", plugin.GetType().FullName);
  902. }
  903. }
  904. if (plugin is IHasPluginConfiguration hasPluginConfiguration)
  905. {
  906. hasPluginConfiguration.SetStartupInfo(s => Directory.CreateDirectory(s));
  907. }
  908. }
  909. catch (Exception ex)
  910. {
  911. Logger.LogError(ex, "Error loading plugin {pluginName}", plugin.GetType().FullName);
  912. return null;
  913. }
  914. return plugin;
  915. }
  916. /// <summary>
  917. /// Discovers the types.
  918. /// </summary>
  919. protected void DiscoverTypes()
  920. {
  921. Logger.LogInformation("Loading assemblies");
  922. AllConcreteTypes = GetComposablePartAssemblies()
  923. .SelectMany(x => x.ExportedTypes)
  924. .Where(type => type.IsClass && !type.IsAbstract && !type.IsInterface && !type.IsGenericType)
  925. .ToArray();
  926. }
  927. private CertificateInfo CertificateInfo { get; set; }
  928. protected X509Certificate2 Certificate { get; private set; }
  929. private IEnumerable<string> GetUrlPrefixes()
  930. {
  931. var hosts = new[] { "+" };
  932. return hosts.SelectMany(i =>
  933. {
  934. var prefixes = new List<string>
  935. {
  936. "http://"+i+":" + HttpPort + "/"
  937. };
  938. if (CertificateInfo != null)
  939. {
  940. prefixes.Add("https://" + i + ":" + HttpsPort + "/");
  941. }
  942. return prefixes;
  943. });
  944. }
  945. protected IHttpListener CreateHttpListener() => new WebSocketSharpListener(Logger);
  946. private CertificateInfo GetCertificateInfo(bool generateCertificate)
  947. {
  948. if (!string.IsNullOrWhiteSpace(ServerConfigurationManager.Configuration.CertificatePath))
  949. {
  950. // Custom cert
  951. return new CertificateInfo
  952. {
  953. Path = ServerConfigurationManager.Configuration.CertificatePath,
  954. Password = ServerConfigurationManager.Configuration.CertificatePassword
  955. };
  956. }
  957. // Generate self-signed cert
  958. var certHost = GetHostnameFromExternalDns(ServerConfigurationManager.Configuration.WanDdns);
  959. var certPath = Path.Combine(ServerConfigurationManager.ApplicationPaths.ProgramDataPath, "ssl", "cert_" + (certHost + "2").GetMD5().ToString("N") + ".pfx");
  960. var password = "embycert";
  961. //if (generateCertificate)
  962. //{
  963. // if (!File.Exists(certPath))
  964. // {
  965. // FileSystemManager.CreateDirectory(FileSystemManager.GetDirectoryName(certPath));
  966. // try
  967. // {
  968. // CertificateGenerator.CreateSelfSignCertificatePfx(certPath, certHost, password, Logger);
  969. // }
  970. // catch (Exception ex)
  971. // {
  972. // Logger.LogError(ex, "Error creating ssl cert");
  973. // return null;
  974. // }
  975. // }
  976. //}
  977. return new CertificateInfo
  978. {
  979. Path = certPath,
  980. Password = password
  981. };
  982. }
  983. /// <summary>
  984. /// Called when [configuration updated].
  985. /// </summary>
  986. /// <param name="sender">The sender.</param>
  987. /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
  988. protected void OnConfigurationUpdated(object sender, EventArgs e)
  989. {
  990. var requiresRestart = false;
  991. // Don't do anything if these haven't been set yet
  992. if (HttpPort != 0 && HttpsPort != 0)
  993. {
  994. // Need to restart if ports have changed
  995. if (ServerConfigurationManager.Configuration.HttpServerPortNumber != HttpPort ||
  996. ServerConfigurationManager.Configuration.HttpsPortNumber != HttpsPort)
  997. {
  998. if (ServerConfigurationManager.Configuration.IsPortAuthorized)
  999. {
  1000. ServerConfigurationManager.Configuration.IsPortAuthorized = false;
  1001. ServerConfigurationManager.SaveConfiguration();
  1002. requiresRestart = true;
  1003. }
  1004. }
  1005. }
  1006. if (!HttpServer.UrlPrefixes.SequenceEqual(GetUrlPrefixes(), StringComparer.OrdinalIgnoreCase))
  1007. {
  1008. requiresRestart = true;
  1009. }
  1010. var currentCertPath = CertificateInfo == null ? null : CertificateInfo.Path;
  1011. var newCertInfo = GetCertificateInfo(false);
  1012. var newCertPath = newCertInfo == null ? null : newCertInfo.Path;
  1013. if (!string.Equals(currentCertPath, newCertPath, StringComparison.OrdinalIgnoreCase))
  1014. {
  1015. requiresRestart = true;
  1016. }
  1017. if (requiresRestart)
  1018. {
  1019. Logger.LogInformation("App needs to be restarted due to configuration change.");
  1020. NotifyPendingRestart();
  1021. }
  1022. }
  1023. /// <summary>
  1024. /// Notifies that the kernel that a change has been made that requires a restart
  1025. /// </summary>
  1026. public void NotifyPendingRestart()
  1027. {
  1028. Logger.LogInformation("App needs to be restarted.");
  1029. var changed = !HasPendingRestart;
  1030. HasPendingRestart = true;
  1031. if (changed)
  1032. {
  1033. EventHelper.QueueEventIfNotNull(HasPendingRestartChanged, this, EventArgs.Empty, Logger);
  1034. }
  1035. }
  1036. /// <summary>
  1037. /// Restarts this instance.
  1038. /// </summary>
  1039. public void Restart()
  1040. {
  1041. if (!CanSelfRestart)
  1042. {
  1043. throw new PlatformNotSupportedException("The server is unable to self-restart. Please restart manually.");
  1044. }
  1045. if (IsShuttingDown)
  1046. {
  1047. return;
  1048. }
  1049. IsShuttingDown = true;
  1050. Task.Run(async () =>
  1051. {
  1052. try
  1053. {
  1054. await SessionManager.SendServerRestartNotification(CancellationToken.None).ConfigureAwait(false);
  1055. }
  1056. catch (Exception ex)
  1057. {
  1058. Logger.LogError(ex, "Error sending server restart notification");
  1059. }
  1060. Logger.LogInformation("Calling RestartInternal");
  1061. RestartInternal();
  1062. });
  1063. }
  1064. protected abstract void RestartInternal();
  1065. /// <summary>
  1066. /// Gets the composable part assemblies.
  1067. /// </summary>
  1068. /// <returns>IEnumerable{Assembly}.</returns>
  1069. protected IEnumerable<Assembly> GetComposablePartAssemblies()
  1070. {
  1071. if (Directory.Exists(ApplicationPaths.PluginsPath))
  1072. {
  1073. foreach (var file in Directory.EnumerateFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.TopDirectoryOnly))
  1074. {
  1075. Logger.LogInformation("Loading assembly {Path}", file);
  1076. yield return Assembly.LoadFrom(file);
  1077. }
  1078. }
  1079. // Include composable parts in the Api assembly
  1080. yield return typeof(ApiEntryPoint).Assembly;
  1081. // Include composable parts in the Dashboard assembly
  1082. yield return typeof(DashboardService).Assembly;
  1083. // Include composable parts in the Model assembly
  1084. yield return typeof(SystemInfo).Assembly;
  1085. // Include composable parts in the Common assembly
  1086. yield return typeof(IApplicationHost).Assembly;
  1087. // Include composable parts in the Controller assembly
  1088. yield return typeof(IServerApplicationHost).Assembly;
  1089. // Include composable parts in the Providers assembly
  1090. yield return typeof(ProviderUtils).Assembly;
  1091. // Include composable parts in the Photos assembly
  1092. yield return typeof(PhotoProvider).Assembly;
  1093. // Emby.Server implementations
  1094. yield return typeof(InstallationManager).Assembly;
  1095. // MediaEncoding
  1096. yield return typeof(MediaBrowser.MediaEncoding.Encoder.MediaEncoder).Assembly;
  1097. // Dlna
  1098. yield return typeof(DlnaEntryPoint).Assembly;
  1099. // Local metadata
  1100. yield return typeof(BoxSetXmlSaver).Assembly;
  1101. // Notifications
  1102. yield return typeof(NotificationManager).Assembly;
  1103. // Xbmc
  1104. yield return typeof(ArtistNfoProvider).Assembly;
  1105. foreach (var i in GetAssembliesWithPartsInternal())
  1106. {
  1107. yield return i;
  1108. }
  1109. }
  1110. protected abstract IEnumerable<Assembly> GetAssembliesWithPartsInternal();
  1111. /// <summary>
  1112. /// Gets the system status.
  1113. /// </summary>
  1114. /// <returns>SystemInfo.</returns>
  1115. public async Task<SystemInfo> GetSystemInfo(CancellationToken cancellationToken)
  1116. {
  1117. var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
  1118. var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
  1119. return new SystemInfo
  1120. {
  1121. HasPendingRestart = HasPendingRestart,
  1122. IsShuttingDown = IsShuttingDown,
  1123. Version = ApplicationVersion,
  1124. ProductName = ApplicationProductName,
  1125. WebSocketPortNumber = HttpPort,
  1126. CompletedInstallations = InstallationManager.CompletedInstallations.ToArray(),
  1127. Id = SystemId,
  1128. ProgramDataPath = ApplicationPaths.ProgramDataPath,
  1129. LogPath = ApplicationPaths.LogDirectoryPath,
  1130. ItemsByNamePath = ApplicationPaths.InternalMetadataPath,
  1131. InternalMetadataPath = ApplicationPaths.InternalMetadataPath,
  1132. CachePath = ApplicationPaths.CachePath,
  1133. HttpServerPortNumber = HttpPort,
  1134. SupportsHttps = SupportsHttps,
  1135. HttpsPortNumber = HttpsPort,
  1136. OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
  1137. OperatingSystemDisplayName = EnvironmentInfo.OperatingSystemName,
  1138. CanSelfRestart = CanSelfRestart,
  1139. CanLaunchWebBrowser = CanLaunchWebBrowser,
  1140. WanAddress = wanAddress,
  1141. HasUpdateAvailable = HasUpdateAvailable,
  1142. TranscodingTempPath = ApplicationPaths.TranscodingTempPath,
  1143. ServerName = FriendlyName,
  1144. LocalAddress = localAddress,
  1145. SupportsLibraryMonitor = true,
  1146. EncoderLocation = MediaEncoder.EncoderLocation,
  1147. SystemArchitecture = EnvironmentInfo.SystemArchitecture,
  1148. SystemUpdateLevel = SystemUpdateLevel,
  1149. PackageName = StartupOptions.PackageName
  1150. };
  1151. }
  1152. public WakeOnLanInfo[] GetWakeOnLanInfo()
  1153. {
  1154. return NetworkManager.GetMacAddresses()
  1155. .Select(i => new WakeOnLanInfo
  1156. {
  1157. MacAddress = i
  1158. })
  1159. .ToArray();
  1160. }
  1161. public async Task<PublicSystemInfo> GetPublicSystemInfo(CancellationToken cancellationToken)
  1162. {
  1163. var localAddress = await GetLocalApiUrl(cancellationToken).ConfigureAwait(false);
  1164. var wanAddress = await GetWanApiUrl(cancellationToken).ConfigureAwait(false);
  1165. return new PublicSystemInfo
  1166. {
  1167. Version = ApplicationVersion,
  1168. Id = SystemId,
  1169. OperatingSystem = EnvironmentInfo.OperatingSystem.ToString(),
  1170. WanAddress = wanAddress,
  1171. ServerName = FriendlyName,
  1172. LocalAddress = localAddress
  1173. };
  1174. }
  1175. public bool EnableHttps => SupportsHttps && ServerConfigurationManager.Configuration.EnableHttps;
  1176. public bool SupportsHttps => Certificate != null || ServerConfigurationManager.Configuration.IsBehindProxy;
  1177. public async Task<string> GetLocalApiUrl(CancellationToken cancellationToken)
  1178. {
  1179. try
  1180. {
  1181. // Return the first matched address, if found, or the first known local address
  1182. var addresses = await GetLocalIpAddressesInternal(false, 1, cancellationToken).ConfigureAwait(false);
  1183. foreach (var address in addresses)
  1184. {
  1185. return GetLocalApiUrl(address);
  1186. }
  1187. return null;
  1188. }
  1189. catch (Exception ex)
  1190. {
  1191. Logger.LogError(ex, "Error getting local Ip address information");
  1192. }
  1193. return null;
  1194. }
  1195. public async Task<string> GetWanApiUrl(CancellationToken cancellationToken)
  1196. {
  1197. const string url = "http://ipv4.icanhazip.com";
  1198. try
  1199. {
  1200. using (var response = await HttpClient.Get(new HttpRequestOptions
  1201. {
  1202. Url = url,
  1203. LogErrorResponseBody = false,
  1204. LogErrors = false,
  1205. LogRequest = false,
  1206. TimeoutMs = 10000,
  1207. BufferContent = false,
  1208. CancellationToken = cancellationToken
  1209. }))
  1210. {
  1211. return GetLocalApiUrl(response.ReadToEnd().Trim());
  1212. }
  1213. }
  1214. catch (Exception ex)
  1215. {
  1216. Logger.LogError(ex, "Error getting WAN Ip address information");
  1217. }
  1218. return null;
  1219. }
  1220. public string GetLocalApiUrl(IpAddressInfo ipAddress)
  1221. {
  1222. if (ipAddress.AddressFamily == IpAddressFamily.InterNetworkV6)
  1223. {
  1224. return GetLocalApiUrl("[" + ipAddress.Address + "]");
  1225. }
  1226. return GetLocalApiUrl(ipAddress.Address);
  1227. }
  1228. public string GetLocalApiUrl(string host)
  1229. {
  1230. return string.Format("http://{0}:{1}",
  1231. host,
  1232. HttpPort.ToString(CultureInfo.InvariantCulture));
  1233. }
  1234. public Task<List<IpAddressInfo>> GetLocalIpAddresses(CancellationToken cancellationToken)
  1235. {
  1236. return GetLocalIpAddressesInternal(true, 0, cancellationToken);
  1237. }
  1238. private async Task<List<IpAddressInfo>> GetLocalIpAddressesInternal(bool allowLoopback, int limit, CancellationToken cancellationToken)
  1239. {
  1240. var addresses = ServerConfigurationManager
  1241. .Configuration
  1242. .LocalNetworkAddresses
  1243. .Select(NormalizeConfiguredLocalAddress)
  1244. .Where(i => i != null)
  1245. .ToList();
  1246. if (addresses.Count == 0)
  1247. {
  1248. addresses.AddRange(NetworkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
  1249. }
  1250. var resultList = new List<IpAddressInfo>();
  1251. foreach (var address in addresses)
  1252. {
  1253. if (!allowLoopback)
  1254. {
  1255. if (address.Equals(IpAddressInfo.Loopback) || address.Equals(IpAddressInfo.IPv6Loopback))
  1256. {
  1257. continue;
  1258. }
  1259. }
  1260. var valid = await IsIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false);
  1261. if (valid)
  1262. {
  1263. resultList.Add(address);
  1264. if (limit > 0 && resultList.Count >= limit)
  1265. {
  1266. return resultList;
  1267. }
  1268. }
  1269. }
  1270. return resultList;
  1271. }
  1272. private IpAddressInfo NormalizeConfiguredLocalAddress(string address)
  1273. {
  1274. var index = address.Trim('/').IndexOf('/');
  1275. if (index != -1)
  1276. {
  1277. address = address.Substring(index + 1);
  1278. }
  1279. if (NetworkManager.TryParseIpAddress(address.Trim('/'), out IpAddressInfo result))
  1280. {
  1281. return result;
  1282. }
  1283. return null;
  1284. }
  1285. private readonly ConcurrentDictionary<string, bool> _validAddressResults = new ConcurrentDictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
  1286. private async Task<bool> IsIpAddressValidAsync(IpAddressInfo address, CancellationToken cancellationToken)
  1287. {
  1288. if (address.Equals(IpAddressInfo.Loopback) ||
  1289. address.Equals(IpAddressInfo.IPv6Loopback))
  1290. {
  1291. return true;
  1292. }
  1293. var apiUrl = GetLocalApiUrl(address);
  1294. apiUrl += "/system/ping";
  1295. if (_validAddressResults.TryGetValue(apiUrl, out var cachedResult))
  1296. {
  1297. return cachedResult;
  1298. }
  1299. var logPing = false;
  1300. #if DEBUG
  1301. logPing = true;
  1302. #endif
  1303. try
  1304. {
  1305. using (var response = await HttpClient.SendAsync(new HttpRequestOptions
  1306. {
  1307. Url = apiUrl,
  1308. LogErrorResponseBody = false,
  1309. LogErrors = logPing,
  1310. LogRequest = logPing,
  1311. TimeoutMs = 5000,
  1312. BufferContent = false,
  1313. CancellationToken = cancellationToken
  1314. }, "POST").ConfigureAwait(false))
  1315. {
  1316. using (var reader = new StreamReader(response.Content))
  1317. {
  1318. var result = reader.ReadToEnd();
  1319. var valid = string.Equals(Name, result, StringComparison.OrdinalIgnoreCase);
  1320. _validAddressResults.AddOrUpdate(apiUrl, valid, (k, v) => valid);
  1321. Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, valid);
  1322. return valid;
  1323. }
  1324. }
  1325. }
  1326. catch (OperationCanceledException)
  1327. {
  1328. Logger.LogDebug("Ping test result to {0}. Success: {1}", apiUrl, "Cancelled");
  1329. throw;
  1330. }
  1331. catch (Exception ex)
  1332. {
  1333. Logger.LogDebug(ex, "Ping test result to {0}. Success: {1}", apiUrl, false);
  1334. _validAddressResults.AddOrUpdate(apiUrl, false, (k, v) => false);
  1335. return false;
  1336. }
  1337. }
  1338. public string FriendlyName =>
  1339. string.IsNullOrEmpty(ServerConfigurationManager.Configuration.ServerName)
  1340. ? Environment.MachineName
  1341. : ServerConfigurationManager.Configuration.ServerName;
  1342. public int HttpPort { get; private set; }
  1343. public int HttpsPort { get; private set; }
  1344. /// <summary>
  1345. /// Shuts down.
  1346. /// </summary>
  1347. public async Task Shutdown()
  1348. {
  1349. if (IsShuttingDown)
  1350. {
  1351. return;
  1352. }
  1353. IsShuttingDown = true;
  1354. try
  1355. {
  1356. await SessionManager.SendServerShutdownNotification(CancellationToken.None).ConfigureAwait(false);
  1357. }
  1358. catch (Exception ex)
  1359. {
  1360. Logger.LogError(ex, "Error sending server shutdown notification");
  1361. }
  1362. ShutdownInternal();
  1363. }
  1364. protected abstract void ShutdownInternal();
  1365. public event EventHandler HasUpdateAvailableChanged;
  1366. private bool _hasUpdateAvailable;
  1367. public bool HasUpdateAvailable
  1368. {
  1369. get => _hasUpdateAvailable;
  1370. set
  1371. {
  1372. var fireEvent = value && !_hasUpdateAvailable;
  1373. _hasUpdateAvailable = value;
  1374. if (fireEvent)
  1375. {
  1376. HasUpdateAvailableChanged?.Invoke(this, EventArgs.Empty);
  1377. }
  1378. }
  1379. }
  1380. /// <summary>
  1381. /// Removes the plugin.
  1382. /// </summary>
  1383. /// <param name="plugin">The plugin.</param>
  1384. public void RemovePlugin(IPlugin plugin)
  1385. {
  1386. var list = Plugins.ToList();
  1387. list.Remove(plugin);
  1388. Plugins = list.ToArray();
  1389. }
  1390. /// <summary>
  1391. /// This returns localhost in the case of no external dns, and the hostname if the
  1392. /// dns is prefixed with a valid Uri prefix.
  1393. /// </summary>
  1394. /// <param name="externalDns">The external dns prefix to get the hostname of.</param>
  1395. /// <returns>The hostname in <paramref name="externalDns"/></returns>
  1396. private static string GetHostnameFromExternalDns(string externalDns)
  1397. {
  1398. if (string.IsNullOrEmpty(externalDns))
  1399. {
  1400. return "localhost";
  1401. }
  1402. try
  1403. {
  1404. return new Uri(externalDns).Host;
  1405. }
  1406. catch
  1407. {
  1408. return externalDns;
  1409. }
  1410. }
  1411. public virtual void LaunchUrl(string url)
  1412. {
  1413. if (!CanLaunchWebBrowser)
  1414. {
  1415. throw new NotSupportedException();
  1416. }
  1417. var process = ProcessFactory.Create(new ProcessOptions
  1418. {
  1419. FileName = url,
  1420. //EnableRaisingEvents = true,
  1421. UseShellExecute = true,
  1422. ErrorDialog = false
  1423. });
  1424. process.Exited += ProcessExited;
  1425. try
  1426. {
  1427. process.Start();
  1428. }
  1429. catch (Exception ex)
  1430. {
  1431. Logger.LogError(ex, "Error launching url: {url}", url);
  1432. throw;
  1433. }
  1434. }
  1435. private static void ProcessExited(object sender, EventArgs e)
  1436. {
  1437. ((IProcess)sender).Dispose();
  1438. }
  1439. public virtual void EnableLoopback(string appName)
  1440. {
  1441. }
  1442. /// <summary>
  1443. /// Called when [application updated].
  1444. /// </summary>
  1445. /// <param name="package">The package.</param>
  1446. protected void OnApplicationUpdated(PackageVersionInfo package)
  1447. {
  1448. Logger.LogInformation("Application has been updated to version {0}", package.versionStr);
  1449. ApplicationUpdated?.Invoke(this, new GenericEventArgs<PackageVersionInfo>
  1450. {
  1451. Argument = package
  1452. });
  1453. NotifyPendingRestart();
  1454. }
  1455. private bool _disposed;
  1456. /// <summary>
  1457. /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
  1458. /// </summary>
  1459. public void Dispose()
  1460. {
  1461. if (!_disposed)
  1462. {
  1463. _disposed = true;
  1464. Dispose(true);
  1465. }
  1466. }
  1467. /// <summary>
  1468. /// Releases unmanaged and - optionally - managed resources.
  1469. /// </summary>
  1470. /// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
  1471. protected virtual void Dispose(bool dispose)
  1472. {
  1473. if (dispose)
  1474. {
  1475. var type = GetType();
  1476. Logger.LogInformation("Disposing {Type}", type.Name);
  1477. var parts = DisposableParts.Distinct().Where(i => i.GetType() != type).ToList();
  1478. DisposableParts.Clear();
  1479. foreach (var part in parts)
  1480. {
  1481. Logger.LogInformation("Disposing {Type}", part.GetType().Name);
  1482. try
  1483. {
  1484. part.Dispose();
  1485. }
  1486. catch (Exception ex)
  1487. {
  1488. Logger.LogError(ex, "Error disposing {Type}", part.GetType().Name);
  1489. }
  1490. }
  1491. }
  1492. }
  1493. }
  1494. internal class CertificateInfo
  1495. {
  1496. public string Path { get; set; }
  1497. public string Password { get; set; }
  1498. }
  1499. }