pipIrr-platform/pipIrr-mw/pipIrr-mw-rtu/src/main/java/com/dy/rtuMw/web/com/CommandCtrl.java
New file
@@ -0,0 +1,296 @@
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<String> 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<List<String>> rtuLogText(String rtuAddr){
        List<String> list ;
        File logFile = ResourceUnit.getInstance().getLogFile(rtuAddr + ".log") ;
        if(logFile != null && logFile.exists()){
            BufferedReader reader = null ;
            try {
                reader = new BufferedReader(new FileReader(logFile)) ;
                //新的实现方法
                Stream<String> 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<Boolean> 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<Boolean> 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<String> 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<Command> 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<Command> 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<Command> 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()));
    }
}