From fdafa596832eae13cebcf5bbe5fa867f7ba068f0 Mon Sep 17 00:00:00 2001 From: LukePulverenti Date: Thu, 21 Feb 2013 20:26:35 -0500 Subject: Removed System.Windows.Forms dependancy from Common. Almost done removing NLog dependancy. --- MediaBrowser.ServerApplication/App.xaml | 15 +- MediaBrowser.ServerApplication/App.xaml.cs | 326 +++++++++++++++++++-- .../Controls/ItemUpdateNotification.xaml.cs | 3 +- .../Controls/MultiItemUpdateNotification.xaml.cs | 3 +- .../Logging/LogWindow.xaml | 8 + .../Logging/LogWindow.xaml.cs | 128 ++++++++ .../Logging/WindowTraceListener.cs | 75 +++++ MediaBrowser.ServerApplication/MainWindow.xaml.cs | 4 +- .../MediaBrowser.ServerApplication.csproj | 18 ++ ...MediaBrowser.ServerApplication_TemporaryKey.pfx | Bin 0 -> 1676 bytes MediaBrowser.ServerApplication/packages.config | 1 + 11 files changed, 541 insertions(+), 40 deletions(-) create mode 100644 MediaBrowser.ServerApplication/Logging/LogWindow.xaml create mode 100644 MediaBrowser.ServerApplication/Logging/LogWindow.xaml.cs create mode 100644 MediaBrowser.ServerApplication/Logging/WindowTraceListener.cs create mode 100644 MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx (limited to 'MediaBrowser.ServerApplication') diff --git a/MediaBrowser.ServerApplication/App.xaml b/MediaBrowser.ServerApplication/App.xaml index 6b7f6c38f..3729dc7b6 100644 --- a/MediaBrowser.ServerApplication/App.xaml +++ b/MediaBrowser.ServerApplication/App.xaml @@ -1,8 +1,7 @@ - - - - - + + + + + diff --git a/MediaBrowser.ServerApplication/App.xaml.cs b/MediaBrowser.ServerApplication/App.xaml.cs index 4da5c39fe..cc6367127 100644 --- a/MediaBrowser.ServerApplication/App.xaml.cs +++ b/MediaBrowser.ServerApplication/App.xaml.cs @@ -1,23 +1,31 @@ using MediaBrowser.Common.Kernel; -using MediaBrowser.Common.Logging; -using MediaBrowser.Common.UI; +using MediaBrowser.Common.Updates; using MediaBrowser.Controller; using MediaBrowser.IsoMounter; +using MediaBrowser.Logging.Nlog; using MediaBrowser.Model.Logging; using MediaBrowser.Server.Uninstall; using MediaBrowser.ServerApplication.Implementations; +using Microsoft.Win32; using System; -using System.Collections.Generic; +using System.Deployment.Application; 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 : BaseApplication, IApplication + public partial class App : Application, IApplicationHost { /// /// Defines the entry point of the application. @@ -25,8 +33,7 @@ namespace MediaBrowser.ServerApplication [STAThread] public static void Main() { - var application = new App(LogManager.GetLogger("App")); - application.InitializeComponent(); + var application = new App(new NLogger("App")); application.Run(); } @@ -43,21 +50,45 @@ namespace MediaBrowser.ServerApplication } } + /// + /// 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. + private string LogFilePath { get; set; } + /// /// Initializes a new instance of the class. /// /// The logger. public App(ILogger logger) - : base(logger) { - + Logger = logger; + + InitializeComponent(); } /// /// Gets the name of the product. /// /// The name of the product. - protected override string ProductName + protected string ProductName { get { return Globals.ProductName; } } @@ -66,7 +97,7 @@ namespace MediaBrowser.ServerApplication /// Gets the name of the publisher. /// /// The name of the publisher. - protected override string PublisherName + protected string PublisherName { get { return Globals.PublisherName; } } @@ -75,7 +106,7 @@ namespace MediaBrowser.ServerApplication /// Gets the name of the suite. /// /// The name of the suite. - protected override string SuiteName + protected string SuiteName { get { return Globals.SuiteName; } } @@ -84,21 +115,180 @@ namespace MediaBrowser.ServerApplication /// Gets the name of the uninstaller file. /// /// The name of the uninstaller file. - protected override string UninstallerFileName + protected string UninstallerFileName { get { return "MediaBrowser.Server.Uninstall.exe"; } } /// - /// Called when [second instance launched]. + /// Gets or sets a value indicating whether [last run at startup value]. /// - /// The args. - protected override void OnSecondInstanceLaunched(IList args) + /// 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) { - base.OnSecondInstanceLaunched(args); + bool createdNew; + SingleInstanceMutex = new Mutex(true, @"Local\" + GetType().Assembly.GetName().Name, out createdNew); + if (!createdNew) + { + SingleInstanceMutex = null; + Shutdown(); + return; + } - OpenDashboard(); - InitializeComponent(); + 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() + { + if (!ApplicationDeployment.IsNetworkDeployed) + { + return; + } + + try + { + var clickOnceHelper = new ClickOnceHelper(PublisherName, ProductName, SuiteName); + + if (Kernel.Configuration.RunAtStartup) + { + clickOnceHelper.UpdateUninstallParameters(UninstallerFileName); + clickOnceHelper.AddShortcutToStartup(); + } + else + { + clickOnceHelper.RemoveShortcutFromStartup(); + } + + 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; } /// @@ -179,21 +369,105 @@ namespace MediaBrowser.ServerApplication } /// - /// Instantiates the kernel. + /// 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. /// - /// IKernel. - protected override IKernel InstantiateKernel() + /// The URI. + /// BitmapImage. + /// uri + public BitmapImage GetBitmapImage(string uri) { - return new Kernel(new PismoIsoManager(Logger), new DotNetZipClient(), new BdInfoExaminer(), Logger); + if (string.IsNullOrEmpty(uri)) + { + throw new ArgumentNullException("uri"); + } + + return GetBitmapImage(new Uri(uri)); } /// - /// Instantiates the main window. + /// Gets the bitmap image. /// - /// Window. - protected override Window InstantiateMainWindow() + /// The URI. + /// BitmapImage. + /// uri + public BitmapImage GetBitmapImage(Uri uri) { - return new MainWindow(Logger); + 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; } } } diff --git a/MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs b/MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs index 312e70e66..5dceba994 100644 --- a/MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs +++ b/MediaBrowser.ServerApplication/Controls/ItemUpdateNotification.xaml.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Logging; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; diff --git a/MediaBrowser.ServerApplication/Controls/MultiItemUpdateNotification.xaml.cs b/MediaBrowser.ServerApplication/Controls/MultiItemUpdateNotification.xaml.cs index bab1958fd..9d58c0227 100644 --- a/MediaBrowser.ServerApplication/Controls/MultiItemUpdateNotification.xaml.cs +++ b/MediaBrowser.ServerApplication/Controls/MultiItemUpdateNotification.xaml.cs @@ -1,5 +1,4 @@ -using MediaBrowser.Common.Logging; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Logging; using System; diff --git a/MediaBrowser.ServerApplication/Logging/LogWindow.xaml b/MediaBrowser.ServerApplication/Logging/LogWindow.xaml new file mode 100644 index 000000000..d50b55454 --- /dev/null +++ b/MediaBrowser.ServerApplication/Logging/LogWindow.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/MediaBrowser.ServerApplication/Logging/LogWindow.xaml.cs b/MediaBrowser.ServerApplication/Logging/LogWindow.xaml.cs new file mode 100644 index 000000000..fca978486 --- /dev/null +++ b/MediaBrowser.ServerApplication/Logging/LogWindow.xaml.cs @@ -0,0 +1,128 @@ +using MediaBrowser.Common.Kernel; +using NLog; +using NLog.Config; +using NLog.Targets; +using System.ComponentModel; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; + +namespace MediaBrowser.ServerApplication.Logging +{ + /// + /// Interaction logic for LogWindow.xaml + /// + public partial class LogWindow : Window + { + /// + /// The _ui thread + /// + private readonly TaskScheduler _uiThread; + /// + /// The _kernel + /// + private readonly IKernel _kernel; + + /// + /// Initializes a new instance of the class. + /// + /// The kernel. + public LogWindow(IKernel kernel) + { + InitializeComponent(); + _uiThread = TaskScheduler.FromCurrentSynchronizationContext(); + _kernel = kernel; + + Loaded += LogWindow_Loaded; + } + + /// + /// Handles the Loaded event of the LogWindow control. + /// + /// The source of the event. + /// The instance containing the event data. + void LogWindow_Loaded(object sender, RoutedEventArgs e) + { + var target = new TraceTarget + { + Layout = "${longdate}, ${level}, ${logger}, ${message}" + }; + + AddLogTarget(target, "LogWindowTraceTarget"); + } + + /// + /// Raises the event. + /// + /// A that contains the event data. + protected override void OnClosing(CancelEventArgs e) + { + base.OnClosing(e); + + RemoveLogTarget("LogWindowTraceTarget"); + } + + /// + /// Logs the message. + /// + /// The MSG. + public async void LogMessage(string msg) + { + await Task.Factory.StartNew(() => lbxLogData.Items.Insert(0, msg.TrimEnd('\n')), CancellationToken.None, TaskCreationOptions.None, _uiThread); + } + + /// + /// The log layout + /// + /// The log layout. + public string LogLayout + { + get { return "${longdate}, ${level}, ${logger}, ${message}"; } + } + + /// + /// Adds the log target. + /// + /// The target. + /// The name. + private void AddLogTarget(Target target, string name) + { + var config = NLog.LogManager.Configuration; + + config.RemoveTarget(name); + + target.Name = name; + config.AddTarget(name, target); + + var level = _kernel.Configuration.EnableDebugLevelLogging ? LogLevel.Debug : LogLevel.Info; + + var rule = new LoggingRule("*", level, target); + config.LoggingRules.Add(rule); + + NLog.LogManager.Configuration = config; + } + + /// + /// Removes the log target. + /// + /// The name. + private void RemoveLogTarget(string name) + { + var config = NLog.LogManager.Configuration; + + config.RemoveTarget(name); + + NLog.LogManager.Configuration = config; + } + + /// + /// Shuts down. + /// + public async void ShutDown() + { + await Task.Factory.StartNew(Close, CancellationToken.None, TaskCreationOptions.None, _uiThread); + } + + } + +} diff --git a/MediaBrowser.ServerApplication/Logging/WindowTraceListener.cs b/MediaBrowser.ServerApplication/Logging/WindowTraceListener.cs new file mode 100644 index 000000000..10d6ef812 --- /dev/null +++ b/MediaBrowser.ServerApplication/Logging/WindowTraceListener.cs @@ -0,0 +1,75 @@ +using System.Diagnostics; + +namespace MediaBrowser.ServerApplication.Logging +{ + /// + /// Class WindowTraceListener + /// + public class WindowTraceListener : DefaultTraceListener + { + /// + /// The _window + /// + private readonly LogWindow _window; + /// + /// Initializes a new instance of the class. + /// + /// The window. + public WindowTraceListener(LogWindow window) + { + _window = window; + _window.Show(); + Name = "MBLogWindow"; + } + + /// + /// Writes the value of the object's method to the listener you create when you implement the class. + /// + /// An whose fully qualified class name you want to write. + public override void Write(object o) + { + var str = o as string; + if (str != null) + Write(str); + else + base.Write(o); + } + + /// + /// Writes the output to the OutputDebugString function and to the method. + /// + /// The message to write to OutputDebugString and . + /// + /// + /// + /// + public override void Write(string message) + { + _window.LogMessage(message); + } + + /// + /// Writes the output to the OutputDebugString function and to the method, followed by a carriage return and line feed (\r\n). + /// + /// The message to write to OutputDebugString and . + /// + /// + /// + /// + public override void WriteLine(string message) + { + Write(message+"\n"); + } + + /// + /// Releases the unmanaged resources used by the and optionally releases the managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected override void Dispose(bool disposing) + { + if (_window != null) + _window.ShutDown(); + base.Dispose(disposing); + } + } +} diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs index e020aebf7..8a312e7ef 100644 --- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs +++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs @@ -1,9 +1,9 @@ -using MediaBrowser.Common.Logging; -using MediaBrowser.Controller; +using MediaBrowser.Controller; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Logging; using MediaBrowser.ServerApplication.Controls; +using MediaBrowser.ServerApplication.Logging; using System; using System.Collections.Generic; using System.ComponentModel; diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj index a5be8d687..ff8be69e4 100644 --- a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj +++ b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication.csproj @@ -120,6 +120,10 @@ False ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll + + False + ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll + False ..\ThirdParty\UPnP\Libs\Platinum.Managed.dll @@ -134,9 +138,11 @@ ..\packages\System.Data.SQLite.1.0.84.0\lib\net45\System.Data.SQLite.Linq.dll + + @@ -166,6 +172,10 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + MSBuild:Compile Designer @@ -185,6 +195,10 @@ LibraryExplorer.xaml + + LogWindow.xaml + + MainWindow.xaml Code @@ -238,6 +252,10 @@ {5356ae30-6a6e-4a64-81e3-f76c50595e64} MediaBrowser.IsoMounter + + {67310740-0ec4-4dc2-9921-33df38b20167} + MediaBrowser.Logging.NLog + {7eeeb4bb-f3e8-48fc-b4c5-70f0fff8329b} MediaBrowser.Model diff --git a/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx new file mode 100644 index 000000000..64676b054 Binary files /dev/null and b/MediaBrowser.ServerApplication/MediaBrowser.ServerApplication_TemporaryKey.pfx differ diff --git a/MediaBrowser.ServerApplication/packages.config b/MediaBrowser.ServerApplication/packages.config index c1e5c8098..c9cf3ee00 100644 --- a/MediaBrowser.ServerApplication/packages.config +++ b/MediaBrowser.ServerApplication/packages.config @@ -2,5 +2,6 @@ + \ No newline at end of file -- cgit v1.2.3