using BDInfo; using MediaBrowser.ClickOnce; using MediaBrowser.Common.IO; using MediaBrowser.Common.Kernel; using MediaBrowser.Common.Net; using MediaBrowser.Controller; using MediaBrowser.IsoMounter; using MediaBrowser.Logging.Nlog; using MediaBrowser.Model.IO; using MediaBrowser.Model.Logging; using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Updates; using MediaBrowser.Networking.Management; using MediaBrowser.Networking.Udp; using MediaBrowser.Networking.Web; using MediaBrowser.Networking.WebSocket; using MediaBrowser.Server.Uninstall; using MediaBrowser.ServerApplication.Implementations; using Microsoft.Win32; using SimpleInjector; using System; using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Cache; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Windows.Media.Imaging; namespace MediaBrowser.ServerApplication { /// /// Interaction logic for App.xaml /// public partial class App : Application, IApplicationHost { /// /// Defines the entry point of the application. /// [STAThread] public static void Main() { var application = new App(new NLogger("App")); application.Run(); } /// /// Gets the instance. /// /// The instance. public static App Instance { get { return Current as App; } } /// /// The single instance mutex /// private Mutex SingleInstanceMutex; /// /// Gets or sets the kernel. /// /// The kernel. protected IKernel Kernel { get; set; } /// /// Gets or sets the logger. /// /// The logger. protected ILogger Logger { get; set; } /// /// Gets or sets the log file path. /// /// The log file path. public string LogFilePath { get; private set; } /// /// The container /// private Container _container = new Container(); /// /// Initializes a new instance of the class. /// /// The logger. public App(ILogger logger) { Logger = logger; InitializeComponent(); } /// /// Gets the name of the product. /// /// The name of the product. protected string ProductName { get { return Globals.ProductName; } } /// /// Gets the name of the publisher. /// /// The name of the publisher. protected string PublisherName { get { return Globals.PublisherName; } } /// /// Gets the name of the suite. /// /// The name of the suite. protected string SuiteName { get { return Globals.SuiteName; } } /// /// Gets the name of the uninstaller file. /// /// The name of the uninstaller file. protected string UninstallerFileName { get { return "MediaBrowser.Server.Uninstall.exe"; } } /// /// Gets or sets the iso manager. /// /// The iso manager. private IIsoManager IsoManager { get; set; } /// /// Gets or sets a value indicating whether [last run at startup value]. /// /// null if [last run at startup value] contains no value, true if [last run at startup value]; otherwise, false. private bool? LastRunAtStartupValue { get; set; } /// /// Raises the event. /// /// A that contains the event data. protected override void OnStartup(StartupEventArgs e) { bool createdNew; SingleInstanceMutex = new Mutex(true, @"Local\" + GetType().Assembly.GetName().Name, out createdNew); if (!createdNew) { SingleInstanceMutex = null; Shutdown(); return; } AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; LoadKernel(); SystemEvents.SessionEnding += SystemEvents_SessionEnding; } /// /// Handles the UnhandledException event of the CurrentDomain control. /// /// The source of the event. /// The instance containing the event data. void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { var exception = (Exception)e.ExceptionObject; Logger.ErrorException("UnhandledException", exception); MessageBox.Show("Unhandled exception: " + exception.Message); } /// /// Handles the SessionEnding event of the SystemEvents control. /// /// The source of the event. /// The instance containing the event data. void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) { // Try to shut down gracefully Shutdown(); } /// /// Loads the kernel. /// protected async void LoadKernel() { Kernel = new Kernel(this, Logger); RegisterResources(); try { new MainWindow(Logger).Show(); var now = DateTime.UtcNow; await Kernel.Init(); var done = (DateTime.UtcNow - now); Logger.Info("Kernel.Init completed in {0}{1} minutes and {2} seconds.", done.Hours > 0 ? done.Hours + " Hours " : "", done.Minutes, done.Seconds); await OnKernelLoaded(); } catch (Exception ex) { Logger.ErrorException("Error launching application", ex); MessageBox.Show("There was an error launching Media Browser: " + ex.Message); // Shutdown the app with an error code Shutdown(1); } } /// /// Called when [kernel loaded]. /// /// Task. protected Task OnKernelLoaded() { return Task.Run(() => { Kernel.ConfigurationUpdated += Kernel_ConfigurationUpdated; ConfigureClickOnceStartup(); }); } /// /// Handles the ConfigurationUpdated event of the Kernel control. /// /// The source of the event. /// The instance containing the event data. void Kernel_ConfigurationUpdated(object sender, EventArgs e) { if (!LastRunAtStartupValue.HasValue || LastRunAtStartupValue.Value != Kernel.Configuration.RunAtStartup) { ConfigureClickOnceStartup(); } } /// /// Configures the click once startup. /// private void ConfigureClickOnceStartup() { try { ClickOnceHelper.ConfigureClickOnceStartupIfInstalled(PublisherName, ProductName, SuiteName, Kernel.Configuration.RunAtStartup, UninstallerFileName); LastRunAtStartupValue = Kernel.Configuration.RunAtStartup; } catch (Exception ex) { Logger.ErrorException("Error configuring ClickOnce", ex); } } /// /// Raises the event. /// /// An that contains the event data. protected override void OnExit(ExitEventArgs e) { ReleaseMutex(); base.OnExit(e); Kernel.Dispose(); } /// /// Releases the mutex. /// private void ReleaseMutex() { if (SingleInstanceMutex == null) { return; } SingleInstanceMutex.ReleaseMutex(); SingleInstanceMutex.Close(); SingleInstanceMutex.Dispose(); SingleInstanceMutex = null; } /// /// Opens the dashboard. /// public static void OpenDashboard() { OpenDashboardPage("dashboard.html"); } /// /// Opens the dashboard page. /// /// The page. public static void OpenDashboardPage(string page) { var url = "http://localhost:" + Controller.Kernel.Instance.Configuration.HttpServerPortNumber + "/" + Controller.Kernel.Instance.WebApplicationName + "/dashboard/" + page; url = AddAutoLoginToDashboardUrl(url); OpenUrl(url); } /// /// Adds the auto login to dashboard URL. /// /// The URL. /// System.String. public static string AddAutoLoginToDashboardUrl(string url) { var user = Controller.Kernel.Instance.Users.FirstOrDefault(u => u.Configuration.IsAdministrator); if (user != null) { if (url.IndexOf('?') == -1) { url += "?u=" + user.Id; } else { url += "&u=" + user.Id; } } return url; } /// /// Opens the URL. /// /// The URL. public static void OpenUrl(string url) { var process = new Process { StartInfo = new ProcessStartInfo { FileName = url }, EnableRaisingEvents = true }; process.Exited += ProcessExited; process.Start(); } /// /// Processes the exited. /// /// The sender. /// The instance containing the event data. static void ProcessExited(object sender, EventArgs e) { ((Process)sender).Dispose(); } /// /// Restarts this instance. /// /// public void Restart() { Dispatcher.Invoke(ReleaseMutex); Kernel.Dispose(); System.Windows.Forms.Application.Restart(); Dispatcher.Invoke(Shutdown); } /// /// Reloads the logger. /// /// public void ReloadLogger() { LogFilePath = Path.Combine(Kernel.ApplicationPaths.LogDirectoryPath, "Server-" + DateTime.Now.Ticks + ".log"); NlogManager.AddFileTarget(LogFilePath, Kernel.Configuration.EnableDebugLevelLogging); } /// /// Gets the image. /// /// The URI. /// Image. /// uri public Image GetImage(string uri) { if (string.IsNullOrEmpty(uri)) { throw new ArgumentNullException("uri"); } return GetImage(new Uri(uri)); } /// /// Gets the image. /// /// The URI. /// Image. /// uri public Image GetImage(Uri uri) { if (uri == null) { throw new ArgumentNullException("uri"); } return new Image { Source = GetBitmapImage(uri) }; } /// /// Gets the bitmap image. /// /// The URI. /// BitmapImage. /// uri public BitmapImage GetBitmapImage(string uri) { if (string.IsNullOrEmpty(uri)) { throw new ArgumentNullException("uri"); } return GetBitmapImage(new Uri(uri)); } /// /// Gets the bitmap image. /// /// The URI. /// BitmapImage. /// uri public BitmapImage GetBitmapImage(Uri uri) { if (uri == null) { throw new ArgumentNullException("uri"); } var bitmap = new BitmapImage { CreateOptions = BitmapCreateOptions.DelayCreation, CacheOption = BitmapCacheOption.OnDemand, UriCachePolicy = new RequestCachePolicy(RequestCacheLevel.CacheIfAvailable) }; bitmap.BeginInit(); bitmap.UriSource = uri; bitmap.EndInit(); RenderOptions.SetBitmapScalingMode(bitmap, BitmapScalingMode.Fant); return bitmap; } /// /// Gets or sets a value indicating whether this instance can self update. /// /// true if this instance can self update; otherwise, false. public bool CanSelfUpdate { get { return ClickOnceHelper.IsNetworkDeployed; } } /// /// Checks for update. /// /// The cancellation token. /// The progress. /// Task{CheckForUpdateResult}. public Task CheckForApplicationUpdate(CancellationToken cancellationToken, IProgress progress) { return new ApplicationUpdateCheck().CheckForApplicationUpdate(cancellationToken, progress); } /// /// Updates the application. /// /// The cancellation token. /// The progress. /// Task. public Task UpdateApplication(CancellationToken cancellationToken, IProgress progress) { return new ApplicationUpdater().UpdateApplication(cancellationToken, progress); } /// /// Registers resources that classes will depend on /// private void RegisterResources() { RegisterSingleInstance(this); RegisterSingleInstance(Logger); IsoManager = new PismoIsoManager(Logger); RegisterSingleInstance(IsoManager); RegisterSingleInstance(() => new BdInfoExaminer()); RegisterSingleInstance(() => new NetworkManager()); RegisterSingleInstance(() => new DotNetZipClient()); RegisterSingleInstance(() => new AlchemyServer(Logger)); Register(typeof(IUdpServer), typeof(UdpServer)); RegisterSingleInstance(() => new HttpServer(this, Kernel, Logger, "Media Browser", "index.html")); } /// /// Creates an instance of type and resolves all constructor dependancies /// /// The type. /// System.Object. public object CreateInstance(Type type) { try { return _container.GetInstance(type); } catch { Logger.Error("Error creating {0}", type.Name); throw; } } /// /// Registers the specified obj. /// /// /// The obj. public void RegisterSingleInstance(T obj) where T : class { _container.RegisterSingle(obj); } /// /// Registers the specified func. /// /// /// The func. public void Register(Func func) where T : class { _container.Register(func); } /// /// Registers the single instance. /// /// /// The func. public void RegisterSingleInstance(Func func) where T : class { _container.RegisterSingle(func); } /// /// Resolves this instance. /// /// /// ``0. public T Resolve() { return (T)_container.GetRegistration(typeof(T), true).GetInstance(); } /// /// Resolves this instance. /// /// /// ``0. public T TryResolve() { var result = _container.GetRegistration(typeof(T), false); if (result == null) { return default(T); } return (T)result.GetInstance(); } /// /// Registers the specified service type. /// /// Type of the service. /// Type of the concrete. public void Register(Type serviceType, Type implementation) { _container.Register(serviceType, implementation); } } }