simulation-backend/src/main/java/com/hivekion/room/bean/Room.java
2025-09-19 16:13:10 +08:00

199 lines
5.0 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 com.hivekion.Global;
import com.hivekion.baseData.entity.Scenario;
import com.hivekion.common.entity.ResponseCmdInfo;
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 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 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();
}
/**
* 停止
*/
public void stop() {
status.set(false);
cancelTask();
}
/**
* 暂停
*/
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();
}
}