You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
95 lines
3.8 KiB
95 lines
3.8 KiB
using CliWrap;
|
|
using CliWrap.Buffered;
|
|
using CoreAgent.Domain.Interfaces.System.Command;
|
|
using CoreAgent.Domain.Models;
|
|
using CoreAgent.Domain.Models.System;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace CoreAgent.Infrastructure.Command.Base;
|
|
|
|
/// <summary>
|
|
/// 命令执行器基类
|
|
/// </summary>
|
|
public abstract class BaseCommandExecutor : ISystemCommandExecutor
|
|
{
|
|
protected readonly ILogger _logger;
|
|
protected abstract string DefaultShell { get; }
|
|
|
|
protected BaseCommandExecutor(ILogger logger)
|
|
{
|
|
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 执行命令并实时输出结果
|
|
/// </summary>
|
|
public abstract Task ExecuteCommandWithOutputAsync(string command, Action<string> outputHandler, Action<string> errorHandler, CancellationTokenSource cancellationTokenSource, int timeout = -1);
|
|
|
|
/// <summary>
|
|
/// 执行命令并返回结果
|
|
/// </summary>
|
|
public abstract Task<CommandExecutionResult> ExecuteCommandAsync(string command, CancellationTokenSource cancellationTokenSource, int timeout = -1);
|
|
|
|
/// <summary>
|
|
/// 获取命令参数,由子类实现具体的命令参数格式化逻辑
|
|
/// </summary>
|
|
protected abstract string GetCommandArguments(string command);
|
|
|
|
/// <summary>
|
|
/// 执行命令的通用逻辑
|
|
/// </summary>
|
|
protected virtual async Task<CommandExecutionResult> ExecuteCommandInternalAsync(string command, string arguments, CancellationTokenSource cancellationTokenSource, int timeout = -1)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(command))
|
|
{
|
|
throw new ArgumentException("命令不能为空", nameof(command));
|
|
}
|
|
|
|
if (cancellationTokenSource == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(cancellationTokenSource));
|
|
}
|
|
|
|
var startTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
try
|
|
{
|
|
_logger.LogDebug("开始执行命令: {Command}", command);
|
|
|
|
var cmd = Cli.Wrap(DefaultShell)
|
|
.WithArguments(arguments)
|
|
.WithValidation(CommandResultValidation.None);
|
|
|
|
// 如果设置了超时,创建一个新的 CancellationTokenSource
|
|
using var timeoutCts = timeout > 0 ? new CancellationTokenSource(timeout) : null;
|
|
using var linkedCts = timeout > 0
|
|
? CancellationTokenSource.CreateLinkedTokenSource(cancellationTokenSource.Token, timeoutCts!.Token)
|
|
: cancellationTokenSource;
|
|
|
|
var result = await cmd.ExecuteBufferedAsync(linkedCts.Token);
|
|
var executionTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTime;
|
|
|
|
if (result.IsSuccess)
|
|
{
|
|
_logger.LogDebug("命令执行成功 - 输出: {Output}", result.StandardOutput);
|
|
return CommandExecutionResult.Success(result.StandardOutput, executionTime);
|
|
}
|
|
else
|
|
{
|
|
_logger.LogDebug("命令执行失败 - 错误: {Error}", result.StandardError);
|
|
return CommandExecutionResult.Failure(result.StandardError, executionTime);
|
|
}
|
|
}
|
|
catch (OperationCanceledException ex)
|
|
{
|
|
var executionTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTime;
|
|
_logger.LogError(ex, "命令执行超时: {Command}", command);
|
|
return CommandExecutionResult.Failure("命令执行超时", executionTime);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var executionTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - startTime;
|
|
_logger.LogError(ex, "命令执行失败: {Command}, 错误: {ErrorMessage}", command, ex.Message);
|
|
return CommandExecutionResult.Failure(ex.Message, executionTime);
|
|
}
|
|
}
|
|
}
|