From 6f3065d5ab4094e00bbc58ff637adbcf528491d4 Mon Sep 17 00:00:00 2001 From: Keivan Beigi Date: Thu, 13 Oct 2011 18:22:51 -0700 Subject: [PATCH] More work on WindowsService, still broken --- NzbDrone.App.Test/NzbDrone.App.Test.csproj | 2 +- NzbDrone.App.Test/ProgramTest.cs | 43 -------- NzbDrone.App.Test/RouterTest.cs | 121 +++++++++++++++++++++ NzbDrone/AppMain.cs | 36 ++++++ NzbDrone/ApplicationServer.cs | 24 +++- NzbDrone/CentralDispatch.cs | 2 - NzbDrone/NzbDrone.csproj | 11 +- NzbDrone/NzbDroneConsole.cs | 54 --------- NzbDrone/NzbDroneService.cs | 43 -------- NzbDrone/Providers/ConsoleProvider.cs | 5 + NzbDrone/Providers/EnviromentProvider.cs | 20 +++- NzbDrone/Providers/ServiceProvider.cs | 10 +- NzbDrone/Router.cs | 99 ++++++++++++----- 13 files changed, 288 insertions(+), 182 deletions(-) delete mode 100644 NzbDrone.App.Test/ProgramTest.cs create mode 100644 NzbDrone.App.Test/RouterTest.cs create mode 100644 NzbDrone/AppMain.cs delete mode 100644 NzbDrone/NzbDroneConsole.cs delete mode 100644 NzbDrone/NzbDroneService.cs diff --git a/NzbDrone.App.Test/NzbDrone.App.Test.csproj b/NzbDrone.App.Test/NzbDrone.App.Test.csproj index 32ddcc403..84d8ce7d7 100644 --- a/NzbDrone.App.Test/NzbDrone.App.Test.csproj +++ b/NzbDrone.App.Test/NzbDrone.App.Test.csproj @@ -77,7 +77,7 @@ - + diff --git a/NzbDrone.App.Test/ProgramTest.cs b/NzbDrone.App.Test/ProgramTest.cs deleted file mode 100644 index 464fad9d4..000000000 --- a/NzbDrone.App.Test/ProgramTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -using FluentAssertions; -using Moq; -using NUnit.Framework; -using NzbDrone.Model; -using NzbDrone.Providers; - -namespace NzbDrone.App.Test -{ - [TestFixture] - public class ProgramTest - { - - [TestCase(null, ApplicationMode.Console)] - [TestCase("", ApplicationMode.Console)] - [TestCase("1", ApplicationMode.Help)] - [TestCase("ii", ApplicationMode.Help)] - [TestCase("uu", ApplicationMode.Help)] - [TestCase("i", ApplicationMode.InstallService)] - [TestCase("I", ApplicationMode.InstallService)] - [TestCase("/I", ApplicationMode.InstallService)] - [TestCase("/i", ApplicationMode.InstallService)] - [TestCase("-I", ApplicationMode.InstallService)] - [TestCase("-i", ApplicationMode.InstallService)] - [TestCase("u", ApplicationMode.UninstallService)] - [TestCase("U", ApplicationMode.UninstallService)] - [TestCase("/U", ApplicationMode.UninstallService)] - [TestCase("/u", ApplicationMode.UninstallService)] - [TestCase("-U", ApplicationMode.UninstallService)] - [TestCase("-u", ApplicationMode.UninstallService)] - public void GetApplicationMode_single_arg(string arg, ApplicationMode mode) - { - NzbDroneConsole.GetApplicationMode(new[] { arg }).Should().Be(mode); - } - - [TestCase("", "", ApplicationMode.Console)] - [TestCase("", null, ApplicationMode.Console)] - [TestCase("i", "n", ApplicationMode.Help)] - public void GetApplicationMode_two_args(string a, string b, ApplicationMode mode) - { - NzbDroneConsole.GetApplicationMode(new[] { a, b }).Should().Be(mode); - } - } -} diff --git a/NzbDrone.App.Test/RouterTest.cs b/NzbDrone.App.Test/RouterTest.cs new file mode 100644 index 000000000..e4f45028b --- /dev/null +++ b/NzbDrone.App.Test/RouterTest.cs @@ -0,0 +1,121 @@ +using AutoMoq; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Model; +using NzbDrone.Providers; + +namespace NzbDrone.App.Test +{ + [TestFixture] + public class RouterTest + { + + [TestCase(null, ApplicationMode.Console)] + [TestCase("", ApplicationMode.Console)] + [TestCase("1", ApplicationMode.Help)] + [TestCase("ii", ApplicationMode.Help)] + [TestCase("uu", ApplicationMode.Help)] + [TestCase("i", ApplicationMode.InstallService)] + [TestCase("I", ApplicationMode.InstallService)] + [TestCase("/I", ApplicationMode.InstallService)] + [TestCase("/i", ApplicationMode.InstallService)] + [TestCase("-I", ApplicationMode.InstallService)] + [TestCase("-i", ApplicationMode.InstallService)] + [TestCase("u", ApplicationMode.UninstallService)] + [TestCase("U", ApplicationMode.UninstallService)] + [TestCase("/U", ApplicationMode.UninstallService)] + [TestCase("/u", ApplicationMode.UninstallService)] + [TestCase("-U", ApplicationMode.UninstallService)] + [TestCase("-u", ApplicationMode.UninstallService)] + public void GetApplicationMode_single_arg(string arg, ApplicationMode mode) + { + Router.GetApplicationMode(new[] { arg }).Should().Be(mode); + } + + [TestCase("", "", ApplicationMode.Console)] + [TestCase("", null, ApplicationMode.Console)] + [TestCase("i", "n", ApplicationMode.Help)] + public void GetApplicationMode_two_args(string a, string b, ApplicationMode mode) + { + Router.GetApplicationMode(new[] { a, b }).Should().Be(mode); + } + + [Test] + public void Route_should_call_install_service_when_application_mode_is_install() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var serviceProviderMock = mocker.GetMock(); + serviceProviderMock.Setup(c => c.Install()); + mocker.GetMock().SetupGet(c => c.IsRunningAsService).Returns(false); + + mocker.Resolve().Route(ApplicationMode.InstallService); + + serviceProviderMock.Verify(c => c.Install(), Times.Once()); + } + + [Test] + public void Route_should_call_uninstall_service_when_application_mode_is_uninstall() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var serviceProviderMock = mocker.GetMock(); + serviceProviderMock.Setup(c => c.UnInstall()); + mocker.GetMock().SetupGet(c => c.IsRunningAsService).Returns(false); + + mocker.Resolve().Route(ApplicationMode.UninstallService); + + serviceProviderMock.Verify(c => c.UnInstall(), Times.Once()); + } + + [Test] + public void Route_should_call_console_service_when_application_mode_is_console() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var consoleProvider = mocker.GetMock(); + var appServerProvider = mocker.GetMock(); + consoleProvider.Setup(c => c.WaitForClose()); + appServerProvider.Setup(c => c.Start()); + mocker.GetMock().SetupGet(c => c.IsRunningAsService).Returns(false); + + mocker.Resolve().Route(ApplicationMode.Console); + + consoleProvider.Verify(c => c.WaitForClose(), Times.Once()); + appServerProvider.Verify(c => c.Start(), Times.Once()); + } + + [TestCase(ApplicationMode.Console)] + [TestCase(ApplicationMode.InstallService)] + [TestCase(ApplicationMode.UninstallService)] + [TestCase(ApplicationMode.Help)] + public void Route_should_call_service_start_when_run_in_service_more(ApplicationMode applicationMode) + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var envMock = mocker.GetMock(); + var appServerMock = mocker.GetMock(); + + envMock.SetupGet(c => c.IsRunningAsService).Returns(true); + appServerMock.Setup(c => c.StartService()); + + mocker.Resolve().Route(applicationMode); + + appServerMock.Verify(c => c.StartService(), Times.Once()); + } + + + [Test] + public void show_error_on_install_if_service_already_exist() + { + var mocker = new AutoMoqer(MockBehavior.Strict); + var consoleMock = mocker.GetMock(); + var serviceMock = mocker.GetMock(); + mocker.GetMock().SetupGet(c => c.IsRunningAsService).Returns(false); + + consoleMock.Setup(c => c.PrintServiceAlreadyExist()); + serviceMock.Setup(c => c.ServiceExist(ServiceProvider.NzbDroneServiceName)).Returns(true); + + mocker.Resolve().Route(ApplicationMode.InstallService); + + mocker.VerifyAllMocks(); + } + } +} diff --git a/NzbDrone/AppMain.cs b/NzbDrone/AppMain.cs new file mode 100644 index 000000000..3960d8929 --- /dev/null +++ b/NzbDrone/AppMain.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Reflection; +using System.Threading; +using NLog; +using Ninject; +using NzbDrone.Model; + +namespace NzbDrone +{ + public static class AppMain + { + + + private static readonly Logger Logger = LogManager.GetLogger("Host.Main"); + + public static void Main(string[] args) + { + try + { + Console.WriteLine("Starting NzbDrone Console. Version " + Assembly.GetExecutingAssembly().GetName().Version); + + CentralDispatch.Kernel.Get().Route(args); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + Logger.Fatal(e.ToString()); + } + } + + + } +} \ No newline at end of file diff --git a/NzbDrone/ApplicationServer.cs b/NzbDrone/ApplicationServer.cs index 41665b52d..f3f1c6bda 100644 --- a/NzbDrone/ApplicationServer.cs +++ b/NzbDrone/ApplicationServer.cs @@ -1,5 +1,6 @@ using System; using System.Net; +using System.ServiceProcess; using System.Threading; using NLog; using Ninject; @@ -7,7 +8,7 @@ using NzbDrone.Providers; namespace NzbDrone { - public class ApplicationServer + public class ApplicationServer : ServiceBase { private static readonly Logger Logger = LogManager.GetLogger("Host.App"); @@ -18,6 +19,13 @@ namespace NzbDrone private readonly ProcessProvider _processProvider; private readonly WebClient _webClient; + public void IsRunningAsService() + { + Logger.Warn(base.Container); + Logger.Warn(base.ServiceName); + + } + [Inject] public ApplicationServer(ConfigProvider configProvider, WebClient webClient, IISProvider iisProvider, DebuggerProvider debuggerProvider, EnviromentProvider enviromentProvider, @@ -33,6 +41,13 @@ namespace NzbDrone public ApplicationServer() { + + } + + public virtual void StartService() + { + Start(); + Run(this); } public virtual void Start() @@ -67,7 +82,12 @@ namespace NzbDrone } } - public virtual void Stop() + protected override void OnStop() + { + StopServer(); + } + + public void StopServer() { Logger.Info("Attempting to stop application."); _iisProvider.StopServer(); diff --git a/NzbDrone/CentralDispatch.cs b/NzbDrone/CentralDispatch.cs index 10b96c2c2..21513e626 100644 --- a/NzbDrone/CentralDispatch.cs +++ b/NzbDrone/CentralDispatch.cs @@ -22,8 +22,6 @@ namespace NzbDrone InitilizeApp(); } - public static ApplicationMode ApplicationMode { get; set; } - public static StandardKernel Kernel { get diff --git a/NzbDrone/NzbDrone.csproj b/NzbDrone/NzbDrone.csproj index 62dc61b76..e9dfb5e0e 100644 --- a/NzbDrone/NzbDrone.csproj +++ b/NzbDrone/NzbDrone.csproj @@ -54,7 +54,7 @@ NzbDrone.ico - NzbDrone.NzbDroneConsole + NzbDrone.AppMain @@ -88,7 +88,9 @@ - + + Component + @@ -96,13 +98,10 @@ - - Component - - + diff --git a/NzbDrone/NzbDroneConsole.cs b/NzbDrone/NzbDroneConsole.cs deleted file mode 100644 index f067a09b0..000000000 --- a/NzbDrone/NzbDroneConsole.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using System.Threading; -using NLog; -using Ninject; -using NzbDrone.Model; - -namespace NzbDrone -{ - public static class NzbDroneConsole - { - - - private static readonly Logger Logger = LogManager.GetLogger("Host.Main"); - - public static void Main(string[] args) - { - try - { - //while (!Debugger.IsAttached) Thread.Sleep(100); - - Console.WriteLine("Starting NzbDrone Console. Version " + Assembly.GetExecutingAssembly().GetName().Version); - - CentralDispatch.ApplicationMode = GetApplicationMode(args); - - CentralDispatch.Kernel.Get().Route(); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - Logger.Fatal(e.ToString()); - } - } - - public static ApplicationMode GetApplicationMode(IEnumerable args) - { - if (args == null) return ApplicationMode.Console; - - var cleanArgs = args.Where(c => c != null && !String.IsNullOrWhiteSpace(c)).ToList(); - if (cleanArgs.Count == 0) return ApplicationMode.Console; - if (cleanArgs.Count != 1) return ApplicationMode.Help; - - var arg = cleanArgs.First().Trim('/', '\\', '-').ToLower(); - - if (arg == "i") return ApplicationMode.InstallService; - if (arg == "u") return ApplicationMode.UninstallService; - - return ApplicationMode.Help; - } - } -} \ No newline at end of file diff --git a/NzbDrone/NzbDroneService.cs b/NzbDrone/NzbDroneService.cs deleted file mode 100644 index c7394bd53..000000000 --- a/NzbDrone/NzbDroneService.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Diagnostics; -using System.ServiceProcess; -using System.Threading; -using NLog; -using Ninject; - -namespace NzbDrone -{ - public class NzbDroneService : ServiceBase - { - - private static readonly Logger Logger = LogManager.GetLogger("Host.CentralDispatch"); - - protected override void OnStart(string[] args) - { - try - { - while (!Debugger.IsAttached) Thread.Sleep(100); - Debugger.Break(); - CentralDispatch.Kernel.Get().Start(); - } - catch (Exception e) - { - - Logger.Fatal("Failed to start Windows Service", e); - } - - } - - protected override void OnStop() - { - try - { - CentralDispatch.Kernel.Get().Stop(); - } - catch (Exception e) - { - Logger.Fatal("Failed to stop Windows Service", e); - } - } - } -} \ No newline at end of file diff --git a/NzbDrone/Providers/ConsoleProvider.cs b/NzbDrone/Providers/ConsoleProvider.cs index 915f084a3..c4374363b 100644 --- a/NzbDrone/Providers/ConsoleProvider.cs +++ b/NzbDrone/Providers/ConsoleProvider.cs @@ -20,5 +20,10 @@ namespace NzbDrone.Providers Logger.Info("Printing Help"); Console.WriteLine("Help"); } + + public virtual void PrintServiceAlreadyExist() + { + Console.WriteLine("A service with the same name ({0}) already exists. Aborting installation", ServiceProvider.NzbDroneServiceName); + } } } \ No newline at end of file diff --git a/NzbDrone/Providers/EnviromentProvider.cs b/NzbDrone/Providers/EnviromentProvider.cs index 8e046029b..b12fff7b3 100644 --- a/NzbDrone/Providers/EnviromentProvider.cs +++ b/NzbDrone/Providers/EnviromentProvider.cs @@ -16,6 +16,22 @@ namespace NzbDrone.Providers get { return Environment.UserInteractive; } } + public virtual bool IsRunningAsService + { + get + { + try + { + Console.Write(""); + return false; + } + catch (Exception) + { + return true; + } + } + } + public virtual string ApplicationPath { get @@ -29,13 +45,13 @@ namespace NzbDrone.Providers } dir = new FileInfo(Assembly.GetExecutingAssembly().Location).Directory; - + while (dir.GetDirectories("iisexpress").Length == 0) { if (dir.Parent == null) throw new ApplicationException("Can't fine IISExpress folder."); dir = dir.Parent; } - + return dir.FullName; } } diff --git a/NzbDrone/Providers/ServiceProvider.cs b/NzbDrone/Providers/ServiceProvider.cs index 240cfa797..99c00140d 100644 --- a/NzbDrone/Providers/ServiceProvider.cs +++ b/NzbDrone/Providers/ServiceProvider.cs @@ -15,7 +15,9 @@ namespace NzbDrone.Providers private static readonly Logger Logger = LogManager.GetLogger("Host.ServiceManager"); - public bool ServiceExist(string name) + + + public virtual bool ServiceExist(string name) { return ServiceController.GetServices().Any( @@ -36,15 +38,15 @@ namespace NzbDrone.Providers var serviceInstaller = new ServiceInstaller(); - String[] cmdline = {@"/assemblypath=" + Assembly.GetExecutingAssembly().Location}; + String[] cmdline = { @"/assemblypath=" + Assembly.GetExecutingAssembly().Location }; var context = new InstallContext("service_install.log", cmdline); serviceInstaller.Context = context; serviceInstaller.DisplayName = NzbDroneServiceName; serviceInstaller.ServiceName = NzbDroneServiceName; serviceInstaller.StartType = ServiceStartMode.Automatic; - - + + serviceInstaller.Parent = installer; serviceInstaller.Install(new ListDictionary()); diff --git a/NzbDrone/Router.cs b/NzbDrone/Router.cs index afda37861..7eba497b0 100644 --- a/NzbDrone/Router.cs +++ b/NzbDrone/Router.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Text; +using System.Threading; using NLog; using NzbDrone.Model; using NzbDrone.Providers; @@ -15,42 +17,89 @@ namespace NzbDrone private readonly ApplicationServer _applicationServer; private readonly ServiceProvider _serviceProvider; private readonly ConsoleProvider _consoleProvider; + private readonly EnviromentProvider _enviromentProvider; - public Router(ApplicationServer applicationServer, ServiceProvider serviceProvider, ConsoleProvider consoleProvider) + public Router(ApplicationServer applicationServer, ServiceProvider serviceProvider, ConsoleProvider consoleProvider, EnviromentProvider enviromentProvider) { _applicationServer = applicationServer; _serviceProvider = serviceProvider; _consoleProvider = consoleProvider; + _enviromentProvider = enviromentProvider; } - public void Route() + public void Route(IEnumerable args) { - Logger.Info("Application mode: {0}", CentralDispatch.ApplicationMode); - switch (CentralDispatch.ApplicationMode) + Route(GetApplicationMode(args)); + } + + public void Route(ApplicationMode applicationMode) + { + Logger.Info("Application mode: {0}", applicationMode); + + _applicationServer.IsRunningAsService(); + + while (!Debugger.IsAttached) { + Thread.Sleep(1000); + } + + + if (_enviromentProvider.IsRunningAsService) + { + _applicationServer.StartService(); - case ApplicationMode.Console: - { - _applicationServer.Start(); - _consoleProvider.WaitForClose(); - break; - } - case ApplicationMode.InstallService: - { - _serviceProvider.Install(); - break; - } - case ApplicationMode.UninstallService: - { - _serviceProvider.UnInstall(); - break; - } - default: - { - _consoleProvider.PrintHelp(); - break; - } } + else + { + switch (applicationMode) + { + + case ApplicationMode.Console: + { + _applicationServer.Start(); + _consoleProvider.WaitForClose(); + break; + } + case ApplicationMode.InstallService: + { + if (_serviceProvider.ServiceExist(ServiceProvider.NzbDroneServiceName)) + { + _consoleProvider.PrintServiceAlreadyExist(); + } + else + { + _serviceProvider.Install(); + } + break; + } + case ApplicationMode.UninstallService: + { + _serviceProvider.UnInstall(); + break; + } + default: + { + _consoleProvider.PrintHelp(); + break; + } + } + } + } + + public static ApplicationMode GetApplicationMode(IEnumerable args) + { + if (args == null) return ApplicationMode.Console; + + var cleanArgs = args.Where(c => c != null && !String.IsNullOrWhiteSpace(c)).ToList(); + if (cleanArgs.Count == 0) return ApplicationMode.Console; + if (cleanArgs.Count != 1) return ApplicationMode.Help; + + var arg = cleanArgs.First().Trim('/', '\\', '-').ToLower(); + + if (arg == "i") return ApplicationMode.InstallService; + if (arg == "u") return ApplicationMode.UninstallService; + + return ApplicationMode.Help; } } }