Previous timeout using CancellationToken didn't work because ReadToEndAsync blocks waiting for process output. Now using Task.WhenAny with Task.Delay to properly timeout and kill hung processes after 5 seconds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
108 lines
3.2 KiB
C#
108 lines
3.2 KiB
C#
using System.Diagnostics;
|
|
|
|
namespace CMM.Library.Helpers;
|
|
|
|
internal class ConsoleHelper
|
|
{
|
|
const string cmdFileName = "cmd.exe";
|
|
private static Process CreatProcess(string fileName) =>
|
|
new Process()
|
|
{
|
|
StartInfo = new ProcessStartInfo
|
|
{
|
|
FileName = fileName,
|
|
UseShellExecute = false,
|
|
RedirectStandardInput = true,
|
|
RedirectStandardOutput = true,
|
|
RedirectStandardError = true,
|
|
CreateNoWindow = true,
|
|
}
|
|
};
|
|
|
|
public static async Task<string> ExecuteCommand(string command, int timeoutMs = 5000)
|
|
{
|
|
Process p = new Process();
|
|
p.StartInfo.UseShellExecute = false;
|
|
p.StartInfo.CreateNoWindow = true;
|
|
p.StartInfo.RedirectStandardOutput = true;
|
|
p.StartInfo.FileName = command;
|
|
p.Start();
|
|
|
|
var readTask = p.StandardOutput.ReadToEndAsync();
|
|
var completedTask = await Task.WhenAny(readTask, Task.Delay(timeoutMs));
|
|
|
|
if (completedTask != readTask)
|
|
{
|
|
// Timeout - kill the process
|
|
try { p.Kill(true); } catch { }
|
|
return string.Empty;
|
|
}
|
|
|
|
return await readTask;
|
|
}
|
|
|
|
public static async Task<string> CmdCommandAsync(params string[] cmds) =>
|
|
await CommandAsync(cmdFileName, cmds);
|
|
|
|
public static string CmdCommand(params string[] cmds) =>
|
|
Command(cmdFileName, cmds);
|
|
|
|
public static async Task<string> CommandAsync(string fileName, params string[] cmds)
|
|
{
|
|
return await CommandAsync(fileName, 5000, cmds);
|
|
}
|
|
|
|
public static async Task<string> CommandAsync(string fileName, int timeoutMs, params string[] cmds)
|
|
{
|
|
var p = CreatProcess(fileName);
|
|
p.Start();
|
|
foreach (var cmd in cmds)
|
|
{
|
|
p.StandardInput.WriteLine(cmd);
|
|
}
|
|
p.StandardInput.WriteLine("exit");
|
|
|
|
var readTask = Task.Run(async () =>
|
|
{
|
|
var result = await p.StandardOutput.ReadToEndAsync();
|
|
var error = await p.StandardError.ReadToEndAsync();
|
|
if (!string.IsNullOrWhiteSpace(error))
|
|
result = result + "\r\n<Error Message>:\r\n" + error;
|
|
return result;
|
|
});
|
|
|
|
var completedTask = await Task.WhenAny(readTask, Task.Delay(timeoutMs));
|
|
|
|
if (completedTask != readTask)
|
|
{
|
|
// Timeout - kill the process
|
|
try { p.Kill(true); } catch { }
|
|
return string.Empty;
|
|
}
|
|
|
|
var output = await readTask;
|
|
p.Close();
|
|
Debug.WriteLine(output);
|
|
return output;
|
|
}
|
|
|
|
public static string Command(string fileName, params string[] cmds)
|
|
{
|
|
var p = CreatProcess(fileName);
|
|
p.Start();
|
|
foreach (var cmd in cmds)
|
|
{
|
|
p.StandardInput.WriteLine(cmd);
|
|
}
|
|
p.StandardInput.WriteLine("exit");
|
|
var result = p.StandardOutput.ReadToEnd();
|
|
var error = p.StandardError.ReadToEnd();
|
|
if (!string.IsNullOrWhiteSpace(error))
|
|
result = result + "\r\n<Error Message>:\r\n" + error;
|
|
p.WaitForExit();
|
|
p.Close();
|
|
Debug.WriteLine(result);
|
|
return result;
|
|
}
|
|
}
|