NavisworksTransport/src/Commands/CommandExecutor.cs

483 lines
15 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using NavisworksTransport.Core;
namespace NavisworksTransport.Commands
{
/// <summary>
/// 命令执行器
/// 提供异步命令执行框架与UIStateManager集成支持命令队列和状态跟踪
/// </summary>
public class CommandExecutor
{
#region
private static CommandExecutor _instance;
private static readonly object _instanceLock = new object();
private readonly ConcurrentDictionary<string, IPathPlanningCommand> _runningCommands;
private readonly ConcurrentQueue<CommandExecutionRequest> _commandQueue;
private readonly SemaphoreSlim _executionSemaphore;
private readonly UIStateManager _uiStateManager;
private volatile bool _isProcessing = false;
private volatile bool _isDisposed = false;
/// <summary>
/// 获取CommandExecutor的单例实例
/// </summary>
public static CommandExecutor Instance
{
get
{
if (_instance == null)
{
lock (_instanceLock)
{
if (_instance == null)
{
_instance = new CommandExecutor();
}
}
}
return _instance;
}
}
/// <summary>
/// 当前正在运行的命令数量
/// </summary>
public int RunningCommandCount => _runningCommands.Count;
/// <summary>
/// 队列中等待执行的命令数量
/// </summary>
public int QueuedCommandCount => _commandQueue.Count;
/// <summary>
/// 最大并发执行命令数
/// </summary>
public int MaxConcurrentCommands { get; set; } = 3;
#endregion
#region
/// <summary>
/// 命令开始执行事件
/// </summary>
public event EventHandler<CommandExecutionEventArgs> CommandStarted;
/// <summary>
/// 命令执行完成事件
/// </summary>
public event EventHandler<CommandCompletedEventArgs> CommandCompleted;
/// <summary>
/// 队列状态改变事件
/// </summary>
public event EventHandler<QueueStatusEventArgs> QueueStatusChanged;
#endregion
#region
private CommandExecutor()
{
_runningCommands = new ConcurrentDictionary<string, IPathPlanningCommand>();
_commandQueue = new ConcurrentQueue<CommandExecutionRequest>();
_executionSemaphore = new SemaphoreSlim(MaxConcurrentCommands, MaxConcurrentCommands);
_uiStateManager = UIStateManager.Instance;
LogManager.Info("CommandExecutor 初始化完成");
}
#endregion
#region
/// <summary>
/// 执行单个命令(异步)
/// </summary>
public async Task<PathPlanningResult> ExecuteAsync(IPathPlanningCommand command, CancellationToken cancellationToken = default)
{
if (command == null)
{
return PathPlanningResult.Failure("命令对象不能为空");
}
if (_isDisposed)
{
return PathPlanningResult.Failure("CommandExecutor已被释放");
}
try
{
LogManager.Info($"开始执行命令: {command.DisplayName} (ID: {command.CommandId})");
// 等待执行槽位
await _executionSemaphore.WaitAsync(cancellationToken);
try
{
// 添加到运行命令列表
_runningCommands.TryAdd(command.CommandId, command);
// 触发命令开始事件
OnCommandStarted(command);
// 订阅命令状态改变事件
command.StatusChanged += OnCommandStatusChanged;
command.ProgressChanged += OnCommandProgressChanged;
// 执行命令
var result = await command.ExecuteAsync(cancellationToken);
// 触发命令完成事件
OnCommandCompleted(command, result);
LogManager.Info($"命令执行完成: {command.DisplayName}, 结果: {(result.IsSuccess ? "" : "")}");
return result;
}
finally
{
// 从运行命令列表中移除
_runningCommands.TryRemove(command.CommandId, out _);
// 取消订阅事件
command.StatusChanged -= OnCommandStatusChanged;
command.ProgressChanged -= OnCommandProgressChanged;
// 释放执行槽位
_executionSemaphore.Release();
}
}
catch (OperationCanceledException)
{
LogManager.Info($"命令执行被取消: {command.DisplayName}");
return PathPlanningResult.Failure("命令执行已取消");
}
catch (Exception ex)
{
LogManager.Error($"执行命令时出现异常: {command.DisplayName}", ex);
return PathPlanningResult.Failure($"命令执行异常: {ex.Message}", ex);
}
}
/// <summary>
/// 将命令加入队列异步执行
/// </summary>
public Task<PathPlanningResult> EnqueueAsync(IPathPlanningCommand command,
CommandPriority priority = CommandPriority.Normal,
CancellationToken cancellationToken = default)
{
if (command == null)
{
return Task.FromResult(PathPlanningResult.Failure("命令对象不能为空"));
}
if (_isDisposed)
{
return Task.FromResult(PathPlanningResult.Failure("CommandExecutor已被释放"));
}
var request = new CommandExecutionRequest
{
Command = command,
Priority = priority,
CancellationToken = cancellationToken,
TaskCompletionSource = new TaskCompletionSource<PathPlanningResult>()
};
_commandQueue.Enqueue(request);
OnQueueStatusChanged();
// 启动处理队列直接在主线程执行避免后台线程导致的Navisworks Native对象生命周期问题
ProcessQueueAsync();
LogManager.Info($"命令已加入队列: {command.DisplayName} (优先级: {priority})");
return request.TaskCompletionSource.Task;
}
/// <summary>
/// 取消指定命令
/// </summary>
public bool CancelCommand(string commandId)
{
if (_runningCommands.TryGetValue(commandId, out var command))
{
command.Cancel();
LogManager.Info($"已发送取消请求: {command.DisplayName}");
return true;
}
LogManager.Warning($"未找到要取消的命令: {commandId}");
return false;
}
/// <summary>
/// 取消所有正在运行的命令
/// </summary>
public void CancelAllCommands()
{
var commands = _runningCommands.Values.ToArray();
foreach (var command in commands)
{
command.Cancel();
}
LogManager.Info($"已发送取消请求给 {commands.Length} 个命令");
}
/// <summary>
/// 获取指定命令的状态
/// </summary>
public CommandExecutionStatus? GetCommandStatus(string commandId)
{
return _runningCommands.TryGetValue(commandId, out var command) ? (CommandExecutionStatus?)command.Status : null;
}
/// <summary>
/// 获取所有正在运行的命令信息
/// </summary>
public IEnumerable<CommandInfo> GetRunningCommands()
{
return _runningCommands.Values.Select(cmd => new CommandInfo
{
CommandId = cmd.CommandId,
DisplayName = cmd.DisplayName,
Description = cmd.Description,
Status = cmd.Status,
Progress = cmd.Progress
}).ToArray();
}
/// <summary>
/// 释放资源
/// </summary>
public void Dispose()
{
if (_isDisposed) return;
_isDisposed = true;
// 取消所有命令
CancelAllCommands();
// 等待所有命令完成最多等待5秒
var timeout = TimeSpan.FromSeconds(5);
var startTime = DateTime.Now;
while (_runningCommands.Count > 0 && DateTime.Now - startTime < timeout)
{
Thread.Sleep(100);
}
_executionSemaphore?.Dispose();
LogManager.Info("CommandExecutor 已释放");
}
#endregion
#region
/// <summary>
/// 处理命令队列
/// </summary>
private async Task ProcessQueueAsync()
{
if (_isProcessing || _isDisposed) return;
_isProcessing = true;
try
{
while (_commandQueue.TryDequeue(out var request) && !_isDisposed)
{
try
{
var result = await ExecuteAsync(request.Command, request.CancellationToken);
request.TaskCompletionSource.SetResult(result);
}
catch (Exception ex)
{
var errorResult = PathPlanningResult.Failure($"队列执行命令失败: {ex.Message}", ex);
request.TaskCompletionSource.SetResult(errorResult);
}
OnQueueStatusChanged();
}
}
finally
{
_isProcessing = false;
}
}
#endregion
#region
/// <summary>
/// 处理命令状态改变事件更新UI
/// </summary>
private void OnCommandStatusChanged(object sender, CommandStatusChangedEventArgs e)
{
if (!(sender is IPathPlanningCommand command)) return;
// 使用UIStateManager安全更新UI
_uiStateManager.QueueUIUpdate(() =>
{
LogManager.Info($"命令状态改变: {command.DisplayName} - {e.PreviousStatus} → {e.CurrentStatus}");
}, UIUpdatePriority.Normal);
}
/// <summary>
/// 处理命令进度改变事件更新UI
/// </summary>
private void OnCommandProgressChanged(object sender, CommandProgressChangedEventArgs e)
{
if (!(sender is IPathPlanningCommand command)) return;
// 使用UIStateManager安全更新UI
_uiStateManager.QueueUIUpdate(() =>
{
// UI可以通过订阅CommandExecutor的事件来更新进度条
}, UIUpdatePriority.Normal);
}
/// <summary>
/// 触发命令开始事件
/// </summary>
private void OnCommandStarted(IPathPlanningCommand command)
{
try
{
CommandStarted?.Invoke(this, new CommandExecutionEventArgs(command));
}
catch (Exception ex)
{
LogManager.Error("触发命令开始事件时出现异常", ex);
}
}
/// <summary>
/// 触发命令完成事件
/// </summary>
private void OnCommandCompleted(IPathPlanningCommand command, PathPlanningResult result)
{
try
{
CommandCompleted?.Invoke(this, new CommandCompletedEventArgs(command, result));
}
catch (Exception ex)
{
LogManager.Error("触发命令完成事件时出现异常", ex);
}
}
/// <summary>
/// 触发队列状态改变事件
/// </summary>
private void OnQueueStatusChanged()
{
try
{
QueueStatusChanged?.Invoke(this, new QueueStatusEventArgs(QueuedCommandCount, RunningCommandCount));
}
catch (Exception ex)
{
LogManager.Error("触发队列状态改变事件时出现异常", ex);
}
}
#endregion
}
#region
/// <summary>
/// 命令优先级
/// </summary>
public enum CommandPriority
{
Low = 0,
Normal = 1,
High = 2,
Critical = 3
}
/// <summary>
/// 命令执行请求
/// </summary>
internal class CommandExecutionRequest
{
public IPathPlanningCommand Command { get; set; }
public CommandPriority Priority { get; set; }
public CancellationToken CancellationToken { get; set; }
public TaskCompletionSource<PathPlanningResult> TaskCompletionSource { get; set; }
}
/// <summary>
/// 命令信息
/// </summary>
public class CommandInfo
{
public string CommandId { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
public CommandExecutionStatus Status { get; set; }
public int Progress { get; set; }
}
/// <summary>
/// 命令执行事件参数
/// </summary>
public class CommandExecutionEventArgs : EventArgs
{
public IPathPlanningCommand Command { get; }
public CommandExecutionEventArgs(IPathPlanningCommand command)
{
Command = command;
}
}
/// <summary>
/// 命令完成事件参数
/// </summary>
public class CommandCompletedEventArgs : EventArgs
{
public IPathPlanningCommand Command { get; }
public PathPlanningResult Result { get; }
public CommandCompletedEventArgs(IPathPlanningCommand command, PathPlanningResult result)
{
Command = command;
Result = result;
}
}
/// <summary>
/// 队列状态事件参数
/// </summary>
public class QueueStatusEventArgs : EventArgs
{
public int QueuedCount { get; }
public int RunningCount { get; }
public QueueStatusEventArgs(int queuedCount, int runningCount)
{
QueuedCount = queuedCount;
RunningCount = runningCount;
}
}
#endregion
}