simulation-backend/src/main/java/com/hivekion/room/bean/Room.java
2025-09-20 14:56:17 +08:00

237 lines
6.4 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.hivekion.room.bean;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson2.JSON;
import com.hivekion.Global;
import com.hivekion.baseData.entity.Scenario;
import com.hivekion.common.entity.ResponseCmdInfo;
import com.hivekion.common.redis.RedisUtil;
import com.hivekion.common.utils;
import com.hivekion.common.uuid.IdUtils;
import com.hivekion.room.func.TaskAction;
import com.hivekion.scenario.bean.ScenarioWsParam;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import com.hivekion.scenario.entity.ScenarioResource;
import com.hivekion.statistic.bean.ScenarioInfo;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
/**
* [类的简要说明]
* <p>
* [详细描述,可选]
* <p>
*
* @author LiDongYU
* @since 2025/7/22
*/
@Data
@Slf4j
public class Room implements AutoCloseable {
private AtomicBoolean status = new AtomicBoolean(false);
/**
* 任务管理相关
*/
private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private ScheduledFuture<?> future;
/**
* 房间ID
*/
private String roomId;
/**
* 想定信息
*/
private Scenario scenario;
private RedisUtil redisUtil;
private com.hivekion.statistic.service.ScenarioService scenarioService;
/**
* 任务容器
*/
private NavigableMap<Long, Map<String, TaskAction>> actionMap = new ConcurrentSkipListMap<>();
//日期格式化
private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
//房间中关联的任务管理器
private Map<String, ScheduledExecutorService> futures = new ConcurrentHashMap<>();
//线程池
private final ExecutorService actionExecutor =
new ThreadPoolExecutor(
5, 100, // corePoolSize, maximumPoolSize
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(1000), // 有界队列只允许100个待执行任务
new ThreadPoolExecutor.AbortPolicy() // 超出直接抛异常
);
public Room(String roomId, Scenario scenario) {
this.roomId = roomId;
this.scenario = scenario;
}
/**
* 持续时间
*/
private AtomicLong duringTime = new AtomicLong(0);
private AtomicLong totalTime = new AtomicLong(0);
private int mag = 1;
/**
* 启动
*
* @param time 总时间
*/
public void start(long time) {
status.set(true);
totalTime.set(time);
startTask();
//初始化系统资源 物资人员等信息
initRoomParam();
}
/**
* 停止
*/
public void stop() {
status.set(false);
cancelTask();
futures.forEach((key, value) -> {
try {
if (!value.isShutdown()) {
value.shutdownNow();
}
} catch (Exception e) {
log.error("error::", e);
}
});
}
/**
* 暂停
*/
public void pause() {
status.set(false);
cancelTask();
}
public void resume() {
status.set(true);
startTask();
}
public long getDuringTime() {
return duringTime.get();
}
// 启动定时任务
private void startTask() {
if (future == null || future.isCancelled()) {
future = scheduler.scheduleAtFixedRate(() -> {
ScenarioWsParam magValue = Global.roomParamMap.get(
this.scenario.getId() + "_" + this.roomId);
if (magValue != null) {
this.mag = magValue.getMag();
}
long curTime = duringTime.addAndGet(this.mag);
sendRemainTime((totalTime.get() - curTime));
NavigableMap<Long, Map<String, TaskAction>> actions = actionMap.headMap(curTime, true);
if (!actions.isEmpty()) {
actions.forEach((key, action) -> {
action.forEach((taskAction, task) -> {
actionExecutor.submit(task::doSomeThing);
});
});
actions.clear();
}
}, 0, 1, TimeUnit.SECONDS);
}
}
// 取消定时任务
private void cancelTask() {
if (future != null && !future.isCancelled()) {
future.cancel(true);
}
}
public void addAction(long time, TaskAction action) {
actionMap.computeIfAbsent(time, k -> new ConcurrentHashMap<>())
.put(IdUtils.simpleUUID(), action);
}
@Override
public void close() throws Exception {
actionMap.clear();
if (future != null && !future.isCancelled()) {
future.cancel(true);
}
if (scheduler != null && !scheduler.isShutdown()) {
scheduler.shutdown();
}
}
private void sendRemainTime(long remainTime) {
Map<String, Object> timeMap = new HashMap<>();
timeMap.put("update_time_str", utils.formatSeconds(remainTime));
timeMap.put("remain_time", remainTime);
timeMap.put("during_time", duringTime.get());
timeMap.put("current_time",
df.format(this.scenario.getStartTime().plusSeconds(duringTime.get())));
Global.sendCmdInfoQueue.add(
ResponseCmdInfo.create("update_time", this.roomId, this.scenario.getId(),
timeMap));
}
public void addTaskReference(ScheduledExecutorService scheduledExecutorService) {
futures.put(IdUtils.simpleUUID(), scheduledExecutorService);
}
public boolean isRunning() {
return status.get();
}
public void initRoomParam(){
if( scenarioService == null) {
scenarioService = SpringUtil.getBean(com.hivekion.statistic.service.ScenarioService.class);
}
for(ScenarioResource scenarioResource:this.scenario.getResourceList() ){
ScenarioInfo scenarioInfo = scenarioService.listScenarioInfo(scenarioResource.getScenarioId(),roomId,scenarioResource.getId());
if( redisUtil == null){
redisUtil = SpringUtil.getBean(RedisUtil.class);
redisUtil.hset(scenarioResource.getScenarioId() + "-" + roomId + "-" + scenarioResource.getId(),"scenarioInfo", JSON.toJSONString(scenarioInfo));
}else{
redisUtil.hset(scenarioResource.getScenarioId() + "-" + roomId + "-" + scenarioResource.getId(),"scenarioInfo",JSON.toJSONString(scenarioInfo));
}
}
}
}