support run as service

This commit is contained in:
Luke Pulverenti 2013-09-20 21:04:14 -04:00
parent b5615cb233
commit 2e511fba83
16 changed files with 550 additions and 205 deletions

View File

@ -1,6 +1,5 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Implementations.Logging;
using MediaBrowser.Common.Implementations.NetworkManagement;
using MediaBrowser.Common.Implementations.ScheduledTasks;
using MediaBrowser.Common.Implementations.Security;
@ -71,7 +70,7 @@ namespace MediaBrowser.Common.Implementations
/// Gets the application paths.
/// </summary>
/// <value>The application paths.</value>
protected TApplicationPathsType ApplicationPaths = new TApplicationPathsType();
protected TApplicationPathsType ApplicationPaths { get; private set; }
/// <summary>
/// The container
@ -153,11 +152,12 @@ namespace MediaBrowser.Common.Implementations
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationHost{TApplicationPathsType}"/> class.
/// </summary>
protected BaseApplicationHost()
protected BaseApplicationHost(TApplicationPathsType applicationPaths, ILogManager logManager)
{
FailedAssemblies = new List<string>();
LogManager = new NlogManager(ApplicationPaths.LogDirectoryPath, LogFilePrefixName);
ApplicationPaths = applicationPaths;
LogManager = logManager;
ConfigurationManager = GetConfigurationManager();
}
@ -172,7 +172,10 @@ namespace MediaBrowser.Common.Implementations
Logger = LogManager.GetLogger("App");
LogManager.ReloadLogger(ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info);
LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging
? LogSeverity.Debug
: LogSeverity.Info;
OnLoggerLoaded();
DiscoverTypes();
@ -211,12 +214,6 @@ namespace MediaBrowser.Common.Implementations
/// <returns>IEnumerable{Assembly}.</returns>
protected abstract IEnumerable<Assembly> GetComposablePartAssemblies();
/// <summary>
/// Gets the name of the log file prefix.
/// </summary>
/// <value>The name of the log file prefix.</value>
protected abstract string LogFilePrefixName { get; }
/// <summary>
/// Gets the configuration manager.
/// </summary>

View File

@ -26,6 +26,15 @@ namespace MediaBrowser.Common.Implementations
_useDebugPath = useDebugPath;
}
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
/// </summary>
/// <param name="programDataPath">The program data path.</param>
protected BaseApplicationPaths(string programDataPath)
{
_programDataPath = programDataPath;
}
/// <summary>
/// The _program data path
/// </summary>

View File

@ -1,10 +1,10 @@
using System.Linq;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.Logging;
using NLog;
using NLog.Config;
using NLog.Targets;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace MediaBrowser.Common.Implementations.Logging
@ -45,6 +45,41 @@ namespace MediaBrowser.Common.Implementations.Logging
LogFilePrefix = logFileNamePrefix;
}
private LogSeverity _severity = LogSeverity.Debug;
public LogSeverity LogSeverity
{
get
{
return _severity;
}
set
{
var changed = _severity != value;
_severity = value;
if (changed)
{
UpdateLogLevel(value);
}
}
}
private void UpdateLogLevel(LogSeverity newLevel)
{
var level = GetLogLevel(newLevel);
var rules = LogManager.Configuration.LoggingRules;
foreach (var rule in rules)
{
if (!rule.IsLoggingEnabledForLevel(level))
{
rule.EnableLoggingForLevel(level);
}
}
}
/// <summary>
/// Adds the file target.
/// </summary>
@ -154,6 +189,8 @@ namespace MediaBrowser.Common.Implementations.Logging
AddFileTarget(LogFilePath, level);
LogSeverity = level;
if (LoggerLoaded != null)
{
Task.Run(() =>

View File

@ -25,11 +25,5 @@ namespace MediaBrowser.Controller
/// </summary>
/// <value>The HTTP server URL prefix.</value>
string HttpServerUrlPrefix { get; }
/// <summary>
/// Gets a value indicating whether this instance is background service.
/// </summary>
/// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
bool IsBackgroundService { get; }
}
}

View File

@ -7,6 +7,12 @@ namespace MediaBrowser.Model.Logging
/// </summary>
public interface ILogManager
{
/// <summary>
/// Gets or sets the log level.
/// </summary>
/// <value>The log level.</value>
LogSeverity LogSeverity { get; set; }
/// <summary>
/// Gets the logger.
/// </summary>

View File

@ -80,12 +80,6 @@ namespace MediaBrowser.Model.System
/// <value>The HTTP server port number.</value>
public int HttpServerPortNumber { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this instance is background service.
/// </summary>
/// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
public bool IsBackgroundService { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="SystemInfo" /> class.
/// </summary>

View File

@ -26,6 +26,17 @@ namespace MediaBrowser.Server.Implementations
{
}
#endif
/// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths" /> class.
/// </summary>
/// <param name="programDataPath">The program data path.</param>
public ServerApplicationPaths(string programDataPath)
: base(programDataPath)
{
}
/// <summary>
/// Gets the path to the base root media directory
/// </summary>
@ -117,7 +128,7 @@ namespace MediaBrowser.Server.Implementations
return Path.Combine(ItemsByNamePath, "MusicGenre");
}
}
/// <summary>
/// Gets the path to the Studio directory
/// </summary>

View File

@ -1,4 +1,5 @@
using MediaBrowser.Controller;
using MediaBrowser.Common.Events;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Logging;
@ -12,32 +13,35 @@ namespace MediaBrowser.ServerApplication
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, IApplicationInterface
public partial class App : Application
{
/// <summary>
/// Gets or sets the logger.
/// </summary>
/// <value>The logger.</value>
protected ILogger Logger { get; set; }
private readonly ILogger _logger;
/// <summary>
/// Gets or sets the composition root.
/// </summary>
/// <value>The composition root.</value>
protected ApplicationHost CompositionRoot { get; set; }
private readonly ApplicationHost _appHost;
public event EventHandler AppStarted;
public bool IsRunningAsService { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="App" /> class.
/// </summary>
/// <param name="logger">The logger.</param>
public App()
public App(ApplicationHost appHost, ILogger logger, bool isRunningAsService)
{
InitializeComponent();
}
_appHost = appHost;
_logger = logger;
IsRunningAsService = isRunningAsService;
public bool IsBackgroundService
{
get { return false; }
InitializeComponent();
}
/// <summary>
@ -51,7 +55,7 @@ namespace MediaBrowser.ServerApplication
public void OnUnhandledException(Exception ex)
{
Logger.ErrorException("UnhandledException", ex);
_logger.ErrorException("UnhandledException", ex);
MessageBox.Show("Unhandled exception: " + ex.Message);
}
@ -70,27 +74,32 @@ namespace MediaBrowser.ServerApplication
{
try
{
CompositionRoot = new ApplicationHost(this);
if (!IsRunningAsService)
{
ShowSplashWindow();
}
Logger = CompositionRoot.LogManager.GetLogger("App");
await _appHost.Init();
var splash = new SplashWindow(CompositionRoot.ApplicationVersion);
if (!IsRunningAsService)
{
HideSplashWindow();
}
splash.Show();
var task = _appHost.RunStartupTasks();
await CompositionRoot.Init();
if (!IsRunningAsService)
{
ShowMainWindow();
}
splash.Hide();
var task = CompositionRoot.RunStartupTasks();
new MainWindow(CompositionRoot.LogManager, CompositionRoot, CompositionRoot.ServerConfigurationManager, CompositionRoot.UserManager, CompositionRoot.LibraryManager, CompositionRoot.JsonSerializer, CompositionRoot.DisplayPreferencesRepository).Show();
EventHelper.FireEventIfNotNull(AppStarted, this, EventArgs.Empty, _logger);
await task.ConfigureAwait(false);
}
catch (Exception ex)
{
Logger.ErrorException("Error launching application", ex);
_logger.ErrorException("Error launching application", ex);
MessageBox.Show("There was an error launching Media Browser: " + ex.Message);
@ -99,27 +108,53 @@ namespace MediaBrowser.ServerApplication
}
}
private MainWindow _mainWindow;
private void ShowMainWindow()
{
var host = _appHost;
var win = new MainWindow(host.LogManager, host,
host.ServerConfigurationManager, host.UserManager,
host.LibraryManager, host.JsonSerializer,
host.DisplayPreferencesRepository);
win.Show();
_mainWindow = win;
}
private void HideMainWindow()
{
if (_mainWindow != null)
{
_mainWindow.Hide();
_mainWindow = null;
}
}
private SplashWindow _splashWindow;
private void ShowSplashWindow()
{
var win = new SplashWindow(_appHost.ApplicationVersion);
win.Show();
_splashWindow = win;
}
private void HideSplashWindow()
{
if (_splashWindow != null)
{
_splashWindow.Hide();
_splashWindow = null;
}
}
public void ShutdownApplication()
{
Dispatcher.Invoke(Shutdown);
}
/// <summary>
/// Raises the <see cref="E:System.Windows.Application.Exit" /> event.
/// </summary>
/// <param name="e">An <see cref="T:System.Windows.ExitEventArgs" /> that contains the event data.</param>
protected override void OnExit(ExitEventArgs e)
{
MainStartup.ReleaseMutex();
base.OnExit(e);
if (CompositionRoot != null)
{
CompositionRoot.Dispose();
}
}
/// <summary>
/// Opens the dashboard page.
/// </summary>
@ -172,20 +207,5 @@ namespace MediaBrowser.ServerApplication
{
((Process)sender).Dispose();
}
/// <summary>
/// Restarts this instance.
/// </summary>
/// <exception cref="System.NotImplementedException"></exception>
public void RestartApplication()
{
Dispatcher.Invoke(MainStartup.ReleaseMutex);
CompositionRoot.Dispose();
System.Windows.Forms.Application.Restart();
Dispatcher.Invoke(Shutdown);
}
}
}

View File

@ -26,6 +26,7 @@ using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.IsoMounter;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Logging;
using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.System;
using MediaBrowser.Model.Updates;
@ -59,6 +60,7 @@ using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace MediaBrowser.ServerApplication
{
@ -84,15 +86,6 @@ namespace MediaBrowser.ServerApplication
get { return (IServerConfigurationManager)ConfigurationManager; }
}
/// <summary>
/// Gets the name of the log file prefix.
/// </summary>
/// <value>The name of the log file prefix.</value>
protected override string LogFilePrefixName
{
get { return "server"; }
}
/// <summary>
/// Gets the name of the web application that can be used for url building.
/// All api urls will be of the form {protocol}://{host}:{port}/{appname}/...
@ -182,13 +175,6 @@ namespace MediaBrowser.ServerApplication
private IItemRepository ItemRepository { get; set; }
private INotificationsRepository NotificationsRepository { get; set; }
public bool IsBackgroundService
{
get { return _appInterface != null && _appInterface.IsBackgroundService; }
}
private readonly IApplicationInterface _appInterface;
/// <summary>
/// The full path to our startmenu shortcut
/// </summary>
@ -199,9 +185,15 @@ namespace MediaBrowser.ServerApplication
private Task<IHttpServer> _httpServerCreationTask;
public ApplicationHost(IApplicationInterface appInterface)
/// <summary>
/// Initializes a new instance of the <see cref="ApplicationHost"/> class.
/// </summary>
/// <param name="applicationPaths">The application paths.</param>
/// <param name="logManager">The log manager.</param>
public ApplicationHost(ServerApplicationPaths applicationPaths, ILogManager logManager)
: base(applicationPaths, logManager)
{
_appInterface = appInterface;
}
/// <summary>
@ -542,7 +534,14 @@ namespace MediaBrowser.ServerApplication
Logger.ErrorException("Error sending server restart web socket message", ex);
}
_appInterface.RestartApplication();
// Second instance will start first, so release the mutex and dispose the http server ahead of time
Application.Current.Dispatcher.Invoke(() => MainStartup.ReleaseMutex(Logger));
Dispose();
System.Windows.Forms.Application.Restart();
ShutdownInternal();
}
/// <summary>
@ -627,8 +626,7 @@ namespace MediaBrowser.ServerApplication
Id = _systemId,
ProgramDataPath = ApplicationPaths.ProgramDataPath,
MacAddress = GetMacAddress(),
HttpServerPortNumber = ServerConfigurationManager.Configuration.HttpServerPortNumber,
IsBackgroundService = IsBackgroundService
HttpServerPortNumber = ServerConfigurationManager.Configuration.HttpServerPortNumber
};
}
@ -663,7 +661,15 @@ namespace MediaBrowser.ServerApplication
Logger.ErrorException("Error sending server shutdown web socket message", ex);
}
_appInterface.ShutdownApplication();
ShutdownInternal();
}
public void ShutdownInternal()
{
Logger.Info("Shutting down application");
var app = Application.Current;
app.Dispatcher.Invoke(app.Shutdown);
}
/// <summary>

View File

@ -1,30 +1,40 @@
using System.ServiceProcess;
using MediaBrowser.Model.Logging;
using System.ServiceProcess;
namespace MediaBrowser.ServerApplication
{
/// <summary>
/// Class BackgroundService
/// </summary>
public class BackgroundService : ServiceBase
{
public BackgroundService()
public static string Name = "MediaBrowser";
public static string DisplayName = "Media Browser";
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="BackgroundService"/> class.
/// </summary>
public BackgroundService(ILogger logger)
{
_logger = logger;
CanPauseAndContinue = false;
CanHandleSessionChangeEvent = true;
CanStop = false;
CanShutdown = true;
ServiceName = "Media Browser";
CanStop = true;
ServiceName = Name;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
/// <summary>
/// When implemented in a derived class, executes when a Stop command is sent to the service by the Service Control Manager (SCM). Specifies actions to take when a service stops running.
/// </summary>
protected override void OnStop()
{
base.OnSessionChange(changeDescription);
}
_logger.Info("Stop command received");
protected override void OnStart(string[] args)
{
}
protected override void OnShutdown()
{
base.OnShutdown();
base.OnStop();
}
}
}

View File

@ -0,0 +1,60 @@
using System.Collections;
using System.ComponentModel;
using System.ServiceProcess;
namespace MediaBrowser.ServerApplication
{
[RunInstaller(true)]
public class BackgroundServiceInstaller : System.Configuration.Install.Installer
{
public BackgroundServiceInstaller()
{
var process = new ServiceProcessInstaller
{
Account = ServiceAccount.LocalSystem
};
var serviceAdmin = new ServiceInstaller
{
StartType = ServiceStartMode.Manual,
ServiceName = BackgroundService.Name,
DisplayName = BackgroundService.DisplayName,
DelayedAutoStart = true,
Description = "The windows background service for Media Browser Server."
};
// Microsoft didn't add the ability to add a
// description for the services we are going to install
// To work around this we'll have to add the
// information directly to the registry but I'll leave
// this exercise for later.
// now just add the installers that we created to our
// parents container, the documentation
// states that there is not any order that you need to
// worry about here but I'll still
// go ahead and add them in the order that makes sense.
Installers.Add(process);
Installers.Add(serviceAdmin);
}
protected override void OnBeforeInstall(IDictionary savedState)
{
Context.Parameters["assemblypath"] = "\"" +
Context.Parameters["assemblypath"] + "\" " + GetStartArgs();
base.OnBeforeInstall(savedState);
}
protected override void OnBeforeUninstall(IDictionary savedState)
{
Context.Parameters["assemblypath"] = "\"" +
Context.Parameters["assemblypath"] + "\" " + GetStartArgs();
base.OnBeforeUninstall(savedState);
}
private string GetStartArgs()
{
return "-service";
}
}
}

View File

@ -64,10 +64,7 @@ namespace MediaBrowser.ServerApplication.EntryPoints
{
_logger.ErrorException("Error launching startup wizard", ex);
if (!_appHost.IsBackgroundService)
{
MessageBox.Show("There was an error launching the Media Browser startup wizard. Please ensure a web browser is installed on the machine and is configured as the default browser.", "Media Browser");
}
MessageBox.Show("There was an error launching the Media Browser startup wizard. Please ensure a web browser is installed on the machine and is configured as the default browser.", "Media Browser");
}
}

View File

@ -1,32 +0,0 @@
using System;
namespace MediaBrowser.ServerApplication
{
/// <summary>
/// Interface IApplicationInterface
/// </summary>
public interface IApplicationInterface
{
/// <summary>
/// Gets a value indicating whether this instance is background service.
/// </summary>
/// <value><c>true</c> if this instance is background service; otherwise, <c>false</c>.</value>
bool IsBackgroundService { get; }
/// <summary>
/// Shutdowns the application.
/// </summary>
void ShutdownApplication();
/// <summary>
/// Restarts the application.
/// </summary>
void RestartApplication();
/// <summary>
/// Called when [unhandled exception].
/// </summary>
/// <param name="ex">The ex.</param>
void OnUnhandledException(Exception ex);
}
}

View File

@ -1,12 +1,18 @@
using MediaBrowser.Common.Constants;
using MediaBrowser.Common.Implementations.Logging;
using MediaBrowser.Common.Implementations.Updates;
using MediaBrowser.Model.Logging;
using MediaBrowser.Server.Implementations;
using Microsoft.Win32;
using System;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Win32;
namespace MediaBrowser.ServerApplication
{
@ -17,7 +23,9 @@ namespace MediaBrowser.ServerApplication
/// </summary>
private static Mutex _singleInstanceMutex;
private static IApplicationInterface _applicationInterface;
private static ApplicationHost _appHost;
private static App _app;
/// <summary>
/// Defines the entry point of the application.
@ -25,6 +33,50 @@ namespace MediaBrowser.ServerApplication
[STAThread]
public static void Main()
{
var startFlag = Environment.GetCommandLineArgs().ElementAtOrDefault(1);
var runService = string.Equals(startFlag, "-service", StringComparison.OrdinalIgnoreCase);
var appPaths = CreateApplicationPaths(runService);
var logManager = new NlogManager(appPaths.LogDirectoryPath, "server");
logManager.ReloadLogger(LogSeverity.Info);
var logger = logManager.GetLogger("Main");
BeginLog(logger);
// Install directly
if (string.Equals(startFlag, "-installservice", StringComparison.OrdinalIgnoreCase))
{
logger.Info("Performing service installation");
InstallService(logger);
return;
}
// Restart with admin rights, then install
if (string.Equals(startFlag, "-launchinstallservice", StringComparison.OrdinalIgnoreCase))
{
logger.Info("Performing service installation");
RunServiceInstallation();
return;
}
// Uninstall directly
if (string.Equals(startFlag, "-uninstallservice", StringComparison.OrdinalIgnoreCase))
{
logger.Info("Performing service uninstallation");
UninstallService(logger);
return;
}
// Restart with admin rights, then uninstall
if (string.Equals(startFlag, "-launchuninstallservice", StringComparison.OrdinalIgnoreCase))
{
logger.Info("Performing service uninstallation");
RunServiceUninstallation();
return;
}
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
bool createdNew;
@ -36,78 +88,228 @@ namespace MediaBrowser.ServerApplication
if (!createdNew)
{
_singleInstanceMutex = null;
logger.Info("Shutting down because another instance of Media Browser Server is already running.");
return;
}
// Look for the existence of an update archive
var appPaths = new ServerApplicationPaths();
var updateArchive = Path.Combine(appPaths.TempUpdatePath, Constants.MbServerPkgName + ".zip");
if (File.Exists(updateArchive))
if (PerformUpdateIfNeeded(appPaths, logger))
{
// Update is there - execute update
try
{
new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive);
// And just let the app exit so it can update
return;
}
catch (Exception e)
{
MessageBox.Show(string.Format("Error attempting to update application.\n\n{0}\n\n{1}", e.GetType().Name, e.Message));
}
logger.Info("Exiting to perform application update.");
return;
}
StartApplication();
try
{
RunApplication(appPaths, logManager, runService);
}
finally
{
logger.Info("Shutting down");
ReleaseMutex(logger);
_appHost.Dispose();
}
}
private static void StartApplication()
/// <summary>
/// Creates the application paths.
/// </summary>
/// <param name="runAsService">if set to <c>true</c> [run as service].</param>
/// <returns>ServerApplicationPaths.</returns>
private static ServerApplicationPaths CreateApplicationPaths(bool runAsService)
{
if (runAsService)
{
#if (RELEASE)
var systemPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
var programDataPath = Path.GetDirectoryName(systemPath);
return new ServerApplicationPaths(programDataPath);
#endif
}
return new ServerApplicationPaths();
}
/// <summary>
/// Begins the log.
/// </summary>
/// <param name="logger">The logger.</param>
private static void BeginLog(ILogger logger)
{
logger.Info("Media Browser Server started");
logger.Info("Command line: {0}", string.Join(" ", Environment.GetCommandLineArgs()));
logger.Info("Server: {0}", Environment.MachineName);
logger.Info("Operating system: {0}", Environment.OSVersion.ToString());
}
/// <summary>
/// Runs the application.
/// </summary>
/// <param name="appPaths">The app paths.</param>
/// <param name="logManager">The log manager.</param>
/// <param name="runService">if set to <c>true</c> [run service].</param>
private static void RunApplication(ServerApplicationPaths appPaths, ILogManager logManager, bool runService)
{
SystemEvents.SessionEnding += SystemEvents_SessionEnding;
var commandLineArgs = Environment.GetCommandLineArgs();
if (commandLineArgs.Length > 1 && commandLineArgs[1].Equals("-service"))
_appHost = new ApplicationHost(appPaths, logManager);
_app = new App(_appHost, _appHost.LogManager.GetLogger("App"), runService);
if (runService)
{
// Start application as a service
StartBackgroundService();
_app.AppStarted += (sender, args) => StartService(logManager);
}
else
_app.Run();
}
/// <summary>
/// Starts the service.
/// </summary>
private static void StartService(ILogManager logManager)
{
var ctl = ServiceController.GetServices().FirstOrDefault(s => s.ServiceName == BackgroundService.Name);
if (ctl == null)
{
StartWpfApp();
RunServiceInstallation();
}
var service = new BackgroundService(logManager.GetLogger("Service"));
service.Disposed += service_Disposed;
ServiceBase.Run(service);
}
/// <summary>
/// Handles the Disposed event of the service control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
static async void service_Disposed(object sender, EventArgs e)
{
await _appHost.Shutdown();
}
/// <summary>
/// Installs the service.
/// </summary>
private static void InstallService(ILogger logger)
{
var runningPath = Process.GetCurrentProcess().MainModule.FileName;
try
{
ManagedInstallerClass.InstallHelper(new[] { runningPath });
logger.Info("Service installation succeeded");
}
catch (Exception ex)
{
logger.ErrorException("Uninstall failed", ex);
}
}
/// <summary>
/// Uninstalls the service.
/// </summary>
private static void UninstallService(ILogger logger)
{
var runningPath = Process.GetCurrentProcess().MainModule.FileName;
try
{
ManagedInstallerClass.InstallHelper(new[] { "/u", runningPath });
logger.Info("Service uninstallation succeeded");
}
catch (Exception ex)
{
logger.ErrorException("Uninstall failed", ex);
}
}
/// <summary>
/// Runs the service installation.
/// </summary>
private static void RunServiceInstallation()
{
var runningPath = Process.GetCurrentProcess().MainModule.FileName;
var startInfo = new ProcessStartInfo
{
FileName = runningPath,
Arguments = "-installservice",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "runas",
ErrorDialog = false
};
using (var process = Process.Start(startInfo))
{
process.WaitForExit();
}
}
/// <summary>
/// Runs the service uninstallation.
/// </summary>
private static void RunServiceUninstallation()
{
var runningPath = Process.GetCurrentProcess().MainModule.FileName;
var startInfo = new ProcessStartInfo
{
FileName = runningPath,
Arguments = "-uninstallservice",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
Verb = "runas",
ErrorDialog = false
};
using (var process = Process.Start(startInfo))
{
process.WaitForExit();
}
}
/// <summary>
/// Handles the SessionEnding event of the SystemEvents control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="SessionEndingEventArgs"/> instance containing the event data.</param>
static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
// Try to shutdown gracefully
if (_applicationInterface != null)
{
_applicationInterface.ShutdownApplication();
}
}
private static void StartWpfApp()
{
var app = new App();
_applicationInterface = app;
app.Run();
}
private static void StartBackgroundService()
{
var task = _appHost.Shutdown();
Task.WaitAll(task);
}
/// <summary>
/// Handles the UnhandledException event of the CurrentDomain control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="UnhandledExceptionEventArgs"/> instance containing the event data.</param>
static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
var exception = (Exception)e.ExceptionObject;
if (_applicationInterface != null)
{
_applicationInterface.OnUnhandledException(exception);
}
_app.OnUnhandledException(exception);
if (!Debugger.IsAttached)
{
@ -118,17 +320,50 @@ namespace MediaBrowser.ServerApplication
/// <summary>
/// Releases the mutex.
/// </summary>
internal static void ReleaseMutex()
internal static void ReleaseMutex(ILogger logger)
{
if (_singleInstanceMutex == null)
{
return;
}
logger.Debug("Releasing mutex");
_singleInstanceMutex.ReleaseMutex();
_singleInstanceMutex.Close();
_singleInstanceMutex.Dispose();
_singleInstanceMutex = null;
}
/// <summary>
/// Performs the update if needed.
/// </summary>
/// <param name="appPaths">The app paths.</param>
/// <param name="logger">The logger.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
private static bool PerformUpdateIfNeeded(ServerApplicationPaths appPaths, ILogger logger)
{
// Look for the existence of an update archive
var updateArchive = Path.Combine(appPaths.TempUpdatePath, Constants.MbServerPkgName + ".zip");
if (File.Exists(updateArchive))
{
logger.Info("An update is available from {0}", updateArchive);
// Update is there - execute update
try
{
new ApplicationUpdater().UpdateApplication(MBApplication.MBServer, appPaths, updateArchive);
// And just let the app exit so it can update
return true;
}
catch (Exception e)
{
MessageBox.Show(string.Format("Error attempting to update application.\n\n{0}\n\n{1}", e.GetType().Name, e.Message));
}
}
return false;
}
}
}

View File

@ -1,6 +1,4 @@
using MahApps.Metro.Controls;
using MediaBrowser.Common;
using MediaBrowser.Controller;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;

View File

@ -173,6 +173,7 @@
<HintPath>..\packages\SimpleInjector.2.3.5\lib\net40-client\SimpleInjector.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration.Install" />
<Reference Include="System.Data" />
<Reference Include="System.Data.SQLite, Version=1.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=x86">
<SpecificVersion>False</SpecificVersion>
@ -209,8 +210,10 @@
</Compile>
<Compile Include="EntryPoints\StartupWizard.cs" />
<Compile Include="EntryPoints\UdpServerEntryPoint.cs" />
<Compile Include="IApplicationInterface.cs" />
<Compile Include="MainStartup.cs" />
<Compile Include="BackgroundServiceInstaller.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Splash\SplashWindow.xaml.cs">
<DependentUpon>SplashWindow.xaml</DependentUpon>
</Compile>