package com.dy.rtuMw.web.com; import com.dy.common.softUpgrade.state.UpgradeTaskVo; import com.dy.common.webUtil.ResultCodeMsg; import com.dy.rtuMw.resource.ResourceUnit; import com.dy.rtuMw.server.ServerProperties; import com.dy.rtuMw.server.forTcp.TcpSessionCache; import com.dy.rtuMw.server.local.CommandInnerDeaLer; import com.dy.rtuMw.server.local.ReturnCommand; import com.dy.rtuMw.server.msCenter.MsCenterUnit; import com.dy.rtuMw.server.tasks.WebDownComTask; import com.dy.common.mw.core.CoreUnit; import com.dy.common.mw.protocol.Command; import com.dy.common.mw.protocol.CommandType; import com.dy.common.webUtil.BaseResponse; import com.dy.common.webUtil.BaseResponseUtils; import com.dy.rtuMw.server.upgrade.UpgradeUnit; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import java.io.*; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; /** * @Author liurunyu * @Date 2023/12/21 13:58 * @LastEditTime 2023/12/21 13:58 * @Description 命令接收 */ @Slf4j @RestController @RequestMapping(path="com") @SuppressWarnings("unchecked")//java版本越高,对泛型约束越严,所以配置SuppressWarnings("unchecked") public class CommandCtrl { @GetMapping(path = "test") public BaseResponse test(){ return BaseResponseUtils.buildSuccess("ok"); } /** * 下载控制器(RTU)上下行数据的log日志文件 * @param rtuAddr * @param req * @param rep */ @GetMapping("/rtuLogFile") public void rtuLogFile(String rtuAddr, HttpServletRequest req, HttpServletResponse rep){ File logFile = ResourceUnit.getInstance().getLogFile(rtuAddr + ".log") ; if(logFile != null && logFile.exists()){ //在Spring Boot中,application/octet-stream;charset=UTF-8通常表示响应的内容是字节流, //并且字符集是UTF-8。对于这种类型的响应,Spring Boot默认使用ByteArrayHttpMessageConverter来处理, //因为它可以处理所有application/octet-stream类型的响应。 //然而,ByteArrayHttpMessageConverter并不直接处理字符集(charset)。 //字符集通常用于文本内容,而application/octet-stream通常用于二进制内容,因此在这种情况下指定字符集可能是不合适的。 //不过,如果你确实需要处理带有特定字符集的application/octet-stream响应,你可能需要自定义HttpMessageConverter。 rep.addHeader("content-type", "application/octet-stream;charset=UTF-8"); rep.addHeader("Content-Disposition", "attachment;fileName=" + (rtuAddr + ".log")) ; ServletOutputStream out = null; FileInputStream in = null ; try { out = rep.getOutputStream() ; } catch (Exception ee) { out = null ; }finally{ if(out != null){ byte[] bs = new byte[1024] ; int len = -1 ; try { in = new FileInputStream(logFile); len = in.read(bs) ; while(len != -1){ out.write(bs, 0, len); len = in.read(bs) ; } } catch (Exception eee) { } finally { if(out != null){ try{ out.flush(); out.close(); }catch(Exception e){ }finally{ if(in != null){ try{ in.close(); }catch(Exception e){ } } } } } } } } } /** * 下载控制器(RTU)上下行数据的log日志文件 * @param rtuAddr */ @GetMapping("/rtuLogText") public BaseResponse> rtuLogText(String rtuAddr){ List list ; File logFile = ResourceUnit.getInstance().getLogFile(rtuAddr + ".log") ; if(logFile != null && logFile.exists()){ BufferedReader reader = null ; try { reader = new BufferedReader(new FileReader(logFile)) ; //新的实现方法 Stream linesStream = reader.lines() ; //list = linesStream.toList() ; //按原来顺序 list = linesStream.sorted(Comparator.reverseOrder()).collect(Collectors.toList()) ;//倒序 /* 原来的实现方法 list = new ArrayList() ; String line ; while((line = reader.readLine()) != null){ list.add(line) ; } */ return BaseResponseUtils.buildSuccess(list); } catch (Exception e) { list = new ArrayList() ; list.add("读取控制器(" + rtuAddr + ")的日志文件异常:" + (e.getMessage() == null?"":("," + e.getMessage()))) ; return BaseResponseUtils.buildSuccess(list); }finally{ if(reader != null){ try{ reader.close(); }catch(Exception e){ } } } }else{ list = new ArrayList() ; list.add("未得到控制器(" + rtuAddr + ")的日志文件") ; return BaseResponseUtils.buildSuccess(list); } } /** * 注册消息接收者 * @param msReceiverWebUrl 消息接收者web http post url * @return */ @GetMapping("/registerMsReceiverWebUrl") public BaseResponse> registerMsReceiverWebUrl(String msReceiverWebUrl){ try{ MsCenterUnit.getInstance().registerMsReceiver(msReceiverWebUrl); }catch (Exception e){ log.error("注册消息接收者时发生异常", e); return BaseResponseUtils.buildError("注册消息接收者时发生异常" + (e.getMessage() == null?"":(":" + e.getMessage()))); } return BaseResponseUtils.buildSuccess(true); } /** * 接收web系统发来升级任务 * @param vo * @return */ @PostMapping(path = "upgradeRtu", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse upgradeRtu(@RequestBody UpgradeTaskVo vo) { log.info("收到RTU升级任务:\n" + vo.toString()) ; try{ UpgradeUnit.getInstance().setUpgradeTask(vo); }catch (Exception e){ log.error("设置RTU升级任务时发生异常", e); return BaseResponseUtils.buildError("设置RTU升级任务时发生异常" + (e.getMessage() == null?"":(":" + e.getMessage()))); } return BaseResponseUtils.buildSuccess(true); } /** * 接收web系统发来强制结束升级任务 * @return */ @GetMapping(path = "ugForceOver") public BaseResponse ugForceOver() { log.info("收到停止RTU升级任务命令") ; try{ String mes = UpgradeUnit.getInstance().forceOverUpgradeTask(); if(mes == null){ mes = "停止升级任务成功" ; return BaseResponseUtils.buildResult(ResultCodeMsg.RsCode.SUCCESS_CODE, mes, mes); }else{ return BaseResponseUtils.buildResult(ResultCodeMsg.RsCode.FAIL_CODE, mes, mes); } }catch (Exception e){ log.error("停止RTU升级任务时发生异常", e); return BaseResponseUtils.buildError("停止RTU升级任务时发生异常" + (e.getMessage() == null?"":(":" + e.getMessage()))); } } /** * 接收web系统发来的命令 * @param com * @return */ @PostMapping(path = "send", consumes = MediaType.APPLICATION_JSON_VALUE) public BaseResponse send(@RequestBody Command com) { log.info("收到web系统发来的命令:\n" + com.toString()) ; String commandType = com.getType() ; if(commandType == null){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,收到命令的命令类型为空!", com.getId(), com.getCode())); } String commandId = com.getId() ; if(commandId == null){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,收到命令的命令ID为空!",null, com.getCode())); } String code = com.getCode() ; if(code == null){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,收到命令的命令功能码为空!", com.getId(), null)); } if(commandType.equals(CommandType.innerCommand)){ //通信中间件内部命令,例如查询监控中间件时钟,查询RTU在线情况等 try{ Command reCom = new CommandInnerDeaLer().deal(com) ; return BaseResponseUtils.buildSuccess(reCom); }catch(Exception e){ return BaseResponseUtils.buildError(ReturnCommand.errored("处理内部命令出错" + (e.getMessage() == null?"":("," + e.getMessage())), com.getId(), com.getCode()) ); } }else if(commandType.equals(CommandType.outerCommand)){ //发向RTU的外部命令,异步处理,web端jroups成员同步得到命令处理结果,但构造命令及下发命令和命令结果接收要异步得到 try{ return this.dealOuterCommand(com) ; }catch(Exception e){ return BaseResponseUtils.buildError(ReturnCommand.errored("处理发向RTU的外部命令出错" + (e.getMessage() == null?"":("," + e.getMessage())), com.getId(), com.getCode()) ); } }else if(commandType.equals(CommandType.resultCommand)){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,通信中间件不接结果类型的命令!", com.getId(), com.getCode())); }else{ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,收到命令的命令功能码为空!", com.getId(), com.getCode())); } } /** * 本地调用,例如任务树中某个任务下发的命令(如清空命令) * @param com * @return */ public BaseResponse sendOutComFromLocal(Command com) { try{ return this.dealOuterCommand(com) ; }catch(Exception e){ return BaseResponseUtils.buildError(ReturnCommand.errored("处理发向RTU的外部命令出错" + (e.getMessage() == null?"":("," + e.getMessage())), com.getId(), com.getCode()) ); } } /** * 处理发向RTU的外部命令 * @return 结果 */ private BaseResponse dealOuterCommand(Command command){ String rtuAddr = command.getRtuAddr() ; if(rtuAddr == null || rtuAddr.trim().equals("")){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,RTU地址为空!", command.getId(), command.getCode())) ; } rtuAddr = rtuAddr.trim() ; Boolean onLine = TcpSessionCache.isConnect(rtuAddr); if(onLine == null){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,RTU(地址=" + rtuAddr + ")未上线!", command.getId(), command.getCode())) ; }else if(!onLine.booleanValue()){ if(!ServerProperties.isLowPower){ return BaseResponseUtils.buildError(ReturnCommand.errored("出错,RTU(地址=" + rtuAddr + ")离线!", command.getId(), command.getCode())) ; } } //生成异步任务 WebDownComTask task = new WebDownComTask() ; task.data = command ; try{ log.info("构造下发远程命令" + command.getCode() + "的核心任务,并放入任务队列中"); CoreUnit.getInstance().pushCoreTask(task); }catch(Exception e){ log.error(e.getMessage(), e); return BaseResponseUtils.buildError(ReturnCommand.successed("命令处理失败" + e.getMessage(), command.getId(), command.getCode())) ; } return BaseResponseUtils.buildSuccess(ReturnCommand.successed("命令已接受,即将构造并下发命令。", command.getId(), command.getCode())); } }