|  |  | 
 |  |  | import org.springframework.scheduling.annotation.Scheduled; | 
 |  |  | import org.springframework.stereotype.Component; | 
 |  |  |  | 
 |  |  | import javax.annotation.PostConstruct; | 
 |  |  | import javax.annotation.PreDestroy; | 
 |  |  | import java.util.ArrayList; | 
 |  |  | import java.util.List; | 
 |  |  | import java.util.Map; | 
 |  |  | import java.util.concurrent.ConcurrentHashMap; | 
 |  |  | import java.util.concurrent.ExecutorService; | 
 |  |  | import java.util.concurrent.Executors; | 
 |  |  | import java.util.concurrent.TimeUnit; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * Created by vincent on 11/9/2024 | 
 |  |  | 
 |  |  | @Component | 
 |  |  | public class FakeProcessor { | 
 |  |  |  | 
 |  |  |  | 
 |  |  |     private final RedisSupport redis = RedisSupport.defaultRedisSupport; | 
 |  |  |  | 
 |  |  |     public static final Map<Long, Boolean> AGV_PROCESSING_MAP = new ConcurrentHashMap<>(); | 
 |  |  |  | 
 |  |  |     private ExecutorService executorService; | 
 |  |  |  | 
 |  |  |     private List<Agv> agvList = new ArrayList<>(); | 
 |  |  |  | 
 |  |  |     private Thread heartBeatThread; | 
 |  |  |  | 
 |  |  |     private Thread responseThread; | 
 |  |  |  | 
 |  |  |     private Thread simulatorTread; | 
 |  |  |  | 
 |  |  |     @Autowired | 
 |  |  |     private AgvService agvService; | 
 |  |  | 
 |  |  |     @Autowired | 
 |  |  |     private JamService jamService; | 
 |  |  |  | 
 |  |  |     /** | 
 |  |  |      * 1.AgvDataService.dataProcess [ agvDetail: vol, code, agvAngle, agvStatus ] | 
 |  |  |      * 2.MainService.upDataSubscribe | 
 |  |  |      * 3.AgvCmdService.executeRequest {@link com.zy.acs.manager.core.service.AgvCmdService#executeAgvActionCmd} | 
 |  |  |      * 4.AgvServiceImpl.judgeOnline | 
 |  |  |      * 5. | 
 |  |  |      */ | 
 |  |  |     @Scheduled(cron = "0/1 * * * * ? ") | 
 |  |  |     public void process() { | 
 |  |  |         Boolean fakeSign = configService.getVal("fakeSign", Boolean.class); | 
 |  |  |         if (null == fakeSign || !fakeSign) { | 
 |  |  |             return; | 
 |  |  |         } | 
 |  |  |     @PostConstruct | 
 |  |  |     public void init() { | 
 |  |  |         // heartBeat | 
 |  |  |         this.heartBeatThread = new Thread(() -> { | 
 |  |  |             while (!Thread.currentThread().isInterrupted()) { | 
 |  |  |                 try { | 
 |  |  |                     Thread.sleep(1000); | 
 |  |  |  | 
 |  |  |         List<Agv> agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1)); | 
 |  |  |         // init executorService | 
 |  |  |         if (null == this.executorService) { | 
 |  |  |             int count = agvList.size(); | 
 |  |  |             this.executorService = Executors.newFixedThreadPool(count); | 
 |  |  |         } | 
 |  |  |                     if (configService.getVal("fakeSign", Boolean.class)) { | 
 |  |  |                         this.processOnline(); | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |         this.responseTheRequest(); | 
 |  |  |  | 
 |  |  |         for (Agv agv : agvList) { | 
 |  |  |             AGV_PROCESSING_MAP.putIfAbsent(agv.getId(), false); | 
 |  |  |  | 
 |  |  |             this.processOnline(agv); | 
 |  |  |  | 
 |  |  |             if (!AGV_PROCESSING_MAP.get(agv.getId())) { | 
 |  |  |                 List<Action> actionList = actionService.queryLatestGroup(agv.getId(), ActionStsType.ISSUED); | 
 |  |  |                 if (!Cools.isEmpty(actionList)) { | 
 |  |  |                     executorService.submit(new AgvSimulatorTask( | 
 |  |  |                             agv | 
 |  |  |                             , redis | 
 |  |  |                             , agvDetailService | 
 |  |  |                             , actionService | 
 |  |  |                             , codeService | 
 |  |  |                             , mapService | 
 |  |  |                             , jamService | 
 |  |  |                             , actionList | 
 |  |  |                     )); | 
 |  |  |                 } catch (Exception e) { | 
 |  |  |                     log.error("FakeProcessor.heartBeatThread fail", e); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         }); | 
 |  |  |         this.heartBeatThread.start(); | 
 |  |  |  | 
 |  |  |         } | 
 |  |  |         // response the request | 
 |  |  |         this.responseThread = new Thread(() -> { | 
 |  |  |             while (!Thread.currentThread().isInterrupted()) { | 
 |  |  |                 try { | 
 |  |  |                     Thread.sleep(30); | 
 |  |  |  | 
 |  |  |                     if (configService.getVal("fakeSign", Boolean.class)) { | 
 |  |  |                         this.responseTheRequest(); | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |                 } catch (Exception e) { | 
 |  |  |                     log.error("FakeProcessor.responseThread fail", e); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         }); | 
 |  |  |         this.responseThread.start(); | 
 |  |  |  | 
 |  |  |         /** | 
 |  |  |          * 1.AgvDataService.dataProcess [ agvDetail: vol, code, agvAngle, agvStatus ] | 
 |  |  |          * 2.MainService.upDataSubscribe | 
 |  |  |          * 3.AgvCmdService.executeRequest {@link com.zy.acs.manager.core.service.AgvCmdService#executeAgvActionCmd} | 
 |  |  |          * 4.AgvServiceImpl.judgeOnline | 
 |  |  |          */ | 
 |  |  |         // Simulator | 
 |  |  |         this.simulatorTread = new Thread(() -> { | 
 |  |  |             while (!Thread.currentThread().isInterrupted()) { | 
 |  |  |                 try { | 
 |  |  |                     Thread.sleep(30); | 
 |  |  |  | 
 |  |  |                     if (configService.getVal("fakeSign", Boolean.class)) { | 
 |  |  |  | 
 |  |  |                         List<Agv> agvList = this.getAgvList(); | 
 |  |  |                         if (null == this.executorService) { | 
 |  |  |                             int count = agvList.size(); | 
 |  |  |                             this.executorService = Executors.newFixedThreadPool(count); | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                         for (Agv agv : agvList) { | 
 |  |  |  | 
 |  |  |                             if (!AGV_PROCESSING_MAP.get(agv.getId())) { | 
 |  |  |                                 List<Action> actionList = actionService.queryLatestGroup(agv.getId(), ActionStsType.ISSUED); | 
 |  |  |                                 if (!Cools.isEmpty(actionList)) { | 
 |  |  |                                     AGV_PROCESSING_MAP.put(agv.getId(), true); | 
 |  |  |                                     executorService.submit(new AgvSimulatorTask( | 
 |  |  |                                             agv | 
 |  |  |                                             , redis | 
 |  |  |                                             , agvDetailService | 
 |  |  |                                             , actionService | 
 |  |  |                                             , codeService | 
 |  |  |                                             , mapService | 
 |  |  |                                             , jamService | 
 |  |  |                                             , actionList | 
 |  |  |                                     )); | 
 |  |  |                                 } | 
 |  |  |                             } | 
 |  |  |  | 
 |  |  |                         } | 
 |  |  |  | 
 |  |  |                     } else { | 
 |  |  |                         this.shutdownFakeThreads(); | 
 |  |  |                     } | 
 |  |  |  | 
 |  |  |                 } catch (Exception e) { | 
 |  |  |                     log.error("FakeProcessor.simulatorTread fail", e); | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         }); | 
 |  |  |         this.simulatorTread.start(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void processOnline(Agv agv) { | 
 |  |  |         redis.setObject(RedisConstant.AGV_ONLINE_FLAG, agv.getUuid(), 1, 30); | 
 |  |  |     private void processOnline() { | 
 |  |  |         for (Agv agv : this.getAgvList()) { | 
 |  |  |             redis.setObject(RedisConstant.AGV_ONLINE_FLAG, agv.getUuid(), 1, 30); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     private void responseTheRequest() { | 
 |  |  |         AgvProtocol protocol = redis.pop(RedisConstant.AGV_PATH_DOWN_FLAG); | 
 |  |  |         if (null != protocol) { | 
 |  |  |             try { | 
 |  |  |                 Thread.sleep(100); | 
 |  |  |             } catch (InterruptedException ignore) {} | 
 |  |  |  | 
 |  |  |             AGV_01_DOWN agv_01_down = (AGV_01_DOWN) protocol.getMessageBody(); | 
 |  |  |  | 
 |  |  |             AGV_01_UP agv_01_up = new AGV_01_UP(); | 
 |  |  | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public List<Agv> getAgvList() { | 
 |  |  |         if (Cools.isEmpty(this.agvList)) { | 
 |  |  |             this.agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, 1)); | 
 |  |  |             this.agvList.forEach(agv -> {AGV_PROCESSING_MAP.putIfAbsent(agv.getId(), false);}); | 
 |  |  |         } | 
 |  |  |         return this.agvList; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public void shutdownFakeThreads() { | 
 |  |  |         if (this.executorService != null && !this.executorService.isShutdown()) { | 
 |  |  |             this.executorService.shutdown(); | 
 |  |  |             try { | 
 |  |  |                 if (!this.executorService.awaitTermination(60, TimeUnit.SECONDS)) { | 
 |  |  |                     this.executorService.shutdownNow(); | 
 |  |  |                 } | 
 |  |  |             } catch (InterruptedException e) { | 
 |  |  |                 this.executorService.shutdownNow(); | 
 |  |  |                 Thread.currentThread().interrupt(); | 
 |  |  |             } | 
 |  |  |             this.executorService = null; // 释放资源 | 
 |  |  |         } | 
 |  |  |         if (!Cools.isEmpty(this.agvList)) { | 
 |  |  |             agvList = new ArrayList<>(); | 
 |  |  |         } | 
 |  |  |         if (!AGV_PROCESSING_MAP.isEmpty()) { | 
 |  |  |             AGV_PROCESSING_MAP.clear(); | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     @PreDestroy | 
 |  |  |     public void shutDown(){ | 
 |  |  |         if (this.heartBeatThread != null) { | 
 |  |  |             this.heartBeatThread .interrupt(); | 
 |  |  |         } | 
 |  |  |         if (this.responseThread != null) { | 
 |  |  |             this.responseThread .interrupt(); | 
 |  |  |         } | 
 |  |  |         if (this.simulatorTread != null) { | 
 |  |  |             this.simulatorTread.interrupt(); | 
 |  |  |         } | 
 |  |  |         this.shutdownFakeThreads(); | 
 |  |  |     } | 
 |  |  |  | 
 |  |  | } |