using Microsoft.Extensions.Logging;
using System.Net.Sockets;
using WIDESEAWCS_Common;
using WIDESEAWCS_Core.Caches;
using WIDESEAWCS_Core.LogHelper;
using WIDESEAWCS_Tasks.Workflow.Abstractions;
namespace WIDESEAWCS_Tasks
{
///
/// 机器人消息处理器 - 消息路由入口
///
///
/// 核心职责:
/// 1. 缓存状态读取:从 Redis 中获取机器人最新的状态
/// 2. 命令分发:根据消息类型分发给不同的处理器
/// - 简单命令(如 homing、running):由 处理
/// - 前缀命令(如 pickfinished、putfinished):由 处理
/// 3. 回包触发:将原始消息回写到客户端
///
/// 这是消息处理管道的入口点,由 TcpSocketServer 的 MessageReceived 事件触发。
///
public class RobotMessageHandler : IRobotMessageRouter
{
///
/// Socket 客户端网关接口
///
///
/// 用于向客户端发送响应消息。
///
private readonly ISocketClientGateway _socketClientGateway;
///
/// 机械手状态管理器
///
///
/// 用于读取和更新机器人的状态。
///
private readonly RobotStateManager _stateManager;
///
/// 缓存服务
///
///
/// 直接使用缓存服务检查状态是否存在。
///
private readonly ICacheService _cache;
///
/// 简单命令处理器
///
///
/// 处理简单的状态更新命令,如运行状态、模式切换等。
///
private readonly IRobotSimpleCommandHandler _simpleCommandHandler;
///
/// 前缀命令处理器
///
///
/// 处理带参数的前缀命令,如 pickfinished(取货完成)、putfinished(放货完成)。
///
private readonly IRobotPrefixCommandHandler _prefixCommandHandler;
///
/// 日志记录器
///
private readonly ILogger _logger;
///
/// 构造函数
///
/// Socket 网关
/// 状态管理器
/// 缓存服务
/// 简单命令处理器
/// 前缀命令处理器
/// 日志记录器
public RobotMessageHandler(
ISocketClientGateway socketClientGateway,
RobotStateManager stateManager,
ICacheService cache,
IRobotSimpleCommandHandler simpleCommandHandler,
IRobotPrefixCommandHandler prefixCommandHandler,
ILogger logger)
{
_socketClientGateway = socketClientGateway;
_stateManager = stateManager;
_cache = cache;
_simpleCommandHandler = simpleCommandHandler;
_prefixCommandHandler = prefixCommandHandler;
_logger = logger;
}
///
/// 处理接收到的消息
///
///
/// 处理流程:
/// 1. 记录日志(记录原始消息内容)
/// 2. 验证缓存中是否存在该设备的状态
/// 3. 尝试用简单命令处理器处理(状态更新类命令)
/// - 如果处理成功,回写原消息并更新状态
/// 4. 如果不是简单命令,检查是否是前缀命令(pickfinished/putfinished)
/// - 如果是,调用前缀命令处理器处理
/// 5. 保持原有行为:简单命令和前缀命令都回写原消息
///
/// 注意:此方法可能在 TCP 消息接收的上下文中被频繁调用,需注意性能。
///
/// 原始消息字符串
/// 消息是否为 JSON 格式(当前未使用)
/// TCP 客户端连接
/// 机器人当前状态
/// 响应消息,如果无需回复则返回 null
public async Task HandleMessageReceivedAsync(string message, bool isJson, TcpClient client, RobotSocketState state)
{
// 记录接收到的消息日志
_logger.LogInformation($"接收到客户端【{state.RobotCrane.DeviceName}】发送消息【{message}】");
QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane.DeviceName);
// 检查任务总数是否未达到上限
if (state.RobotTaskTotalNum > RobotConst.MaxTaskTotalNum)
{
// 记录接收到的消息日志
_logger.LogInformation($"接收到客户端【{state.RobotCrane.DeviceName}】发送消息【{message}】");
QuartzLogger.Info($"接收到客户端消息【{message}】", state.RobotCrane.DeviceName);
// 处理成功后,将原消息回写到客户端(保持原有行为)
await _socketClientGateway.SendMessageAsync(client, message);
return null;
}
// 构建缓存键,检查 Redis 中是否存在该设备的状态
var cacheKey = $"{RedisPrefix.Code}:{RedisName.SocketDevices}:{client.Client.RemoteEndPoint}";
// 如果缓存中不存在或状态为 null,忽略此消息
if (!_cache.TryGetValue(cacheKey, out RobotSocketState? cachedState) || cachedState == null)
{
return null;
}
// 使用缓存中获取的状态
var activeState = cachedState;
// 将消息转换为小写(用于简单命令匹配)
string messageLower = message.ToLowerInvariant();
// 尝试用简单命令处理器处理
// 简单命令包括:homing、homed、running、pausing、runmode、controlmode 等
if (await _simpleCommandHandler.HandleAsync(messageLower, activeState))
{
// 处理成功后,将原消息回写到客户端(保持原有行为)
await _socketClientGateway.SendMessageAsync(client, message);
_logger.LogInformation($"发送消息【{message}】");
QuartzLogger.Info($"发送消息:【{message}】", state.RobotCrane.DeviceName);
// 安全更新状态到 Redis
_stateManager.TryUpdateStateSafely(activeState.IPAddress, activeState);
return null;
}
// 如果不是简单命令,检查是否是前缀命令
// 前缀命令包括:pickfinished、putfinished(后面跟逗号分隔的位置参数)
if (_prefixCommandHandler.IsPrefixCommand(messageLower))
{
// 调用前缀命令处理器
// 前缀命令处理器会解析位置参数并更新状态
await _prefixCommandHandler.HandleAsync(message, activeState, client);
}
// 默认返回 null,不产生响应消息
return null;
}
}
}