2013-08-07 05:32:22 +00:00
|
|
|
|
using System;
|
2013-08-14 04:40:34 +00:00
|
|
|
|
using System.Collections.Generic;
|
2013-08-07 05:32:22 +00:00
|
|
|
|
using System.ComponentModel;
|
2011-10-07 03:37:41 +00:00
|
|
|
|
using System.Diagnostics;
|
2013-08-07 05:32:22 +00:00
|
|
|
|
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;
|
2011-10-23 05:26:43 +00:00
|
|
|
|
using NzbDrone.Common.Model;
|
2011-10-07 03:37:41 +00:00
|
|
|
|
|
2011-10-23 05:26:43 +00:00
|
|
|
|
namespace NzbDrone.Common
|
2011-10-07 03:37:41 +00:00
|
|
|
|
{
|
2013-05-10 23:53:50 +00:00
|
|
|
|
public interface IProcessProvider
|
|
|
|
|
{
|
|
|
|
|
ProcessInfo GetCurrentProcess();
|
|
|
|
|
ProcessInfo GetProcessById(int id);
|
2013-07-05 18:51:38 +00:00
|
|
|
|
Process Start(string path);
|
2013-05-10 23:53:50 +00:00
|
|
|
|
Process Start(ProcessStartInfo startInfo);
|
|
|
|
|
void WaitForExit(Process process);
|
|
|
|
|
void SetPriority(int processId, ProcessPriorityClass priority);
|
|
|
|
|
void KillAll(string processName);
|
2013-07-30 20:19:09 +00:00
|
|
|
|
bool Exists(string processName);
|
|
|
|
|
ProcessPriorityClass GetCurrentProcessPriority();
|
2013-08-07 05:32:22 +00:00
|
|
|
|
Process ShellExecute(string path, string args = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null);
|
2013-05-10 23:53:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ProcessProvider : IProcessProvider
|
2011-10-07 03:37:41 +00:00
|
|
|
|
{
|
2012-01-23 02:24:16 +00:00
|
|
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
2011-10-07 03:37:41 +00:00
|
|
|
|
|
2013-04-17 23:32:53 +00:00
|
|
|
|
public const string NzbDroneProcessName = "NzbDrone";
|
|
|
|
|
public const string NzbDroneConsoleProcessName = "NzbDrone.Console";
|
2011-10-07 03:37:41 +00:00
|
|
|
|
|
2013-08-14 04:40:34 +00:00
|
|
|
|
private static List<Process> GetProcessesByName(string name)
|
|
|
|
|
{
|
|
|
|
|
var monoProcesses = Process.GetProcessesByName("mono")
|
|
|
|
|
.Where(process => process.Modules.Cast<ProcessModule>().Any(module => module.ModuleName.ToLower() == name + ".exe"));
|
|
|
|
|
return Process.GetProcessesByName(name)
|
|
|
|
|
.Union(monoProcesses).ToList();
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
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
|
|
|
|
|
2013-07-30 20:19:09 +00:00
|
|
|
|
public bool Exists(string processName)
|
|
|
|
|
{
|
2013-08-14 04:40:34 +00:00
|
|
|
|
return GetProcessesByName(processName).Any();
|
2013-07-30 20:19:09 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ProcessPriorityClass GetCurrentProcessPriority()
|
|
|
|
|
{
|
|
|
|
|
return Process.GetCurrentProcess().PriorityClass;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
public ProcessInfo GetProcessById(int id)
|
2011-10-07 06:36:04 +00:00
|
|
|
|
{
|
2011-12-12 06:52:58 +00:00
|
|
|
|
Logger.Trace("Finding process with Id:{0}", id);
|
|
|
|
|
|
2013-05-07 05:54:21 +00:00
|
|
|
|
var processInfo = ConvertToProcessInfo(Process.GetProcesses().FirstOrDefault(p => p.Id == id));
|
2011-12-12 06:52:58 +00:00
|
|
|
|
|
|
|
|
|
if (processInfo == null)
|
|
|
|
|
{
|
|
|
|
|
Logger.Warn("Unable to find process with ID {0}", id);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Found process {0}", processInfo.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return processInfo;
|
2011-10-07 06:36:04 +00:00
|
|
|
|
}
|
2011-10-07 03:37:41 +00:00
|
|
|
|
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
public Process Start(string path)
|
2011-10-07 03:37:41 +00:00
|
|
|
|
{
|
2013-07-05 18:51:38 +00:00
|
|
|
|
return Start(new ProcessStartInfo(path));
|
2011-10-07 03:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-07 05:32:22 +00:00
|
|
|
|
public Process ShellExecute(string path, string args = null, Action<string> onOutputDataReceived = null, Action<string> onErrorDataReceived = null)
|
|
|
|
|
{
|
2013-08-14 04:25:38 +00:00
|
|
|
|
|
|
|
|
|
if (OsInfo.IsMono && path.EndsWith(".exe", StringComparison.InvariantCultureIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
args = path + " " + args;
|
|
|
|
|
path = "mono";
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-07 05:32:22 +00:00
|
|
|
|
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
|
2013-08-07 05:32:22 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.Info("Starting {0} {1}", path, args);
|
|
|
|
|
|
2013-08-13 05:08:37 +00:00
|
|
|
|
var process = new Process
|
|
|
|
|
{
|
|
|
|
|
StartInfo = startInfo
|
|
|
|
|
};
|
2013-08-07 05:32:22 +00:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
2013-08-07 05:32:22 +00:00
|
|
|
|
process.BeginErrorReadLine();
|
|
|
|
|
process.BeginOutputReadLine();
|
|
|
|
|
|
2013-08-14 03:22:28 +00:00
|
|
|
|
|
2013-08-07 05:32:22 +00:00
|
|
|
|
return process;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
public Process Start(ProcessStartInfo startInfo)
|
2011-10-07 03:37:41 +00:00
|
|
|
|
{
|
2011-10-07 06:36:04 +00:00
|
|
|
|
Logger.Info("Starting process. [{0}]", startInfo.FileName);
|
|
|
|
|
|
|
|
|
|
var process = new Process
|
|
|
|
|
{
|
|
|
|
|
StartInfo = startInfo
|
|
|
|
|
};
|
|
|
|
|
process.Start();
|
2013-07-05 18:51:38 +00:00
|
|
|
|
|
2011-10-07 06:36:04 +00:00
|
|
|
|
return process;
|
2011-10-07 03:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
public void WaitForExit(Process process)
|
2012-02-26 21:22:35 +00:00
|
|
|
|
{
|
|
|
|
|
Logger.Trace("Waiting for process {0} to exit.", process.ProcessName);
|
|
|
|
|
process.WaitForExit();
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-07 06:36:04 +00:00
|
|
|
|
|
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
public void SetPriority(int processId, ProcessPriorityClass priority)
|
2011-10-07 06:36:04 +00:00
|
|
|
|
{
|
|
|
|
|
var process = Process.GetProcessById(processId);
|
|
|
|
|
|
|
|
|
|
Logger.Info("Updating [{0}] process priority from {1} to {2}",
|
|
|
|
|
process.ProcessName,
|
|
|
|
|
process.PriorityClass,
|
|
|
|
|
priority);
|
|
|
|
|
|
|
|
|
|
process.PriorityClass = priority;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-27 00:56:49 +00:00
|
|
|
|
public void KillAll(string processName)
|
|
|
|
|
{
|
2013-08-14 04:40:34 +00:00
|
|
|
|
var processToKill = GetProcessesByName(processName);
|
2013-07-27 00:56:49 +00:00
|
|
|
|
|
|
|
|
|
foreach (var processInfo in processToKill)
|
|
|
|
|
{
|
|
|
|
|
Kill(processInfo.Id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-10-07 06:36:04 +00:00
|
|
|
|
private static ProcessInfo ConvertToProcessInfo(Process process)
|
|
|
|
|
{
|
2013-07-30 20:19:09 +00:00
|
|
|
|
if (process == null) return null;
|
|
|
|
|
|
|
|
|
|
process.Refresh();
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (process.Id <= 0 || process.HasExited) return null;
|
|
|
|
|
|
|
|
|
|
return new ProcessInfo
|
|
|
|
|
{
|
|
|
|
|
Id = process.Id,
|
|
|
|
|
StartPath = process.MainModule.FileName,
|
|
|
|
|
Name = process.ProcessName
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
catch (Win32Exception)
|
|
|
|
|
{
|
|
|
|
|
Logger.Warn("Coudn't get process info for " + process.ProcessName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
2011-10-07 03:37:41 +00:00
|
|
|
|
}
|
2013-05-04 21:09:25 +00:00
|
|
|
|
|
2013-05-07 05:38:40 +00:00
|
|
|
|
|
2013-07-05 18:51:38 +00:00
|
|
|
|
|
|
|
|
|
private void Kill(int processId)
|
|
|
|
|
{
|
2013-08-14 03:22:28 +00:00
|
|
|
|
var process = Process.GetProcesses().FirstOrDefault(p => p.Id == processId);
|
|
|
|
|
|
|
|
|
|
if (process == null)
|
2013-07-05 18:51:38 +00:00
|
|
|
|
{
|
|
|
|
|
Logger.Warn("Cannot find process with id: {0}", processId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-14 03:22:28 +00:00
|
|
|
|
process.Refresh();
|
2013-07-05 18:51:38 +00:00
|
|
|
|
|
|
|
|
|
if (process.HasExited)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger.Info("[{0}]: Killing process", process.Id);
|
|
|
|
|
process.Kill();
|
|
|
|
|
Logger.Info("[{0}]: Waiting for exit", process.Id);
|
|
|
|
|
process.WaitForExit();
|
|
|
|
|
Logger.Info("[{0}]: Process terminated successfully", process.Id);
|
|
|
|
|
}
|
2011-10-07 03:37:41 +00:00
|
|
|
|
}
|
2013-08-13 14:23:47 +00:00
|
|
|
|
}
|