using MediaBrowser.ClickOnce; using MediaBrowser.Common.Kernel; using MediaBrowser.Controller; using MediaBrowser.IsoMounter; using MediaBrowser.Logging.Nlog; using MediaBrowser.Model.Logging; using MediaBrowser.Model.Updates; using MediaBrowser.Server.Uninstall; using MediaBrowser.ServerApplication.Implementations; using Microsoft.Win32; 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; } /// /// 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 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, new PismoIsoManager(Logger), new DotNetZipClient(), new BdInfoExaminer(), Logger); 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); } } }