Lidarr/src/NzbDrone.Common/Processes/ProcessProvider.cs

318 lines
9.8 KiB
C#
Raw Normal View History

using System;
2013-08-14 04:40:34 +00:00
using System.Collections.Generic;
using System.ComponentModel;
2011-10-07 03:37:41 +00:00
using System.Diagnostics;
using System.IO;
2011-10-07 03:37:41 +00:00
using System.Linq;
using NLog;
2013-08-14 04:25:38 +00:00
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Common.Model;
2011-10-07 03:37:41 +00:00
namespace NzbDrone.Common.Processes
2011-10-07 03:37:41 +00:00
{
2013-05-10 23:53:50 +00:00
public interface IProcessProvider
{
int GetCurrentProcessId();
2013-05-10 23:53:50 +00:00
ProcessInfo GetCurrentProcess();
ProcessInfo GetProcessById(int id);
2013-11-26 02:46:12 +00:00
List<ProcessInfo> FindProcessByName(string name);
2013-08-14 05:20:24 +00:00
void OpenDefaultBrowser(string url);
2013-05-10 23:53:50 +00:00
void WaitForExit(Process process);
void SetPriority(int processId, ProcessPriorityClass priority);
void KillAll(string processName);
void Kill(int processId);
Boolean Exists(int processId);
Boolean Exists(string processName);
ProcessPriorityClass GetCurrentProcessPriority();
2013-08-14 05:20:24 +00:00
Process Start(string path, string args = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null);
Process SpawnNewProcess(string path, string args = null);
ProcessOutput StartAndCapture(string path, string args = null);
2013-05-10 23:53:50 +00:00
}
public class ProcessProvider : IProcessProvider
2011-10-07 03:37:41 +00:00
{
2014-12-17 07:12:26 +00:00
private readonly Logger _logger;
2011-10-07 03:37:41 +00:00
2013-08-14 05:20:24 +00:00
public const string NZB_DRONE_PROCESS_NAME = "NzbDrone";
public const string NZB_DRONE_CONSOLE_PROCESS_NAME = "NzbDrone.Console";
2011-10-07 03:37:41 +00:00
2014-12-17 07:12:26 +00:00
public ProcessProvider(Logger logger)
{
_logger = logger;
}
public int GetCurrentProcessId()
{
return Process.GetCurrentProcess().Id;
}
public ProcessInfo GetCurrentProcess()
2011-10-07 03:37:41 +00:00
{
2011-10-07 06:36:04 +00:00
return ConvertToProcessInfo(Process.GetCurrentProcess());
}
2011-10-07 03:37:41 +00:00
public bool Exists(int processId)
{
return GetProcessById(processId) != null;
}
public Boolean Exists(string processName)
{
2013-08-14 04:40:34 +00:00
return GetProcessesByName(processName).Any();
}
public ProcessPriorityClass GetCurrentProcessPriority()
{
return Process.GetCurrentProcess().PriorityClass;
}
public ProcessInfo GetProcessById(int id)
2011-10-07 06:36:04 +00:00
{
2014-12-17 07:12:26 +00:00
_logger.Debug("Finding process with Id:{0}", id);
2013-05-07 05:54:21 +00:00
var processInfo = ConvertToProcessInfo(Process.GetProcesses().FirstOrDefault(p => p.Id == id));
if (processInfo == null)
{
2014-12-17 07:12:26 +00:00
_logger.Warn("Unable to find process with ID {0}", id);
}
else
{
2014-12-17 07:12:26 +00:00
_logger.Debug("Found process {0}", processInfo.ToString());
}
return processInfo;
2011-10-07 06:36:04 +00:00
}
2011-10-07 03:37:41 +00:00
2013-11-26 02:46:12 +00:00
public List<ProcessInfo> FindProcessByName(string name)
{
return GetProcessesByName(name).Select(ConvertToProcessInfo).Where(c => c != null).ToList();
2013-11-26 02:46:12 +00:00
}
2013-08-14 05:20:24 +00:00
public void OpenDefaultBrowser(string url)
2011-10-07 03:37:41 +00:00
{
2014-12-17 07:12:26 +00:00
_logger.Info("Opening URL [{0}]", url);
2013-08-14 05:20:24 +00:00
var process = new Process
{
StartInfo = new ProcessStartInfo(url)
{
UseShellExecute = true
}
};
process.Start();
2011-10-07 03:37:41 +00:00
}
2013-08-14 05:20:24 +00:00
public Process Start(string path, string args = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null)
{
2014-12-07 20:54:07 +00:00
if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
2013-08-14 04:25:38 +00:00
{
2015-02-06 01:15:45 +00:00
args = GetMonoArgs(path, args);
2013-08-14 04:25:38 +00:00
path = "mono";
}
var logger = LogManager.GetLogger(new FileInfo(path).Name);
var startInfo = new ProcessStartInfo(path, args)
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
2013-08-14 03:22:28 +00:00
RedirectStandardInput = true
};
logger.Debug("Starting {0} {1}", path, args);
var process = new Process
{
StartInfo = startInfo
};
process.OutputDataReceived += (sender, eventArgs) =>
{
if (string.IsNullOrWhiteSpace(eventArgs.Data)) return;
logger.Debug(eventArgs.Data);
if (onOutputDataReceived != null)
{
onOutputDataReceived(eventArgs.Data);
}
};
process.ErrorDataReceived += (sender, eventArgs) =>
{
if (string.IsNullOrWhiteSpace(eventArgs.Data)) return;
logger.Error(eventArgs.Data);
if (onErrorDataReceived != null)
{
onErrorDataReceived(eventArgs.Data);
}
};
2013-08-14 03:22:28 +00:00
process.Start();
process.BeginErrorReadLine();
process.BeginOutputReadLine();
return process;
}
public Process SpawnNewProcess(string path, string args = null)
{
2014-12-07 20:54:07 +00:00
if (OsInfo.IsMonoRuntime && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
{
2015-02-06 01:15:45 +00:00
args = GetMonoArgs(path, args);
path = "mono";
}
2014-12-17 07:12:26 +00:00
_logger.Debug("Starting {0} {1}", path, args);
var startInfo = new ProcessStartInfo(path, args);
var process = new Process
{
StartInfo = startInfo
};
process.Start();
return process;
}
public ProcessOutput StartAndCapture(string path, string args = null)
{
var output = new ProcessOutput();
Start(path, args, s => output.Standard.Add(s), error => output.Error.Add(error)).WaitForExit();
return output;
}
public void WaitForExit(Process process)
{
2014-12-17 07:12:26 +00:00
_logger.Debug("Waiting for process {0} to exit.", process.ProcessName);
process.WaitForExit();
}
public void SetPriority(int processId, ProcessPriorityClass priority)
2011-10-07 06:36:04 +00:00
{
var process = Process.GetProcessById(processId);
2014-12-17 07:12:26 +00:00
_logger.Info("Updating [{0}] process priority from {1} to {2}",
2011-10-07 06:36:04 +00:00
process.ProcessName,
process.PriorityClass,
priority);
process.PriorityClass = priority;
}
public void Kill(int processId)
{
var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId);
if (process == null)
{
2014-12-17 07:12:26 +00:00
_logger.Warn("Cannot find process with id: {0}", processId);
return;
}
process.Refresh();
2015-01-15 00:58:21 +00:00
if (process.Id != Process.GetCurrentProcess().Id && process.HasExited)
{
2014-12-17 07:12:26 +00:00
_logger.Debug("Process has already exited");
return;
}
2014-12-17 07:12:26 +00:00
_logger.Info("[{0}]: Killing process", process.Id);
process.Kill();
2014-12-17 07:12:26 +00:00
_logger.Info("[{0}]: Waiting for exit", process.Id);
process.WaitForExit();
2014-12-17 07:12:26 +00:00
_logger.Info("[{0}]: Process terminated successfully", process.Id);
}
2013-07-27 00:56:49 +00:00
public void KillAll(string processName)
{
var processes = GetProcessesByName(processName);
2013-07-27 00:56:49 +00:00
2014-12-17 07:12:26 +00:00
_logger.Debug("Found {0} processes to kill", processes.Count);
foreach (var processInfo in processes)
2013-07-27 00:56:49 +00:00
{
2014-12-17 07:12:26 +00:00
_logger.Debug("Killing process: {0} [{1}]", processInfo.Id, processInfo.ProcessName);
2013-07-27 00:56:49 +00:00
Kill(processInfo.Id);
}
}
2014-12-17 07:12:26 +00:00
private ProcessInfo ConvertToProcessInfo(Process process)
2011-10-07 06:36:04 +00:00
{
if (process == null) return null;
process.Refresh();
2013-11-26 02:46:12 +00:00
ProcessInfo processInfo = null;
try
{
2013-11-26 02:46:12 +00:00
if (process.Id <= 0) return null;
processInfo = new ProcessInfo();
processInfo.Id = process.Id;
processInfo.Name = process.ProcessName;
processInfo.StartPath = GetExeFileName(process);
2015-01-15 00:58:21 +00:00
if (process.Id != Process.GetCurrentProcess().Id && process.HasExited)
{
2013-11-26 02:46:12 +00:00
processInfo = null;
}
}
2013-11-26 02:46:12 +00:00
catch (Win32Exception e)
{
2014-12-17 07:12:26 +00:00
_logger.WarnException("Couldn't get process info for " + process.ProcessName, e);
}
2013-11-26 02:46:12 +00:00
return processInfo;
2011-10-07 03:37:41 +00:00
}
private static string GetExeFileName(Process process)
{
if (process.MainModule.FileName != "mono.exe")
{
return process.MainModule.FileName;
}
return process.Modules.Cast<ProcessModule>().FirstOrDefault(module => module.ModuleName.ToLower().EndsWith(".exe")).FileName;
}
2014-12-17 07:12:26 +00:00
private List<Process> GetProcessesByName(string name)
{
//TODO: move this to an OS specific class
2013-08-14 03:22:28 +00:00
var monoProcesses = Process.GetProcessesByName("mono")
.Union(Process.GetProcessesByName("mono-sgen"))
.Where(process =>
process.Modules.Cast<ProcessModule>()
.Any(module =>
module.ModuleName.ToLower() == name.ToLower() + ".exe"));
var processes = Process.GetProcessesByName(name)
.Union(monoProcesses).ToList();
2014-12-17 07:12:26 +00:00
_logger.Debug("Found {0} processes with the name: {1}", processes.Count, name);
return processes;
}
2015-02-06 01:15:45 +00:00
private string GetMonoArgs(string path, string args)
{
return String.Format("--debug {0} {1}", path, args);
}
2011-10-07 03:37:41 +00:00
}
}