Decompiled source of Instances v3.0.1

BepInEx/core/Instances/netstandard2.0/Instances.dll

Decompiled 5 months ago
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
using Instances.Exceptions;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Malte Rosenbjerg")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("Rosenbjerg Softworks")]
[assembly: AssemblyDescription("A .NET Standard Process wrapper with an elegant API, for both asyncronous and syncronous use, providing both Events and support for Tasks with cancellation support")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Instances")]
[assembly: AssemblyTitle("Instances")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/rosenbjerg/Instances")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace Instances
{
	public static class Instance
	{
		public static IProcessInstance Start(string path, string arguments = "", EventHandler<string>? outputHandler = null, EventHandler<string>? errorHandler = null)
		{
			return Start(new ProcessStartInfo
			{
				FileName = path,
				Arguments = arguments
			}, outputHandler, errorHandler);
		}

		public static IProcessInstance Start(ProcessStartInfo startInfo, EventHandler<string>? outputHandler, EventHandler<string>? errorHandler)
		{
			ProcessArguments processArguments = new ProcessArguments(startInfo);
			if (outputHandler != null)
			{
				processArguments.OutputDataReceived += outputHandler;
			}
			if (errorHandler != null)
			{
				processArguments.ErrorDataReceived += errorHandler;
			}
			return processArguments.Start();
		}

		public static IProcessResult Finish(string path, string arguments = "", EventHandler<string>? outputHandler = null, EventHandler<string>? errorHandler = null)
		{
			return Finish(new ProcessStartInfo
			{
				FileName = path,
				Arguments = arguments
			}, outputHandler, errorHandler);
		}

		public static IProcessResult Finish(ProcessStartInfo startInfo, EventHandler<string>? outputHandler = null, EventHandler<string>? errorHandler = null)
		{
			using IProcessInstance processInstance = Start(startInfo, outputHandler, errorHandler);
			return processInstance.WaitForExit();
		}

		public static Task<IProcessResult> FinishAsync(string path, string arguments = "", CancellationToken cancellationToken = default(CancellationToken), EventHandler<string>? outputHandler = null, EventHandler<string>? errorHandler = null)
		{
			return FinishAsync(new ProcessStartInfo
			{
				FileName = path,
				Arguments = arguments
			}, cancellationToken, outputHandler, errorHandler);
		}

		public static async Task<IProcessResult> FinishAsync(ProcessStartInfo startInfo, CancellationToken cancellationToken = default(CancellationToken), EventHandler<string>? outputHandler = null, EventHandler<string>? errorHandler = null)
		{
			using IProcessInstance instance = Start(startInfo, outputHandler, errorHandler);
			return await instance.WaitForExitAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false);
		}
	}
	public interface IProcessInstance : IDisposable
	{
		IReadOnlyCollection<string> OutputData { get; }

		IReadOnlyCollection<string> ErrorData { get; }

		event EventHandler<IProcessResult>? Exited;

		event EventHandler<string>? OutputDataReceived;

		event EventHandler<string>? ErrorDataReceived;

		Task SendInputAsync(string input);

		void SendInput(string input);

		Task<IProcessResult> WaitForExitAsync(CancellationToken cancellationToken = default(CancellationToken));

		IProcessResult WaitForExit();

		IProcessResult Kill();
	}
	public interface IProcessResult
	{
		int ExitCode { get; }

		IReadOnlyList<string> OutputData { get; }

		IReadOnlyList<string> ErrorData { get; }
	}
	public class ProcessArguments
	{
		private readonly ProcessStartInfo _processStartInfo;

		public bool IgnoreEmptyLines { get; set; }

		public int DataBufferCapacity { get; set; } = int.MaxValue;


		public event EventHandler<IProcessResult>? Exited;

		public event EventHandler<string>? OutputDataReceived;

		public event EventHandler<string>? ErrorDataReceived;

		public ProcessArguments(string path, string arguments)
			: this(new ProcessStartInfo
			{
				FileName = path,
				Arguments = arguments
			})
		{
		}

		public ProcessArguments(ProcessStartInfo processStartInfo)
		{
			_processStartInfo = processStartInfo;
		}

		public IProcessInstance Start()
		{
			_processStartInfo.CreateNoWindow = true;
			_processStartInfo.UseShellExecute = false;
			_processStartInfo.RedirectStandardOutput = true;
			_processStartInfo.RedirectStandardInput = true;
			_processStartInfo.RedirectStandardError = true;
			Process process = new Process
			{
				StartInfo = _processStartInfo,
				EnableRaisingEvents = true
			};
			ProcessInstance processInstance = new ProcessInstance(process, IgnoreEmptyLines, DataBufferCapacity);
			processInstance.Exited += this.Exited;
			processInstance.OutputDataReceived += this.OutputDataReceived;
			processInstance.ErrorDataReceived += this.ErrorDataReceived;
			try
			{
				process.Start();
				process.BeginOutputReadLine();
				process.BeginErrorReadLine();
				return processInstance;
			}
			catch (Win32Exception ex) when (ex.Message.Contains("The system cannot find the file specified") || ex.Message.Contains("No such file or directory"))
			{
				throw new InstanceFileNotFoundException(_processStartInfo.FileName, ex);
			}
		}
	}
	public static class ProcessArgumentsExtensions
	{
		public static IProcessResult StartAndWaitForExit(this ProcessArguments processArguments)
		{
			using IProcessInstance processInstance = processArguments.Start();
			return processInstance.WaitForExit();
		}

		public static async Task<IProcessResult> StartAndWaitForExitAsync(this ProcessArguments processArguments, CancellationToken cancellationToken = default(CancellationToken))
		{
			using IProcessInstance instance = processArguments.Start();
			return await instance.WaitForExitAsync(cancellationToken);
		}
	}
	public class ProcessInstance : IProcessInstance, IDisposable
	{
		private readonly bool _ignoreEmptyLines;

		private readonly int _dataBufferCapacity;

		private readonly Process _process;

		private readonly TaskCompletionSource<bool> _mainTask = new TaskCompletionSource<bool>();

		private readonly TaskCompletionSource<bool> _stdoutTask = new TaskCompletionSource<bool>();

		private readonly TaskCompletionSource<bool> _stderrTask = new TaskCompletionSource<bool>();

		private readonly Queue<string> _outputData = new Queue<string>();

		private readonly Queue<string> _errorData = new Queue<string>();

		public IReadOnlyCollection<string> OutputData => _outputData.ToList().AsReadOnly();

		public IReadOnlyCollection<string> ErrorData => _errorData.ToList().AsReadOnly();

		public event EventHandler<IProcessResult>? Exited;

		public event EventHandler<string>? OutputDataReceived;

		public event EventHandler<string>? ErrorDataReceived;

		internal ProcessInstance(Process process, bool ignoreEmptyLines, int dataBufferCapacity)
		{
			process.OutputDataReceived += ReceiveOutput;
			process.ErrorDataReceived += ReceiveError;
			process.Exited += ReceiveExit;
			_process = process;
			_ignoreEmptyLines = ignoreEmptyLines;
			_dataBufferCapacity = dataBufferCapacity;
		}

		public async Task SendInputAsync(string input)
		{
			ThrowIfProcessExited();
			await _process.StandardInput.WriteAsync(input).ConfigureAwait(continueOnCapturedContext: false);
			await _process.StandardInput.FlushAsync().ConfigureAwait(continueOnCapturedContext: false);
		}

		public void SendInput(string input)
		{
			ThrowIfProcessExited();
			_process.StandardInput.Write(input);
			_process.StandardInput.Flush();
		}

		public IProcessResult Kill()
		{
			try
			{
				_process.Kill();
				return GetResult();
			}
			catch (InvalidOperationException innerException)
			{
				throw new InstanceProcessAlreadyExitedException(innerException);
			}
		}

		public async Task<IProcessResult> WaitForExitAsync(CancellationToken cancellationToken = default(CancellationToken))
		{
			if (cancellationToken != default(CancellationToken))
			{
				cancellationToken.Register(delegate
				{
					_process.Kill();
				});
			}
			await _mainTask.Task.ConfigureAwait(continueOnCapturedContext: false);
			return GetResult();
		}

		public IProcessResult WaitForExit()
		{
			try
			{
				_process.WaitForExit();
				return GetResult();
			}
			catch (SystemException innerException)
			{
				throw new InstanceProcessAlreadyExitedException(innerException);
			}
		}

		public void Dispose()
		{
			_process.Dispose();
		}

		private void ReceiveExit(object sender, EventArgs e)
		{
			object sender2 = sender;
			Task.WhenAll<bool>(_stdoutTask.Task, _stderrTask.Task).ContinueWith(delegate
			{
				this.Exited?.Invoke(sender2, GetResult());
				return _mainTask.TrySetResult(result: true);
			});
		}

		private void ReceiveOutput(object _, DataReceivedEventArgs e)
		{
			AddData(_outputData, e.Data, this.OutputDataReceived, _stdoutTask);
		}

		private void ReceiveError(object _, DataReceivedEventArgs e)
		{
			AddData(_errorData, e.Data, this.ErrorDataReceived, _stderrTask);
		}

		private void AddData(Queue<string> dataList, string? data, EventHandler<string>? eventHandler, TaskCompletionSource<bool> taskCompletionSource)
		{
			if (data == null)
			{
				taskCompletionSource.TrySetResult(result: true);
			}
			else if (!_ignoreEmptyLines || !(data == string.Empty))
			{
				dataList.Enqueue(data);
				for (int i = 0; i < dataList.Count - _dataBufferCapacity; i++)
				{
					dataList.Dequeue();
				}
				eventHandler?.Invoke(this, data);
			}
		}

		private IProcessResult GetResult()
		{
			return new ProcessResult(_process.HasExited ? _process.ExitCode : (-100), _outputData.ToArray(), _errorData.ToArray());
		}

		private void ThrowIfProcessExited()
		{
			if (_process.HasExited)
			{
				throw new InstanceProcessAlreadyExitedException();
			}
		}
	}
	public class ProcessResult : IProcessResult
	{
		public int ExitCode { get; }

		public IReadOnlyList<string> OutputData { get; }

		public IReadOnlyList<string> ErrorData { get; }

		internal ProcessResult(int exitCode, IReadOnlyList<string> outputData, IReadOnlyList<string> errorData)
		{
			OutputData = outputData;
			ErrorData = errorData;
			ExitCode = exitCode;
		}
	}
}
namespace Instances.Exceptions
{
	public class InstanceException : Exception
	{
		public InstanceException(string msg, Exception innerException)
			: base(msg, innerException)
		{
		}
	}
	public class InstanceFileNotFoundException : InstanceException
	{
		public InstanceFileNotFoundException(string fileName, Exception innerException)
			: base("File not found: " + fileName, innerException)
		{
		}
	}
	public class InstanceProcessAlreadyExitedException : Exception
	{
		public InstanceProcessAlreadyExitedException()
			: base("The process instance has already exited")
		{
		}

		public InstanceProcessAlreadyExitedException(Exception innerException)
			: base("The process instance has already exited", innerException)
		{
		}
	}
}