package com.zy.acs.manager.fake;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.zy.acs.common.constant.RedisConstant;
|
import com.zy.acs.common.domain.AgvProtocol;
|
import com.zy.acs.common.domain.protocol.AGV_01_DOWN;
|
import com.zy.acs.common.domain.protocol.AGV_01_UP;
|
import com.zy.acs.common.utils.RedisSupport;
|
import com.zy.acs.framework.common.Cools;
|
import com.zy.acs.manager.core.service.MainService;
|
import com.zy.acs.manager.core.service.MapService;
|
import com.zy.acs.manager.manager.entity.Action;
|
import com.zy.acs.manager.manager.entity.Agv;
|
import com.zy.acs.manager.manager.enums.ActionStsType;
|
import com.zy.acs.manager.manager.enums.StatusType;
|
import com.zy.acs.manager.manager.service.*;
|
import com.zy.acs.manager.system.service.ConfigService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
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
|
*/
|
@Slf4j
|
@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 AgvDetailService agvDetailService;
|
@Autowired
|
private ActionService actionService;
|
@Autowired
|
private ConfigService configService;
|
@Autowired
|
private CodeService codeService;
|
@Autowired
|
private MapService mapService;
|
@Autowired
|
private JamService jamService;
|
@Autowired
|
private MainService mainService;
|
|
@PostConstruct
|
public void init() {
|
// heartBeat
|
this.heartBeatThread = new Thread(() -> {
|
while (!Thread.currentThread().isInterrupted()) {
|
try {
|
Thread.sleep(1000);
|
|
if (configService.getVal("fakeSign", Boolean.class)) {
|
this.processOnline();
|
}
|
|
} 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(10);
|
|
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
|
, mainService
|
, actionList
|
));
|
}
|
}
|
|
}
|
|
} else {
|
this.shutdownFakeThreads();
|
}
|
|
} catch (Exception e) {
|
log.error("FakeProcessor.simulatorTread fail", e);
|
}
|
}
|
});
|
this.simulatorTread.start();
|
}
|
|
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) {
|
AGV_01_DOWN agv_01_down = (AGV_01_DOWN) protocol.getMessageBody();
|
|
AGV_01_UP agv_01_up = new AGV_01_UP();
|
agv_01_up.setSerialNo(agv_01_down.getSerialNo());
|
|
redis.setObject(RedisConstant.AGV_PATH_UP_FLAG
|
, protocol.getAgvNo() + "_" + agv_01_up.getSerialNo()
|
, agv_01_up);
|
}
|
}
|
|
public List<Agv> getAgvList() {
|
if (Cools.isEmpty(this.agvList)) {
|
this.agvList = agvService.list(new LambdaQueryWrapper<Agv>().eq(Agv::getStatus, StatusType.ENABLE.val));
|
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();
|
}
|
|
|
}
|