using System.Diagnostics; using System.IO; using System.Text; namespace Zcbot.WindowsNode; internal sealed class ProcessSupervisor { internal Process Start( ProcessStartInfo startInfo, string failureMessage = "Adapter worker did not start.") => Process.Start(startInfo) ?? throw new InvalidOperationException(failureMessage); internal async Task TerminateTreeAsync( Process process, CancellationToken cancellationToken = default) { if (process.HasExited) return; process.Kill(entireProcessTree: true); using var timeout = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); timeout.CancelAfter(TimeSpan.FromSeconds(30)); try { await process.WaitForExitAsync(timeout.Token); } catch (OperationCanceledException exception) when (!cancellationToken.IsCancellationRequested) { throw new InvalidOperationException( "Adapter worker process tree did not terminate within 30 seconds.", exception); } } internal async Task CaptureOutputAsync( StreamReader reader, IProgress? progress = null) { var output = new StringBuilder(); while (await reader.ReadLineAsync() is { } line) { if (output.Length < 16 * 1024) { output.AppendLine(line); } progress?.Report(line); } return output.ToString(); } }