2025-12-16 14:37:16 +08:00
|
|
|
|
package com.tuoheng.machine.service;
|
2025-12-16 13:56:36 +08:00
|
|
|
|
|
2025-12-16 15:51:07 +08:00
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
|
|
2025-12-16 14:37:16 +08:00
|
|
|
|
import com.tuoheng.machine.events.DrcEvent;
|
|
|
|
|
|
import com.tuoheng.machine.redis.RedisStateStore;
|
|
|
|
|
|
import com.tuoheng.machine.status.DrcState;
|
2025-12-16 13:56:36 +08:00
|
|
|
|
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状态机实例
|
|
|
|
|
|
*/
|
2025-12-16 15:51:07 +08:00
|
|
|
|
@Slf4j
|
2025-12-16 13:56:36 +08:00
|
|
|
|
@Component
|
|
|
|
|
|
public class DrcMachineService {
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
StateMachineFactory<DrcState, DrcEvent> drcStateMachineFactory;
|
|
|
|
|
|
|
|
|
|
|
|
@Autowired
|
|
|
|
|
|
private RedisStateStore redisStateStore;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 存储所有机巢的DRC状态机实例
|
|
|
|
|
|
* Key: 机巢ID (airportSn)
|
|
|
|
|
|
* Value: 状态机实例
|
|
|
|
|
|
*/
|
|
|
|
|
|
private final Map<String, StateMachine<DrcState, DrcEvent>> stateMachineMap = new ConcurrentHashMap<>();
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取或创建状态机
|
|
|
|
|
|
* 如果状态机不存在,则创建新的状态机实例
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
* @return 状态机实例
|
|
|
|
|
|
*/
|
|
|
|
|
|
public StateMachine<DrcState, DrcEvent> getOrCreateStateMachine(String airportSn) {
|
|
|
|
|
|
return stateMachineMap.computeIfAbsent(airportSn, id -> {
|
|
|
|
|
|
StateMachine<DrcState, DrcEvent> stateMachine = drcStateMachineFactory.getStateMachine(id);
|
|
|
|
|
|
// 服务器重启后,状态机初始化为 UNKNOWN 状态
|
|
|
|
|
|
// 不从 Redis 恢复旧状态,等待第一次心跳同步真实状态
|
|
|
|
|
|
// 这样可以避免服务器重启期间丢失心跳导致的状态不一致问题
|
|
|
|
|
|
stateMachine.start();
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.info("创建并启动DRC状态机: %s, 初始状态: UNKNOWN (等待心跳同步)", id);
|
2025-12-16 13:56:36 +08:00
|
|
|
|
return stateMachine;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取状态机(不创建)
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
* @return 状态机实例,如果不存在返回null
|
|
|
|
|
|
*/
|
|
|
|
|
|
public StateMachine<DrcState, DrcEvent> getStateMachine(String airportSn) {
|
|
|
|
|
|
return stateMachineMap.get(airportSn);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取状态机的当前状态
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
* @return 当前状态,如果状态机不存在返回null
|
|
|
|
|
|
*/
|
|
|
|
|
|
public DrcState getCurrentState(String airportSn) {
|
|
|
|
|
|
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.get(airportSn);
|
|
|
|
|
|
if (stateMachine == null) {
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.info("DRC状态机不存在: {}", airportSn);
|
2025-12-16 13:56:36 +08:00
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
return stateMachine.getState().getId();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取状态机的所有当前状态(包括子状态)
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
* @return 当前状态集合的字符串表示
|
|
|
|
|
|
*/
|
|
|
|
|
|
public String getCurrentStates(String airportSn) {
|
|
|
|
|
|
StateMachine<DrcState, DrcEvent> 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<DrcState, DrcEvent> stateMachine = getOrCreateStateMachine(airportSn);
|
|
|
|
|
|
boolean result = stateMachine.sendEvent(event);
|
|
|
|
|
|
|
|
|
|
|
|
if (result) {
|
|
|
|
|
|
// 持久化最新状态
|
|
|
|
|
|
redisStateStore.saveDrcState(airportSn, stateMachine.getState().getId());
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.info("DRC事件发送成功 - 机巢: {}, 事件: {}, 当前状态: {}",
|
|
|
|
|
|
airportSn, event, getCurrentStates(airportSn));
|
2025-12-16 13:56:36 +08:00
|
|
|
|
} else {
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.error("DRC事件发送失败 - 机巢: {}, 事件: {}, 当前状态: {}",
|
|
|
|
|
|
airportSn, event, getCurrentStates(airportSn));
|
2025-12-16 13:56:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 移除状态机
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
*/
|
|
|
|
|
|
public void removeStateMachine(String airportSn) {
|
|
|
|
|
|
StateMachine<DrcState, DrcEvent> stateMachine = stateMachineMap.remove(airportSn);
|
|
|
|
|
|
if (stateMachine != null) {
|
|
|
|
|
|
stateMachine.stop();
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.info("停止并移除DRC状态机: {}", airportSn);
|
2025-12-16 13:56:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查状态机是否存在
|
|
|
|
|
|
*
|
|
|
|
|
|
* @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<String> getAllAirportIds() {
|
|
|
|
|
|
return stateMachineMap.keySet();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 检查状态机是否处于指定状态
|
|
|
|
|
|
*
|
|
|
|
|
|
* @param airportSn 机巢序列号
|
|
|
|
|
|
* @param state 要检查的状态
|
|
|
|
|
|
* @return 是否处于指定状态
|
|
|
|
|
|
*/
|
|
|
|
|
|
public boolean isInState(String airportSn, DrcState state) {
|
|
|
|
|
|
StateMachine<DrcState, DrcEvent> 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);
|
2025-12-16 15:51:07 +08:00
|
|
|
|
log.info("重启DRC状态机: {}", airportSn);
|
2025-12-16 13:56:36 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|