ApplicationHost.cs 76 KB

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