package com.dy.pipIrrRemote.monitor; import com.alibaba.fastjson2.JSONObject; import com.dy.common.aop.SsoAop; import com.dy.common.mw.protocol.Command; import com.dy.common.util.IDLongGenerator; import com.dy.common.util.NumUtil; import com.dy.common.webUtil.BaseResponse; import com.dy.common.webUtil.BaseResponseUtils; import com.dy.pipIrrGlobal.command.ComResultWait; import com.dy.pipIrrGlobal.pojoPr.PrController; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.env.Environment; import org.springframework.http.MediaType; import org.springframework.validation.BindingResult; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; /** * @Author: liurunyu * @Date: 2025/4/30 16:08 * @Description */ @Slf4j @Tag(name = "远程透传命令", description = "远程透传命令") @RestController @RequestMapping(path = "comTrans") @RequiredArgsConstructor public class ComTransCtrl { @Autowired private Environment env ; @Autowired private RestTemplate restTemplate ; @Value("${mw.waitMwRtnResultTimeout}") private int waitMwRtnResultTimeout ; @Value("${mw.rtuCallbackUrl_rm}") private String rtuResultSendWebUrl; @Autowired private ComTransSv comSv; /** * 向设备(控制器)发送透传命令 * @param dto 前端发来的值对象 * @param bindingResult 对dto验证的结果 * @return 返回前端 */ @PostMapping(path = "send", consumes = MediaType.APPLICATION_JSON_VALUE) @SsoAop() public BaseResponse send(@RequestBody @Valid ComTransDto dto, BindingResult bindingResult) { if (bindingResult != null && bindingResult.hasErrors()) { return BaseResponseUtils.buildError(Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage()); } String msg = this.checkDto(dto) ; if(msg != null){ return BaseResponseUtils.buildError(msg) ; } //得到控制器对象 PrController ctrlPo = comSv.getRtu(dto.getIntakeId()); if (ctrlPo == null) { return BaseResponseUtils.buildError("从数据库中未得到控制器数据") ; } //检查协议 msg = comSv.checkProtocol(ctrlPo) ; if(msg != null) { return BaseResponseUtils.buildError(msg) ; } //得到功能码对应的命令名称 String comName = comSv.getCommandName(dto.comCode, ctrlPo) ; if(comName == null) { return BaseResponseUtils.buildError("未得到功能码对应命令名称") ; } Long comId = new IDLongGenerator().generate(); String comData = dto.comData.toUpperCase() ; //生成并保存命令日志 comSv.saveComHistoryPo(comId, ctrlPo.getProtocol(), dto.comCode, "透传(" + comName + ")", dto.getIntakeId(), ctrlPo.getRtuAddr(), new ComTransParam(dto.comCode, comData), dto.getOperator()); try{ CompletableFuture feature = new CompletableFuture<>(); ComResultWait.put(comId, feature); //创建外部透传命令(发给控制器) Command com = comSv.createOuterTransparentCommand("" + comId, dto.comCode); com.rtuAddr = ctrlPo.getRtuAddr() ; com.attachment = comData ; com.rtuResultSendWebUrl = rtuResultSendWebUrl; //得到通信中间件发送命令的web URL String rqUrl = comSv.get2MwRequestUrl(this.env, comSv.ContextComSend) ; //向通信中间件发送web请求 BaseResponse res = comSv.sendPostRequest2Mw(restTemplate, rqUrl, com) ; //处理通信中间件对web请求的响应 msg = comSv.dealMwDealResponse(res) ; if(msg != null) { return BaseResponseUtils.buildError(msg) ; }else{ try{ //等待通信中间件通知控制器执行命令上行数据(命令结果) JSONObject resultData = feature.get(waitMwRtnResultTimeout, TimeUnit.SECONDS); Long commandId = resultData.getLong("commandId"); if (commandId.equals(comId)) { return BaseResponseUtils.buildSuccess(resultData); } else { return BaseResponseUtils.buildSuccess("控制器执行命令成功"); } }catch (Exception e){ return BaseResponseUtils.buildFail("等待通信中间件通知命令结果超时或异常"); } } }catch (Exception e){ return BaseResponseUtils.buildFail("服务端构造并向通信中间件发送请求时异常" + (e.getMessage() == null?"":e.getMessage())) ; }finally { try { //最后清除CompletableFuture缓存 ComResultWait.remove(comId); }catch (Exception ee){} } } /** * 验证 * @param dto * @return */ private String checkDto(ComTransDto dto){ if(!NumUtil.isHex(dto.comCode)){ return "命令功能码不是十六进制数"; } if(!NumUtil.isHex(dto.comData)){ return "命令数据不是十六进制数"; } if(dto.comData.length() % 2 != 0){ return "命令数据不完备(长度不是偶数)"; } if(!dto.comData.contains(dto.comCode)){ return "命令数据中不包含功能码"; } return null ; } }