package com.tuoheng.machine.service; import lombok.extern.slf4j.Slf4j; import com.tuoheng.machine.events.DrcEvent; import com.tuoheng.machine.redis.RedisStateStore; import com.tuoheng.machine.status.DrcState; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.statemachine.StateMachine; import org.springframework.statemachine.config.StateMachineFactory; import org.springframework.stereotype.Component; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * DRC状态机管理器 * 负责管理多个机巢的DRC状态机实例 */ @Slf4j @Component public class DrcMachineService { @Autowired StateMachineFactory drcStateMachineFactory; @Autowired private RedisStateStore redisStateStore; /** * 存储所有机巢的DRC状态机实例 * Key: 机巢ID (airportSn) * Value: 状态机实例 */ private final Map> stateMachineMap = new ConcurrentHashMap<>(); /** * 获取或创建状态机 * 如果状态机不存在,则创建新的状态机实例 * * @param airportSn 机巢序列号 * @return 状态机实例 */ public StateMachine getOrCreateStateMachine(String airportSn) { return stateMachineMap.computeIfAbsent(airportSn, id -> { StateMachine stateMachine = drcStateMachineFactory.getStateMachine(id); // 服务器重启后,状态机初始化为 UNKNOWN 状态 // 不从 Redis 恢复旧状态,等待第一次心跳同步真实状态 // 这样可以避免服务器重启期间丢失心跳导致的状态不一致问题 stateMachine.start(); log.info("创建并启动DRC状态机: %s, 初始状态: UNKNOWN (等待心跳同步)", id); return stateMachine; }); } /** * 获取状态机(不创建) * * @param airportSn 机巢序列号 * @return 状态机实例,如果不存在返回null */ public StateMachine getStateMachine(String airportSn) { return stateMachineMap.get(airportSn); } /** * 获取状态机的当前状态 * * @param airportSn 机巢序列号 * @return 当前状态,如果状态机不存在返回null */ public DrcState getCurrentState(String airportSn) { StateMachine stateMachine = stateMachineMap.get(airportSn); if (stateMachine == null) { log.info("DRC状态机不存在: {}", airportSn); return null; } return stateMachine.getState().getId(); } /** * 获取状态机的所有当前状态(包括子状态) * * @param airportSn 机巢序列号 * @return 当前状态集合的字符串表示 */ public String getCurrentStates(String airportSn) { StateMachine stateMachine = stateMachineMap.get(airportSn); if (stateMachine == null) { return "状态机不存在"; } StringBuilder states = new StringBuilder(); stateMachine.getState().getIds().forEach(state -> { if (states.length() > 0) { states.append(" -> "); } states.append(state); }); return states.toString(); } /** * 发送事件到状态机 * * @param airportSn 机巢序列号 * @param event 事件 * @return 是否发送成功 */ public boolean sendEvent(String airportSn, DrcEvent event) { StateMachine stateMachine = getOrCreateStateMachine(airportSn); boolean result = stateMachine.sendEvent(event); if (result) { // 持久化最新状态 redisStateStore.saveDrcState(airportSn, stateMachine.getState().getId()); log.info("DRC事件发送成功 - 机巢: {}, 事件: {}, 当前状态: {}", airportSn, event, getCurrentStates(airportSn)); } else { log.error("DRC事件发送失败 - 机巢: {}, 事件: {}, 当前状态: {}", airportSn, event, getCurrentStates(airportSn)); } return result; } /** * 移除状态机 * * @param airportSn 机巢序列号 */ public void removeStateMachine(String airportSn) { StateMachine stateMachine = stateMachineMap.remove(airportSn); if (stateMachine != null) { stateMachine.stop(); log.info("停止并移除DRC状态机: {}", airportSn); } } /** * 检查状态机是否存在 * * @param airportSn 机巢序列号 * @return 是否存在 */ public boolean hasStateMachine(String airportSn) { return stateMachineMap.containsKey(airportSn); } /** * 获取所有状态机的数量 * * @return 状态机数量 */ public int getStateMachineCount() { return stateMachineMap.size(); } /** * 获取所有机巢ID * * @return 机巢ID集合 */ public java.util.Set getAllAirportIds() { return stateMachineMap.keySet(); } /** * 检查状态机是否处于指定状态 * * @param airportSn 机巢序列号 * @param state 要检查的状态 * @return 是否处于指定状态 */ public boolean isInState(String airportSn, DrcState state) { StateMachine stateMachine = stateMachineMap.get(airportSn); if (stateMachine == null) { return false; } return stateMachine.getState().getIds().contains(state); } /** * 重启状态机 * * @param airportSn 机巢序列号 */ public void restartStateMachine(String airportSn) { removeStateMachine(airportSn); getOrCreateStateMachine(airportSn); log.info("重启DRC状态机: {}", airportSn); } }