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; /** * [类的简要说明] *

* [详细描述,可选] *

* * @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> actionMap = new ConcurrentSkipListMap<>(); //日期格式化 private DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); //房间中关联的任务管理器 private Map 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> 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 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)); } } } }