Created
September 30, 2016 22:15
-
-
Save rwindegger/f07c38fb4e0d1827e66f454b9098ca13 to your computer and use it in GitHub Desktop.
Implements the base process class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// @license <![CDATA[Copyright © windegger.wtf 2016 | |
/// | |
/// Unauthorized copying of this file, via any medium is strictly | |
/// prohibited | |
/// | |
/// Proprietary and confidential | |
/// | |
/// Written by Rene Windegger <rene@windegger.wtf> on 24.02.2016]]> | |
/// @file Diagnostics\BaseProcess.cs | |
/// Implements the base process class. | |
namespace wtf.windegger.SharedLibrary.Diagnostics | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Threading; | |
using Threading; | |
using System.Diagnostics; | |
/// See . | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @sa System.Diagnostics.Process | |
public abstract class BaseProcess<T, TEnvironment> : Process | |
where T : BaseProcess<T, TEnvironment>, new() | |
where TEnvironment : IEnvironmentBuilder | |
{ | |
#region Static Properties | |
/// Gets the process scheduler. | |
/// @return The process scheduler. | |
public static LimitedConcurrencyTaskScheduler ProcessScheduler { get; } = new LimitedConcurrencyTaskScheduler(1); | |
/// Gets the processes. | |
/// @return The processes. | |
public static LinkedList Processes { get; } = new LinkedList(); | |
#endregion | |
#region Static Methods | |
/// Starts the given environment. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param environment The environment. | |
/// @return A Task | |
public static Task Start(TEnvironment environment) | |
{ | |
return Task.Factory.StartNew(() => new T()) | |
.ContinueWith(p => { Processes.AddLast(p.Result); return p.Result; }) | |
.ContinueWith(p => { p.Result.Execute(environment); return p.Result; }, ProcessScheduler) | |
.ContinueWith(p => { Processes.Remove(p.Result); return p.Result; }); | |
} | |
/// Starts. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param environment The environment. | |
/// @param token The token. | |
/// @return A Task | |
public static Task Start(TEnvironment environment, CancellationToken token) | |
{ | |
return Task.Factory.StartNew(() => new T(), token) | |
.ContinueWith(p => { Processes.AddLast(p.Result); return p.Result; }, token) | |
.ContinueWith(p => { p.Result.Execute(environment); return p.Result; }, token, TaskContinuationOptions.LongRunning, ProcessScheduler) | |
.ContinueWith(p => { Processes.Remove(p.Result); return p.Result; }, token); | |
} | |
#endregion | |
#region Properties | |
/// Gets the command line. | |
/// @return The command line. | |
public string CommandLine { get; } | |
/// Gets the environment. | |
/// @return The environment. | |
public TEnvironment Environment { get; private set; } | |
#endregion | |
#region Fields | |
private StringBuilder m_ConsoleBuilder = new StringBuilder(); ///< The console builder | |
private readonly object m_DataReceivedLock = new object(); ///< The data received lock | |
#endregion | |
/// Initializes a new instance of the | |
/// wtf.windegger.SharedLibrary.Diagnostics.BaseProcess<T, | |
/// TEnvironment> class. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param commandLine The command line. | |
public BaseProcess(string commandLine) : base() | |
{ | |
CommandLine = commandLine; | |
} | |
#region Protected Methods | |
/// Executes the given environment. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param env The environment. | |
protected void Execute(TEnvironment env) | |
{ | |
Environment = env; | |
ProcessStartInfo info = new ProcessStartInfo(CommandLine, Environment.BuildArgumentLine()); | |
info.RedirectStandardError = true; | |
info.RedirectStandardInput = true; | |
info.RedirectStandardOutput = true; | |
info.UseShellExecute = false; | |
info.CreateNoWindow = true; | |
info.WorkingDirectory = Environment.WorkingDirectory; | |
foreach (var e in Environment.BuildEnvironmentVariables()) | |
{ | |
#if NET451 | |
info.EnvironmentVariables.Add(e.Key, e.Value); | |
#else | |
info.Environment.Add(e.Key, e.Value); | |
#endif | |
} | |
StartInfo = info; | |
ErrorDataReceived += DataReceived; | |
OutputDataReceived += DataReceived; | |
Start(); | |
Environment.IsRunning = true; | |
BeginErrorReadLine(); | |
BeginOutputReadLine(); | |
#if NET451 | |
AppDomain.CurrentDomain.ProcessExit += ApplicationExit; | |
#endif | |
WaitForExit(); | |
if (HasExited) | |
{ | |
CancelErrorRead(); | |
CancelOutputRead(); | |
#if NET451 | |
Close(); | |
AppDomain.CurrentDomain.ProcessExit -= ApplicationExit; | |
#endif | |
Environment.IsRunning = false; | |
Environment.IsFinished = true; | |
} | |
} | |
#endregion | |
#region Private Methods | |
/// Application exit. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param sender Source of the event. | |
/// @param e Event information. | |
private void ApplicationExit(object sender, EventArgs e) | |
{ | |
ShutdownRequested(); | |
} | |
/// Data received. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param sender Source of the event. | |
/// @param e Data received event information. | |
private void DataReceived(object sender, DataReceivedEventArgs e) | |
{ | |
if (!string.IsNullOrWhiteSpace(e.Data?.Trim())) | |
{ | |
string line = e.Data.Trim(); | |
lock (m_DataReceivedLock) | |
{ | |
m_ConsoleBuilder.AppendLine(line); | |
} | |
Environment.Console = m_ConsoleBuilder.ToString(); | |
LineReceived(line); | |
} | |
} | |
#endregion | |
#region Abstract Methods | |
/// Shutdown requested. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
protected abstract void ShutdownRequested(); | |
/// Line received. | |
/// @author Rene Windegger | |
/// @date 24.02.2016 | |
/// @param line The line. | |
protected abstract void LineReceived(string line); | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment