package com.its.vds.dto; import com.its.app.utils.SysUtils; import com.its.vds.domain.NET; import com.its.vds.domain.VdsDebug; import com.its.vds.domain.VdsFrameSequence; import com.its.vds.domain.task.VdsCommandTimeoutTask; import com.its.vds.entity.TbVdsCtlr; import com.its.vds.entity.TbVdsCtlrStts; import com.its.vds.entity.TbVdsCtrlHs; import com.its.vds.entity.TbVdsDtct; import com.its.vds.xnettcp.vds.handler.VdsServerIdleStateHandler; import com.its.vds.xnettcp.vds.process.TcpServerSendData; import com.its.vds.xnettcp.vds.process.TcpServerSendDataProcess; import com.its.vds.xnettcp.vds.protocol.VdsReqFramePacket; import com.its.vds.xnettcp.vds.protocol.enums.eVdsOpCode; import com.its.vds.xnettcp.vds.protocol.impl.VdsReqDataLength; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelHandlerContext; import lombok.*; import lombok.extern.slf4j.Slf4j; import java.io.Serializable; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.Map; import java.util.Timer; import java.util.concurrent.ConcurrentHashMap; @Slf4j @Getter @Setter @ToString @Builder @NoArgsConstructor//(access = AccessLevel.PROTECTED) @AllArgsConstructor public class TbVdsCtlrDto implements Serializable { private static final long serialVersionUID = 1L; private int index; private Long vdsCtlrNmbr; private String vdsCtlrId; private String vdsNm; private String vdsCtlrIp; private Integer vdsCtlrPort; private Integer vdsCtlrLocalNo; private String vdsTypeCd; private String istlLctnNm; private Integer groupNo; private Integer fanMode; private Integer fanRunTmpr; private Integer hetrMode; private Integer hetrRunTmpr; private Integer detectLanes; private Integer trafClctCycl; private Integer sttsClctCycl; private String istlLctnAddr; private String validYn; private String delYn; private Map vdsDtctMap; private TbVdsCtlrStts stts; private int netState; private boolean isDupCon; private boolean isDupLogin; private String dstIpAddr; private Channel channel = null; private Channel dupChannel = null; private InetSocketAddress cliReq; private long syncTime; private VdsFrameSequence seq; private ConcurrentHashMap registeredCommandTimer = null; private ConcurrentHashMap registeredCommand = null; private ConcurrentHashMap userCommands = null; private int connectCount; private String connectTm; private String disConnectTm; private long lastRecvTime; private VdsDebug debug; private TcpServerSendDataProcess dataProcess; // 제어기로 데이터를 전송할 전송 전송 큐를 처리할 스레드 public void init() { this.debug = new VdsDebug(); this.stts = new TbVdsCtlrStts(this.vdsCtlrNmbr); this.seq = new VdsFrameSequence(); this.registeredCommandTimer = new ConcurrentHashMap<>(); this.registeredCommand = new ConcurrentHashMap<>(); this.userCommands = new ConcurrentHashMap<>(); this.connectCount = 0; this.connectTm = "-"; this.disConnectTm = "-"; this.lastRecvTime = 0; initNet(); this.dataProcess = new TcpServerSendDataProcess(this); this.dataProcess.run(); } public String getLogKey() { return this.vdsCtlrId; } /** * 제어기 전송 패킷의 패킷 번호를 구한다. * @return */ public short getSeqNext() { return this.seq.nextValue(); } /** * 제어기 전송 스레드 타스크 큐에 명령을 전송 * @param data * @return */ public synchronized boolean addRequestData(TcpServerSendData data) { return this.dataProcess.add(data); } /** * 제어기 네트워크 최초 접속시 발생 이벤트 * @param ctx */ public synchronized void connected(ChannelHandlerContext ctx) { this.netState = NET.LOGIN_REQ; this.connectTm = SysUtils.getSysTimeStr(); this.channel = ctx.channel(); this.lastRecvTime = System.currentTimeMillis(); this.connectCount++; this.stts.initNormal(); clearRegisteredCommandTimer(); } /** * 제어기 네트워크 연결 종료 이벤트 */ public synchronized void disconnected() { clearRegisteredCommandTimer(); this.netState = NET.CLOSED; this.channel = null; this.disConnectTm = SysUtils.getSysTimeStr(); this.stts.initError(); } public String getLastRecvTimeFmt() { SimpleDateFormat sdfDate = new SimpleDateFormat("MM-dd HH:mm:ss"); return sdfDate.format(this.lastRecvTime); } public void resetConnectCount() { if (this.netState == NET.CLOSED) this.connectCount = 0; else this.connectCount = 1; } void initNet() { this.netState = NET.CLOSED; this.isDupCon = false; this.isDupLogin = false; this.dstIpAddr = ""; this.channel = null; this.dupChannel = null; this.cliReq = null; this.syncTime = 0; } /** * 제어기 명령 타임아웃 타스크 클리어 */ public synchronized void clearRegisteredCommandTimer() { this.registeredCommand.clear(); for (Map.Entry e : this.registeredCommandTimer.entrySet()) { Timer task = e.getValue(); task.cancel(); } this.registeredCommandTimer.clear(); } /** * 제어기 명령 타임아웃 타스크 추가 * @param cmdTimeoutTask * @return */ public synchronized void addRegisteredCommandsTimer(VdsCommandTimeoutTask cmdTimeoutTask) { long timeoutSec = 1000L * 5; Timer timer = new Timer(); timer.schedule(cmdTimeoutTask, timeoutSec); this.registeredCommandTimer.put(cmdTimeoutTask.getPacketNmbr(), timer); this.registeredCommand.put(cmdTimeoutTask.getPacketNmbr(), cmdTimeoutTask); // log.info("addRegisteredCommandsTimer: VDS {}, Task {} EA, OpCode {}.", // cmdTimeoutTask.getCtlr().getVdsCtlrNmbr(), this.registeredCommandTimer.size(), cmdTimeoutTask.getPacket().getOpCode()); } /** * 제어기 명령 타임아웃 타스크 제거 * @param opCode */ public synchronized void removeRegisteredCommandsTimer(eVdsOpCode opCode) { short packetNmbr = (short)opCode.getValue(); Timer timer = this.registeredCommandTimer.get(packetNmbr); if (timer != null) { timer.cancel(); this.registeredCommandTimer.remove(packetNmbr); } VdsCommandTimeoutTask cmdTimeoutTask = this.registeredCommand.get(packetNmbr); if (cmdTimeoutTask != null) { this.registeredCommand.remove(packetNmbr); // log.info("removeRegisteredCommandsTimer: VDS {}, Task {} EA, OpCode {}.", // cmdTimeoutTask.getCtlr().getVdsCtlrNmbr(), this.registeredCommandTimer.size(), cmdTimeoutTask.getPacket().getOpCode()); } } /** * Channel Send Data * @param packet * @param retryCnt * @return */ public synchronized boolean sendData(VdsReqFramePacket packet, int retryCnt) { boolean result = false; ByteBuffer sendBuffer = packet.getByteBuffer(); String packetDesc = packet.getOpCodeDesc(); log.info("~REQUEST-{}. VDS {}, {} Bytes.", packetDesc, this.vdsCtlrNmbr, sendBuffer.capacity()); if (this.channel != null) { ChannelFuture f = this.channel.writeAndFlush(sendBuffer); f.awaitUninterruptibly(); if (f.isDone() || f.isSuccess()) { result = true; } else { log.error("~REQUEST-{}. VDS {}, sendData Failed. {} Bytes.", packetDesc, this.vdsCtlrNmbr, sendBuffer.array().length); } } else { log.error("~REQUEST-{}. VDS {}, sendData Failed. Not Connected. {} Bytes.", packetDesc, this.vdsCtlrNmbr, sendBuffer.array().length); } if (result) { VdsCommandTimeoutTask cmdTimeoutTask = new VdsCommandTimeoutTask(this, packet, retryCnt); addRegisteredCommandsTimer(cmdTimeoutTask); } return result; } public boolean channelClose() { if (getChannel() == null || getNetState() == NET.CLOSED) { log.error("Close Request: channel not connected: [{}]", this); return false; } VdsServerIdleStateHandler.disconnectChannel(this, getChannel()); return true; } public boolean reset() { if (getChannel() == null || getNetState() == NET.CLOSED) { log.error("Reset Request: channel not connected: [{}]", this); return false; } VdsReqDataLength resetControl = new VdsReqDataLength(this); // resetControl.controlReset(); return addRequestData(new TcpServerSendData(eVdsOpCode.OP_VDS_DATA_LENGTH, resetControl)); } public synchronized boolean removeUserCommands(Long packetNmbr) { TbVdsCtrlHs command = this.userCommands.get(packetNmbr); if (command != null) { this.userCommands.remove(packetNmbr); return true; } return false; } public synchronized TbVdsCtrlHs getUserCommands(Long packetNmbr) { TbVdsCtrlHs command = this.userCommands.get(packetNmbr); return command; } public TbVdsCtlr toEntity() { return TbVdsCtlr.builder() .vdsCtlrNmbr(this.vdsCtlrNmbr) .vdsCtlrId(this.vdsCtlrId) .vdsNm(this.vdsNm) .vdsCtlrIp(this.vdsCtlrIp) .vdsCtlrPort(this.vdsCtlrPort) .vdsCtlrLocalNo(this.vdsCtlrLocalNo) .vdsTypeCd(this.vdsTypeCd) .istlLctnNm(this.istlLctnNm) .groupNo(this.groupNo) .fanMode(this.fanMode) .fanRunTmpr(this.fanRunTmpr) .hetrMode(this.hetrMode) .hetrRunTmpr(this.hetrRunTmpr) .detectLanes(this.detectLanes) .trafClctCycl(this.trafClctCycl) .sttsClctCycl(this.sttsClctCycl) .istlLctnAddr(this.istlLctnAddr) .validYn(this.validYn) .delYn(this.delYn) .build(); } }