package com.ruoyi.sim.service.impl;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.sim.constant.CommConst;
import com.ruoyi.sim.domain.Seat;
import com.ruoyi.sim.domain.Sim;
import com.ruoyi.sim.domain.SimMsg;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
import static com.ruoyi.sim.constant.CommConst.RETRY_COUNT_0;
import static com.ruoyi.sim.constant.CommConst.RETRY_COUNT_QUERY_SN_IMPORTANT;
@Service
public class CommCheckService {
private static final Logger l = LoggerFactory.getLogger(CommCheckService.class);
@Autowired
private SeatService seatService;
@Autowired
private SimService simService;
@Autowired
private CommBuildService commBuildService;
@Autowired
private CommSendService commSendService;
@Autowired
private SocketService socketService;
@Autowired
private CommStrategy commStrategy;
/**
* 等同于ping命令。
*
* @param ipV4
* @return
* @throws IOException
*/
public boolean pingIsReachable(String ipV4) {
InetAddress ia = null;
try {
ia = InetAddress.getByName(ipV4);
return ia.isReachable(CommConst.PING_TIME_OUT);
} catch (UnknownHostException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
/**
* ping路由器得到状态
*
* @param routerIp
* @return
*/
public AjaxResult checkRouterState(final String routerIp) {
if (routerIp == null || StringUtils.isBlank(routerIp)) {
throw new IllegalArgumentException("routerIp isBlank");
}
if (pingIsReachable(routerIp)) {
return AjaxResult.success();
} else {
simService.updateAllEnableState(Sim.State.OFFLINE);
seatService.updateAllEnableState(Seat.SocketState.OFFLINE);
return AjaxResult.error("路由器[" + routerIp + "]无法连接!");
}
}
/**
* pingRS485得到状态
*
* @param rs485Ip
* @return
*/
public AjaxResult checkPingRs485State(final String rs485Ip) {
if (rs485Ip == null || StringUtils.isBlank(rs485Ip)) {
throw new IllegalArgumentException("rs485Ip isBlank");
}
if (pingIsReachable(rs485Ip)) {
return AjaxResult.success();
} else {
// 更新SocketState
seatService.updateSocketStateByRs485Ip(rs485Ip, Seat.SocketState.OFFLINE);
return AjaxResult.error("RS485物联网网关[" + rs485Ip + "]无法连接!");
}
}
public AjaxResult checkPingStudentPcState(final String studentIp) {
if (studentIp == null || StringUtils.isBlank(studentIp)) {
throw new IllegalArgumentException("studentIp isBlank");
}
if (pingIsReachable(studentIp)) {
return AjaxResult.success();
} else {
return AjaxResult.error("学员操作端[" + studentIp + "]无法连接!");
}
}
/**
* 检查一个座次状况。
* 维护 seat表-socket_state字段;
* 维护 seat表-sim_id字段;
* 维护 sim表-Online、Offline状态;
*
* @param seat 座次
* @param important true:重要的场景 开始考试 重试次数不同,也会进行序列号检查。false:不重要场景 定时巡查。
* @return 在线的话,带一个Sim对象出来。离线Sim对象为空。
*/
public AjaxResult checkOneSeatState(final Seat seat, final boolean important) {
// check args.
if (seat == null) {
throw new IllegalArgumentException("seat is null");
}
//
socketService.tryOpenOne(seat.toSimSocketParamVo());
int retryTotalCount;
if (important) {
retryTotalCount = CommConst.RETRY_COUNT_WHICH_SIM_IMPORTANT;
} else {
retryTotalCount = CommConst.RETRY_COUNT_0;
}
SimMsg smS = commBuildService.buildSendMsgWhichSim();
SimMsg smR = commSendService.send(smS, seat, null, retryTotalCount, commStrategy.getSleepShort());
Integer result = smR.getResult();
if (Objects.equals(result, SimMsg.Result.SUCCESS)) {
final String simNum = CommParseUtils.subSimNum(smR.getReceiveMsg());
Sim sim = simService.uniqueBySimNum(simNum);
if (sim == null) {
return AjaxResult.error("找不到模拟器[" + simNum + "]对应数据。");
} else {
l.info("座号[{}]上发现模拟器[{}]", seat.getSeatNum(), sim.getSimNum());
}
// 更新SimId
seatService.updateCurrentSimIdBySeatNum(seat.getSeatNum(), sim.getSimId());
// 更新Sim状态
simService.updateSimStateBySimId(sim.getSimId(), Sim.State.ONLINE);
// 查询出最新的Sim对象
sim = simService.uniqueBySimNum(simNum);
//
String msgTemp = "座号[{0}]-模拟器[{1}]型[{2}]在线";
String msg = MessageFormat.format(msgTemp, seat.getSeatNum(), Sim.TYPE_NAME_MAP.get(sim.getSimType()), sim.getSimNum());
// 成功的话,Obj为Sim对象。
return AjaxResult.success(msg, sim);
} else if (Objects.equals(result, SimMsg.Result.RECEIVE_CHECK_FAIL)) {
return smR.getDefaultErrorAR();
} else if (Objects.equals(result, SimMsg.Result.READ_TIMEOUT_EXCEPTION)) {
// 更新SimId
seatService.updateCurrentSimIdBySeatNum(seat.getSeatNum(), Sim.ID_0);
String msgTemp = "座号[{0}]-没有连接任何接模拟器,检查线缆连接和线缆开关";
String msg = MessageFormat.format(msgTemp, seat.getSeatNum());
// 失败的话,Obj为空。
return AjaxResult.success(msg, null);
} else if (Objects.equals(result, SimMsg.Result.RECEIVE_NOT_MATCH)) {
return smR.getDefaultErrorAR();
}
return AjaxResult.error("检查座次模拟器失败!", null);
}
/**
* 纯数据库查询,模拟器是否在线。
* 模拟器是否被禁用。
*
* @param simId
* @return
*/
public AjaxResult checkOneSimOnlineState(final Long simId) {
if (simId == null || simId <= 0) {
return AjaxResult.error("没有连接任何接模拟器,
检查线缆连接和线缆开关!");
}
Sim sim = simService.selectSimBySimId(simId);
if (sim != null) {
switch (sim.getSimState()) {
case Sim.State.ONLINE: {
return AjaxResult.success("模拟器[" + sim.getSimNum() + "]在线!");
}
case Sim.State.OFFLINE: {
return AjaxResult.success("模拟器[" + sim.getSimNum() + "]离线!");
}
case Sim.State.DISABLE: {
return AjaxResult.error("模拟器[" + sim.getSimNum() + "]禁用!");
}
}
}
return AjaxResult.error("模拟器[" + Objects.requireNonNull(sim).getSimNum() + "]XXXX!");
}
/**
* 默认Seat中已经有CurrentSimId数据
* 检查回应报文模拟器类型是否正确。
*
* @param seat 座次
* @param important
* @param targetSimType 期望模拟器目标类型
* @return
*/
public AjaxResult checkOneSimType(final Seat seat, final boolean important, final String targetSimType) {
// check args.
if (seat == null) {
throw new IllegalArgumentException("seat is null");
}
if (seat.getCurrentSimId() == null || Sim.ID_0.equals(seat.getCurrentSimId())) {
throw new IllegalArgumentException("sim id is 0");
}
if (!simService.existBySimId(seat.getCurrentSimId())) {
return AjaxResult.error("模拟器ID[" + seat.getCurrentSimId() + "]不存在!");
}
//
final String msgErrorTemp = "连接模拟器类型或序列号不正确!
应该连接模拟器型号:
";
final String msgOk = "连接模拟器类型或序列号正确!";
int retryTotalCount;
if (important) {
retryTotalCount = RETRY_COUNT_QUERY_SN_IMPORTANT;
} else {
retryTotalCount = RETRY_COUNT_0;
}
Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
SimMsg smS = commBuildService.buildSendMsgReadSimType(sim.getSimNum());
SimMsg smR = commSendService.send(smS, seat, sim, retryTotalCount, commStrategy.getSleepShort());
if (StringUtils.isNotBlank(smR.getReceiveMsg())) {
final String content = CommParseUtils.subContentData(smR);
switch (targetSimType) {
case Sim.TYPE_0001 -> {
if (content.startsWith(CommConst.TYPE_0001_SN_PREFIX) && content.endsWith(sim.getSimNum())) {
return AjaxResult.success(msgOk);
} else {
return AjaxResult.error(msgErrorTemp + Sim.TYPE_NAME_MAP.get(targetSimType));
}
}
case Sim.TYPE_0002 -> {
if (content.startsWith(CommConst.TYPE_0002_SN_PREFIX) && content.endsWith(sim.getSimNum())) {
return AjaxResult.success(msgOk);
} else {
return AjaxResult.error(msgErrorTemp + Sim.TYPE_NAME_MAP.get(targetSimType));
}
}
case Sim.TYPE_0003 -> {
if (content.startsWith(CommConst.TYPE_0003_SN_PREFIX) && content.endsWith(sim.getSimNum())) {
return AjaxResult.success(msgOk);
} else {
return AjaxResult.error(msgErrorTemp + Sim.TYPE_NAME_MAP.get(targetSimType));
}
}
default -> throw new IllegalStateException("Unexpected value: " + targetSimType);
}
}
return AjaxResult.error("失败,检查一个模拟器[" + sim.getSimNum() + "]型号或序列号执行错误!
请检查模拟器线缆连接情况和连接模拟器型号!");
}
/**
* 默认Seat中已经有CurrentSimId数据
*
* @param seat
* @param important
* @return
*/
@Transactional
public AjaxResult checkOneSimOnlineState(final Seat seat, final boolean important) {
// check args.
if (seat == null) {
throw new IllegalArgumentException("seat is null");
}
if (seat.getCurrentSimId() == null || Sim.ID_0.equals(seat.getCurrentSimId())) {
return AjaxResult.error("模拟器ID不存在!");
}
if (!simService.existBySimId(seat.getCurrentSimId())) {
return AjaxResult.error("模拟器ID[" + seat.getCurrentSimId() + "]不存在!");
}
//
int retryTotalCount;
if (important) {
retryTotalCount = RETRY_COUNT_QUERY_SN_IMPORTANT;
} else {
retryTotalCount = RETRY_COUNT_0;
}
Sim sim = simService.selectSimBySimId(seat.getCurrentSimId());
SimMsg smS02 = commBuildService.buildSendMsgReadSimType(sim.getSimNum());
SimMsg smR02 = commSendService.send(smS02, seat, sim, retryTotalCount, commStrategy.getSleepShort());
if (StringUtils.isNotBlank(smR02.getReceiveMsg())) {
// 只要返回正确报文,即认为在线。
simService.updateSimStateBySimId(sim.getSimId(), Sim.State.ONLINE);
socketService.failedReset0(seat.toSimSocketParamVo());
return AjaxResult.success("成功,检查一个模拟器[" + sim.getSimNum() + "]OK!");
}
return AjaxResult.error("失败,检查一个模拟器[" + sim.getSimNum() + "]在线状态执行错误!");
}
/**
* [定时执行]查找所有没有被手动禁用的座次 和 座次上的模拟器。
*/
public AjaxResult checkAllSeatAndSimState() {
List list = seatService.listAllEnable();
list.forEach(seat -> {
checkOneSeatState(seat, false);
// checkOneSimState(seat, false);
});
return AjaxResult.success("检查完毕,成功!");
}
}