2025-07-16 09:20:13 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
using YunDa.Server.ISMSTcp.Models;
|
2025-07-31 18:51:24 +08:00
|
|
|
|
using YunDa.Server.ISMSTcp.Interfaces;
|
2025-07-16 09:20:13 +08:00
|
|
|
|
|
|
|
|
|
|
namespace YunDa.Server.ISMSTcp.Services
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 命令状态机实现
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class CommandStateMachine : ICommandStateMachine
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ILogger<CommandStateMachine> _logger;
|
|
|
|
|
|
private readonly object _lock = new object();
|
2025-07-31 18:51:24 +08:00
|
|
|
|
private CommandState _currentCommand;
|
2025-07-16 09:20:13 +08:00
|
|
|
|
|
|
|
|
|
|
public CommandStateMachine(ILogger<CommandStateMachine> logger)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger = logger;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 当前命令状态
|
|
|
|
|
|
/// </summary>
|
2025-07-31 18:51:24 +08:00
|
|
|
|
public CommandState CurrentCommand
|
2025-07-16 09:20:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
return _currentCommand;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否有命令正在执行
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool HasPendingCommand
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
2025-07-31 18:51:24 +08:00
|
|
|
|
return _currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse;
|
2025-07-16 09:20:13 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 开始执行命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="commandName">命令名称</param>
|
|
|
|
|
|
/// <param name="fullMessage">完整消息</param>
|
|
|
|
|
|
/// <param name="timeoutSeconds">超时时间(秒)</param>
|
|
|
|
|
|
/// <returns>是否成功开始执行</returns>
|
|
|
|
|
|
public bool StartCommand(string commandName, string fullMessage, int timeoutSeconds = 180)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(commandName))
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Cannot start command with empty name");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查是否有命令正在执行
|
2025-07-31 18:51:24 +08:00
|
|
|
|
if (_currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse)
|
2025-07-16 09:20:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (_currentCommand.IsTimeout)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Previous command '{PreviousCommand}' timed out, starting new command '{NewCommand}'",
|
|
|
|
|
|
_currentCommand.CommandName, commandName);
|
|
|
|
|
|
_currentCommand.State = CommandExecutionState.Timeout;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Command '{CurrentCommand}' is still pending (remaining: {RemainingTime:F1}s), cannot start new command '{NewCommand}'",
|
|
|
|
|
|
_currentCommand.CommandName, _currentCommand.RemainingTimeoutSeconds, commandName);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建新的命令状态
|
|
|
|
|
|
_currentCommand = new CommandState
|
|
|
|
|
|
{
|
|
|
|
|
|
CommandName = commandName,
|
|
|
|
|
|
FullMessage = fullMessage,
|
|
|
|
|
|
State = CommandExecutionState.WaitingForResponse,
|
|
|
|
|
|
SentTime = DateTime.Now,
|
|
|
|
|
|
TimeoutSeconds = timeoutSeconds
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("Started command '{CommandName}' with timeout {TimeoutSeconds}s",
|
|
|
|
|
|
commandName, timeoutSeconds);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 完成当前命令
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="commandName">响应的命令名称(用于验证)</param>
|
|
|
|
|
|
/// <returns>是否成功完成</returns>
|
2025-07-31 18:51:24 +08:00
|
|
|
|
public bool CompleteCommand(string commandName = null)
|
2025-07-16 09:20:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentCommand == null || _currentCommand.State != CommandExecutionState.WaitingForResponse)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("No pending command to complete");
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果提供了命令名称,验证是否匹配
|
|
|
|
|
|
if (!string.IsNullOrEmpty(commandName) &&
|
|
|
|
|
|
!string.Equals(_currentCommand.CommandName, commandName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Command name mismatch: expected '{Expected}', got '{Actual}'",
|
|
|
|
|
|
_currentCommand.CommandName, commandName);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var executionTime = DateTime.Now.Subtract(_currentCommand.SentTime).TotalSeconds;
|
|
|
|
|
|
_currentCommand.State = CommandExecutionState.Completed;
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("Completed command '{CommandName}' in {ExecutionTime:F2}s",
|
|
|
|
|
|
_currentCommand.CommandName, executionTime);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置命令超时
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>是否有命令被设置为超时</returns>
|
|
|
|
|
|
public bool TimeoutCommand()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
2025-07-31 18:51:24 +08:00
|
|
|
|
if (_currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse)
|
2025-07-16 09:20:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
_currentCommand.State = CommandExecutionState.Timeout;
|
|
|
|
|
|
_logger.LogWarning("Command '{CommandName}' timed out after {TimeoutSeconds}s",
|
|
|
|
|
|
_currentCommand.CommandName, _currentCommand.TimeoutSeconds);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检查并处理超时
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>是否有命令超时</returns>
|
|
|
|
|
|
public bool CheckAndHandleTimeout()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
2025-07-31 18:51:24 +08:00
|
|
|
|
if (_currentCommand != null && _currentCommand.IsTimeout == true)
|
2025-07-16 09:20:13 +08:00
|
|
|
|
{
|
|
|
|
|
|
return TimeoutCommand();
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-31 18:51:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 处理OK响应,解锁命令状态
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>是否成功处理OK响应</returns>
|
|
|
|
|
|
public bool HandleOkResponse()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse)
|
|
|
|
|
|
{
|
|
|
|
|
|
var executionTime = DateTime.Now.Subtract(_currentCommand.SentTime).TotalSeconds;
|
|
|
|
|
|
_currentCommand.State = CommandExecutionState.Completed;
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation("Command '{CommandName}' completed with OK response in {ExecutionTime:F2}s",
|
|
|
|
|
|
_currentCommand.CommandName, executionTime);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (_currentCommand != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning("Received OK response but command '{CommandName}' is in state: {State}",
|
|
|
|
|
|
_currentCommand.CommandName, _currentCommand.State);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogDebug("Received OK response but no command is currently pending");
|
|
|
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-16 09:20:13 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 重置状态机
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Reset()
|
|
|
|
|
|
{
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_currentCommand != null)
|
|
|
|
|
|
{
|
2025-07-31 18:51:24 +08:00
|
|
|
|
_logger.LogInformation("Resetting command state machine, current command: '{CommandName}' in state: {State}",
|
2025-07-16 09:20:13 +08:00
|
|
|
|
_currentCommand.CommandName, _currentCommand.State);
|
|
|
|
|
|
}
|
|
|
|
|
|
_currentCommand = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|