More NzbDrone.exe refactoring

This commit is contained in:
kay.one 2011-10-06 20:37:41 -07:00
parent f3ca3e97f9
commit 69ba365cd3
11 changed files with 324 additions and 176 deletions

View File

@ -87,4 +87,9 @@
<Abbreviation Text="IIS" />
</Naming2>
</CodeStyleSettings>
<Daemon.SolutionSettings>
<SkipFilesAndFolders>
<Item>43BD3BBD-1531-4D8F-9C08-E1CD544AB2CD/d:Content</Item>
</SkipFilesAndFolders>
</Daemon.SolutionSettings>
</Configuration>

129
NzbDrone/Application.cs Normal file
View File

@ -0,0 +1,129 @@
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Timers;
using NLog;
using NzbDrone.Providers;
namespace NzbDrone
{
internal class Application
{
private static readonly Logger Logger = LogManager.GetLogger("Application");
private readonly ConfigProvider _configProvider;
private readonly WebClient _webClient;
private readonly IISProvider _iisProvider;
private readonly ConsoleProvider _consoleProvider;
private readonly DebuggerProvider _debuggerProvider;
private readonly EnviromentProvider _enviromentProvider;
private readonly ProcessProvider _processProvider;
public Application(ConfigProvider configProvider, WebClient webClient, IISProvider iisProvider, ConsoleProvider consoleProvider,
DebuggerProvider debuggerProvider, EnviromentProvider enviromentProvider, ProcessProvider processProvider)
{
_configProvider = configProvider;
_webClient = webClient;
_iisProvider = iisProvider;
_consoleProvider = consoleProvider;
_debuggerProvider = debuggerProvider;
_enviromentProvider = enviromentProvider;
_processProvider = processProvider;
_configProvider.ConfigureNlog();
_configProvider.CreateDefaultConfigFile();
Logger.Info("Starting NZBDrone. Start-up Path:'{0}'", _configProvider.ApplicationRoot);
Thread.CurrentThread.Name = "Host";
AppDomain.CurrentDomain.UnhandledException += ((s, e) => AppDomainException(e));
AppDomain.CurrentDomain.ProcessExit += ProgramExited;
AppDomain.CurrentDomain.DomainUnload += ProgramExited;
}
internal void Start()
{
_iisProvider.StopServer();
_iisProvider.StartServer();
_debuggerProvider.Attach();
var prioCheckTimer = new System.Timers.Timer(5000);
prioCheckTimer.Elapsed += EnsurePriority;
prioCheckTimer.Enabled = true;
if (_enviromentProvider.IsUserInteractive && _configProvider.LaunchBrowser)
{
try
{
Logger.Info("Starting default browser. {0}", _iisProvider.AppUrl);
_processProvider.Start(_iisProvider.AppUrl);
}
catch (Exception e)
{
Logger.ErrorException("Failed to open URL in default browser.", e);
}
_consoleProvider.WaitForClose();
return;
}
try
{
_webClient.DownloadString(_iisProvider.AppUrl);
}
catch (Exception e)
{
Logger.ErrorException("Failed to load home page.", e);
}
}
internal void Stop()
{
}
private void AppDomainException(object excepion)
{
Console.WriteLine("EPIC FAIL: {0}", excepion);
Logger.Fatal("EPIC FAIL: {0}", excepion);
#if RELEASE
new Client
{
ApiKey = "43BBF60A-EB2A-4C1C-B09E-422ADF637265",
ApplicationName = "NZBDrone",
CurrentException = excepion as Exception
}.Submit();
#endif
}
internal void EnsurePriority(object sender, ElapsedEventArgs e)
{
var currentProcessId = _processProvider.GetCurrentProcessId();
if (_processProvider.GetProcessPriority(currentProcessId) != ProcessPriorityClass.Normal)
{
_processProvider.SetPriority(_processProvider.GetCurrentProcessId(), ProcessPriorityClass.Normal);
}
var iisProcessPriority = _processProvider.GetProcessPriority(_iisProvider.IISProcessId);
if (iisProcessPriority != ProcessPriorityClass.Normal && iisProcessPriority != ProcessPriorityClass.AboveNormal)
{
_processProvider.SetPriority(_iisProvider.IISProcessId, ProcessPriorityClass.Normal);
}
}
private void ProgramExited(object sender, EventArgs e)
{
_iisProvider.StopServer();
}
}
}

View File

@ -67,6 +67,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\Exceptioneer.WindowsFormsClient.dll</HintPath>
</Reference>
<Reference Include="Ninject">
<HintPath>..\packages\Ninject.2.2.1.4\lib\net40-Full\Ninject.dll</HintPath>
</Reference>
<Reference Include="NLog, Version=2.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Libraries\NLog.dll</HintPath>
@ -82,19 +85,25 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Application.cs" />
<Compile Include="Providers\ConsoleProvider.cs" />
<Compile Include="Providers\DebuggerProvider.cs" />
<Compile Include="Providers\EnviromentProvider.cs" />
<Compile Include="NzbDroneService.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ProcessAttacher.cs" />
<Compile Include="Providers\ConfigProvider.cs" />
<Compile Include="Providers\IISControllerProvider.cs" />
<Compile Include="Providers\IISProvider.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Providers\ProcessProvider.cs" />
<Compile Include="Providers\ServiceProvider.cs" />
<Compile Include="Providers\WebClientProvider.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Content Include="NzbDrone.ico" />

View File

@ -1,174 +1,30 @@
using System;
using System.Diagnostics;
using System.Net;
using System.Threading;
using System.Timers;
using Exceptioneer.WindowsFormsClient;
using NLog;
using NzbDrone.Providers;
using Ninject;
namespace NzbDrone
{
internal static class Program
internal static class Program
{
private static readonly Logger Logger = LogManager.GetLogger("Application");
public static readonly StandardKernel Kernel = new StandardKernel();
static readonly ConfigProvider ConfigProvider = new ConfigProvider();
static readonly IISControllerProvider IISController = new IISControllerProvider(ConfigProvider);
private static readonly Logger Logger = LogManager.GetLogger("Main");
private static void Main()
{
try
{
ConfigProvider.ConfigureNlog();
ConfigProvider.CreateDefaultConfigFile();
Logger.Info("Starting NZBDrone. Start-up Path:'{0}'", ConfigProvider.ApplicationRoot);
Thread.CurrentThread.Name = "Host";
Process currentProcess = Process.GetCurrentProcess();
var prioCheckTimer = new System.Timers.Timer(5000);
prioCheckTimer.Elapsed += prioCheckTimer_Elapsed;
prioCheckTimer.Enabled = true;
currentProcess.EnableRaisingEvents = true;
currentProcess.Exited += ProgramExited;
AppDomain.CurrentDomain.UnhandledException += ((s, e) => AppDomainException(e));
AppDomain.CurrentDomain.ProcessExit += ProgramExited;
AppDomain.CurrentDomain.DomainUnload += ProgramExited;
IISController.StopServer();
IISController.StartServer();
#if DEBUG
Attach();
#endif
if (!Environment.UserInteractive || !ConfigProvider.LaunchBrowser)
{
try
{
new WebClient().DownloadString(IISController.AppUrl);
}
catch (Exception e)
{
Logger.ErrorException("Failed to load home page.", e);
}
}
else
{
try
{
Logger.Info("Starting default browser. {0}", IISController.AppUrl);
Process.Start(IISController.AppUrl);
}
catch (Exception e)
{
Logger.ErrorException("Failed to open URL in default browser.", e);
}
while (true)
{
Console.ReadLine();
}
}
Console.WriteLine("Starting Console.");
Kernel.Get<Application>().Start();
}
catch (Exception e)
{
AppDomainException(e);
Console.WriteLine(e.ToString());
Logger.Fatal(e.ToString());
}
Console.WriteLine("Press enter to exit.");
Console.ReadLine();
}
private static void prioCheckTimer_Elapsed(object sender, ElapsedEventArgs e)
{
Process currentProcess = Process.GetCurrentProcess();
if (currentProcess.PriorityClass != ProcessPriorityClass.Normal)
{
SetPriority(currentProcess);
}
if (IISControllerProvider.IISProcess != null)
{
IISControllerProvider.IISProcess.Refresh();
if (IISControllerProvider.IISProcess.PriorityClass != ProcessPriorityClass.Normal && IISControllerProvider.IISProcess.PriorityClass != ProcessPriorityClass.AboveNormal)
{
SetPriority(IISControllerProvider.IISProcess);
}
}
}
private static void SetPriority(Process process)
{
Logger.Info("Updating [{0}] process priority from {1} to {2}",
process.ProcessName,
IISControllerProvider.IISProcess.PriorityClass,
ProcessPriorityClass.Normal);
process.PriorityClass = ProcessPriorityClass.Normal;
}
#if DEBUG
private static void Attach()
{
if (Debugger.IsAttached)
{
Logger.Info("Trying to attach to debugger");
var count = 0;
while (true)
{
try
{
ProcessAttacher.Attach();
Logger.Info("Debugger Attached");
return;
}
catch (Exception e)
{
count++;
if (count > 20)
{
Logger.WarnException("Unable to attach to debugger", e);
return;
}
Thread.Sleep(100);
}
}
}
}
#endif
private static void AppDomainException(object excepion)
{
Console.WriteLine("EPIC FAIL: {0}", excepion);
Logger.Fatal("EPIC FAIL: {0}", excepion);
#if RELEASE
new Client
{
ApiKey = "43BBF60A-EB2A-4C1C-B09E-422ADF637265",
ApplicationName = "NZBDrone",
CurrentException = excepion as Exception
}.Submit();
#endif
IISController.StopServer();
}
private static void ProgramExited(object sender, EventArgs e)
{
IISController.StopServer();
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NzbDrone.Providers
{
public class ConsoleProvider
{
public virtual void WaitForClose()
{
while (true)
{
Console.ReadLine();
}
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using NLog;
namespace NzbDrone.Providers
{
internal class DebuggerProvider
{
private static readonly Logger Logger = LogManager.GetLogger("DebuggerProvider");
internal virtual void Attach()
{
#if DEBUG
if (Debugger.IsAttached)
{
Logger.Info("Trying to attach to debugger");
var count = 0;
while (true)
{
try
{
ProcessAttacher.Attach();
Logger.Info("Debugger Attached");
return;
}
catch (Exception e)
{
count++;
if (count > 20)
{
Logger.WarnException("Unable to attach to debugger", e);
return;
}
Thread.Sleep(100);
}
}
}
#endif
}
}
}

View File

@ -11,11 +11,11 @@ using NLog;
namespace NzbDrone.Providers
{
internal class IISControllerProvider
internal class IISProvider
{
private readonly ConfigProvider _configProvider;
private static readonly Logger IISLogger = LogManager.GetLogger("IISExpress");
private static readonly Logger Logger = LogManager.GetLogger("IISControllerProvider");
private static readonly Logger Logger = LogManager.GetLogger("IISProvider");
private readonly string IISExe;
private readonly string IISConfigPath;
@ -23,10 +23,10 @@ namespace NzbDrone.Providers
private static Timer _pingTimer;
private static int _pingFailCounter;
public static Process IISProcess { get; private set; }
private static Process _iisProcess;
public IISControllerProvider(ConfigProvider configProvider)
public IISProvider(ConfigProvider configProvider)
{
_configProvider = configProvider;
IISExe = Path.Combine(_configProvider.IISFolder, @"iisexpress.exe");
@ -38,27 +38,40 @@ namespace NzbDrone.Providers
get { return string.Format("http://localhost:{0}/", _configProvider.Port); }
}
internal int IISProcessId
{
get
{
if (_iisProcess == null)
{
throw new InvalidOperationException("IIS Process isn't running yet.");
}
return _iisProcess.Id;
}
}
internal Process StartServer()
{
Logger.Info("Preparing IISExpress Server...");
IISProcess = new Process();
_iisProcess = new Process();
IISProcess.StartInfo.FileName = IISExe;
IISProcess.StartInfo.Arguments = String.Format("/config:\"{0}\" /trace:i", IISConfigPath);//"/config:"""" /trace:i";
IISProcess.StartInfo.WorkingDirectory = _configProvider.ApplicationRoot;
_iisProcess.StartInfo.FileName = IISExe;
_iisProcess.StartInfo.Arguments = String.Format("/config:\"{0}\" /trace:i", IISConfigPath);//"/config:"""" /trace:i";
_iisProcess.StartInfo.WorkingDirectory = _configProvider.ApplicationRoot;
IISProcess.StartInfo.UseShellExecute = false;
IISProcess.StartInfo.RedirectStandardOutput = true;
IISProcess.StartInfo.RedirectStandardError = true;
IISProcess.StartInfo.CreateNoWindow = true;
_iisProcess.StartInfo.UseShellExecute = false;
_iisProcess.StartInfo.RedirectStandardOutput = true;
_iisProcess.StartInfo.RedirectStandardError = true;
_iisProcess.StartInfo.CreateNoWindow = true;
IISProcess.OutputDataReceived += (OnOutputDataReceived);
IISProcess.ErrorDataReceived += (OnErrorDataReceived);
_iisProcess.OutputDataReceived += (OnOutputDataReceived);
_iisProcess.ErrorDataReceived += (OnErrorDataReceived);
//Set Variables for the config file.
IISProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PATH", _configProvider.ApplicationRoot);
IISProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PID", Process.GetCurrentProcess().Id.ToString());
_iisProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PATH", _configProvider.ApplicationRoot);
_iisProcess.StartInfo.EnvironmentVariables.Add("NZBDRONE_PID", Process.GetCurrentProcess().Id.ToString());
try
{
@ -70,22 +83,22 @@ namespace NzbDrone.Providers
}
Logger.Info("Starting process. [{0}]", IISProcess.StartInfo.FileName);
Logger.Info("Starting process. [{0}]", _iisProcess.StartInfo.FileName);
IISProcess.Start();
IISProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
_iisProcess.Start();
_iisProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
IISProcess.BeginErrorReadLine();
IISProcess.BeginOutputReadLine();
_iisProcess.BeginErrorReadLine();
_iisProcess.BeginOutputReadLine();
//Start Ping
_pingTimer = new Timer(300000) { AutoReset = true };
_pingTimer.Elapsed += (PingServer);
_pingTimer.Start();
return IISProcess;
return _iisProcess;
}
private static void OnErrorDataReceived(object sender, DataReceivedEventArgs e)
@ -98,7 +111,7 @@ namespace NzbDrone.Providers
internal void StopServer()
{
KillProcess(IISProcess);
KillProcess(_iisProcess);
Logger.Info("Finding orphaned IIS Processes.");
foreach (var process in Process.GetProcessesByName("IISExpress"))

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using NLog;
namespace NzbDrone.Providers
{
public class ProcessProvider
{
private static readonly Logger Logger = LogManager.GetLogger("ProcessProvider");
public virtual void SetPriority(int processId, ProcessPriorityClass priority)
{
var process = Process.GetProcessById(processId);
Logger.Info("Updating [{0}] process priority from {1} to {2}",
process.ProcessName,
process.PriorityClass,
priority);
process.PriorityClass = priority;
}
public virtual ProcessPriorityClass GetProcessPriority(int processId)
{
return Process.GetProcessById(processId).PriorityClass;
}
public virtual int GetCurrentProcessId()
{
return Process.GetCurrentProcess().Id;
}
public virtual Process Start(string path)
{
return Process.Start(path);
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
namespace NzbDrone.Providers
{
internal class WebClientProvider
{
public virtual string DownloadString(string url)
{
return new WebClient().DownloadString(url);
}
}
}

4
NzbDrone/packages.config Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Ninject" version="2.2.1.4" />
</packages>

View File

@ -4,4 +4,5 @@
<repository path="..\NzbDrone.Core.Test\packages.config" />
<repository path="..\NzbDrone.Core\packages.config" />
<repository path="..\NzbDrone.App.Test\packages.config" />
<repository path="..\NzbDrone\packages.config" />
</repositories>