215 lines
7.7 KiB
C#
215 lines
7.7 KiB
C#
using System;
|
||
using Microsoft.Extensions.Logging;
|
||
using YunDa.Server.ISMSTcp.Models;
|
||
using YunDa.Server.ISMSTcp.Interfaces;
|
||
|
||
namespace YunDa.Server.ISMSTcp.Services
|
||
{
|
||
/// <summary>
|
||
/// 命令状态机实现
|
||
/// </summary>
|
||
public class CommandStateMachine : ICommandStateMachine
|
||
{
|
||
private readonly ILogger<CommandStateMachine> _logger;
|
||
private readonly object _lock = new object();
|
||
private CommandState _currentCommand;
|
||
|
||
public CommandStateMachine(ILogger<CommandStateMachine> logger)
|
||
{
|
||
_logger = logger;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 当前命令状态
|
||
/// </summary>
|
||
public CommandState CurrentCommand
|
||
{
|
||
get
|
||
{
|
||
lock (_lock)
|
||
{
|
||
return _currentCommand;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 是否有命令正在执行
|
||
/// </summary>
|
||
public bool HasPendingCommand
|
||
{
|
||
get
|
||
{
|
||
lock (_lock)
|
||
{
|
||
return _currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <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)
|
||
{
|
||
// 检查是否有命令正在执行
|
||
if (_currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse)
|
||
{
|
||
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>
|
||
public bool CompleteCommand(string commandName = null)
|
||
{
|
||
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)
|
||
{
|
||
if (_currentCommand != null && _currentCommand.State == CommandExecutionState.WaitingForResponse)
|
||
{
|
||
_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)
|
||
{
|
||
if (_currentCommand != null && _currentCommand.IsTimeout == true)
|
||
{
|
||
return TimeoutCommand();
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <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.LogInformation("Received OK response but no command is currently pending");
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 重置状态机
|
||
/// </summary>
|
||
public void Reset()
|
||
{
|
||
lock (_lock)
|
||
{
|
||
if (_currentCommand != null)
|
||
{
|
||
_logger.LogInformation("Resetting command state machine, current command: '{CommandName}' in state: {State}",
|
||
_currentCommand.CommandName, _currentCommand.State);
|
||
}
|
||
_currentCommand = null;
|
||
}
|
||
}
|
||
}
|
||
}
|