292 lines
10 KiB
Java
292 lines
10 KiB
Java
package com.cisdi.data.AMETEKSurfaceVision.gateway;
|
||
|
||
import com.alibaba.fastjson.JSON;
|
||
|
||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO;
|
||
import com.cisdi.data.AMETEKSurfaceVision.DynamicCodeActionParamDTO.PropertyConfig;
|
||
import com.cisdi.data.common.exception.BusinessException;
|
||
import com.cisdi.data.sdk.consts.ServiceName;
|
||
import com.cisdi.data.sdk.gateway.message.SocketMessage;
|
||
import com.cisdi.data.sdk.gateway.netty.IoSession;
|
||
import com.cisdi.data.sdk.gateway.netty.impl.AbstractIoSession;
|
||
import com.cisdi.data.sdk.service.DynamicCodecService;
|
||
import com.cisdi.data.sdk.service.SendService;
|
||
import com.cisdi.data.sdk.service.Service;
|
||
import com.cisdi.data.sdk.vo.ExeResultVo;
|
||
import io.netty.buffer.ByteBuf;
|
||
import io.netty.buffer.Unpooled;
|
||
import java.util.HashMap;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
|
||
/**
|
||
* 表检仪协议会话
|
||
*
|
||
* @author tzz
|
||
*/
|
||
public class SurfaceVisionIoSession extends AbstractIoSession implements IoSession {
|
||
private long lastAliveTime = System.currentTimeMillis();
|
||
private static Logger logger = LoggerFactory.getLogger(SurfaceVisionIoSession.class);
|
||
private String deviceId = null;
|
||
private String gwPrefixCache = null;
|
||
private final static byte[] beat = {0x07,0x7C,0x24,0x0D,0x0A};
|
||
|
||
private int count = 1;
|
||
// 初始化为0的原子整型变量作为计数器,用作发送命令的replayId,初始值为1
|
||
|
||
/** 当前下发命令replayId */
|
||
private Integer currentCount = -1;
|
||
|
||
public void setCurrentSend(SurfaceVisionSocketReturnMessage currentSend) {
|
||
this.currentSend = currentSend;
|
||
}
|
||
|
||
/** 当前下发命令信息 */
|
||
private SurfaceVisionSocketReturnMessage currentSend = null;
|
||
|
||
public void increment() {
|
||
if (count < SurfaceVisionConstants.MAX_COUNT) {
|
||
count++;
|
||
// 自增1并返回新值
|
||
}
|
||
else {
|
||
count = 1;
|
||
}
|
||
}
|
||
|
||
public int getCount() {
|
||
return count;
|
||
// 获取当前计数器的值
|
||
}
|
||
|
||
|
||
public SurfaceVisionIoSession(String deviceId) {
|
||
this.deviceId = deviceId;
|
||
}
|
||
|
||
@Override
|
||
public String[] getDeviceIds() {
|
||
return new String[0];
|
||
}
|
||
|
||
/** 获取当前下发电文点位配置信息 */
|
||
private List<PropertyConfig> getPropertyConfig(String msgKeyName){
|
||
//获取DynamicService
|
||
Service service = serviceProvider.getByName(ServiceName.DynamicCodec);
|
||
if (service == null || !(service instanceof DynamicCodecService)) {
|
||
throw new BusinessException("获取DynamicService失败");
|
||
}
|
||
|
||
//获取网关ID
|
||
String runId = socketGateway.getInstanceVo().getRunId();
|
||
|
||
//获取点位配置信息
|
||
DynamicCodecService dynamicCodecService = (DynamicCodecService)service;
|
||
String actionParam = dynamicCodecService.findByRunIdAndMsgKey(runId, msgKeyName);
|
||
DynamicCodeActionParamDTO dto = null;
|
||
try {
|
||
dto = JSON.parseObject(actionParam, DynamicCodeActionParamDTO.class);
|
||
} catch (Exception e) {
|
||
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "json转换错误", e);
|
||
}
|
||
|
||
if (dto == null || dto.getPropertyList() == null || dto.getPropertyList().isEmpty()) {
|
||
throw new BusinessException("连接id:" + runId + "电文号:" + msgKeyName + "属性列表为空");
|
||
}
|
||
|
||
//返回点位信息
|
||
return dto.getPropertyList();
|
||
}
|
||
|
||
@Override
|
||
public void onRead(Object message) {
|
||
//获取表检仪上送或返回消息
|
||
ByteBuf inBuf = (ByteBuf) message;
|
||
|
||
int length = inBuf.readableBytes();
|
||
|
||
//将消息头和消息体拆包,解析出消息头信息
|
||
SurfaceVisionFrameInputVo vo = SurfaceVisionVoDecoder.Decode(inBuf);
|
||
logger.info("AMETEKSurfaceVision收到 msg: {}", vo);
|
||
|
||
//消息头,也是电文信息
|
||
String msgKey = vo.getMsgKey();
|
||
|
||
try {
|
||
//通过消息头判断返回消息类型
|
||
if(vo.getBeatType()){
|
||
//判断是否心跳信息
|
||
lastAliveTime = System.currentTimeMillis();
|
||
logger.info("接收到心跳消息,当前时间为:{}", lastAliveTime);
|
||
} else if (msgKey.startsWith(SurfaceVisionConstants.RETURN_HEADER1)) {
|
||
//非Query命令正常返回消息
|
||
//解码
|
||
SurfaceVisionVoDecoder.DecodeReturn(vo);
|
||
|
||
//组装返回信息,判断replayId是否一致
|
||
ExeResultVo sendResult = new ExeResultVo();
|
||
if (!currentCount.equals(vo.getReplayId())) {
|
||
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, ReplayId:{} 与实际发送下去的:{},不一致"
|
||
, msgKey, vo, vo.getReplayId(), currentCount);
|
||
sendResult.setSuccess(false);
|
||
sendResult.setMessage("返回消息replayId与发送消息replayId不符");
|
||
} else {
|
||
sendResult.setSuccess(vo.getStatus());
|
||
sendResult.setMessage(vo.getDescription());
|
||
}
|
||
|
||
//组装返回结果
|
||
returnData(sendResult);
|
||
} else if (SurfaceVisionConstants.RETURN_HEADER2.equals(msgKey)) {
|
||
//下发命令异常返回消息
|
||
//解码
|
||
SurfaceVisionVoDecoder.DecodeReturnError(vo);
|
||
|
||
ExeResultVo sendResult = new ExeResultVo();
|
||
sendResult.setSuccess(vo.getStatus());
|
||
sendResult.setMessage(vo.getDescription());
|
||
|
||
//组装返回结果
|
||
returnData(sendResult);
|
||
} else if (SurfaceVisionConstants.RETURN_HEADER3.equals(msgKey)) {
|
||
//Query命令返回
|
||
//解码
|
||
SurfaceVisionVoDecoder.DecodeReturnQuery(vo);
|
||
|
||
ExeResultVo sendResult = new ExeResultVo();
|
||
sendResult.setSuccess(vo.getStatus());
|
||
sendResult.setMessage(vo.getDescription());
|
||
|
||
Map<Object, Object> queryData = new HashMap<>();
|
||
queryData.putAll(vo.getReturnData());
|
||
sendResult.setData(queryData);
|
||
|
||
//组装返回结果
|
||
returnData(sendResult);
|
||
} else {
|
||
//主动上报消息
|
||
//解码
|
||
SurfaceVisionVoDecoder.DecodeData(vo, getPropertyConfig(msgKey));
|
||
Map<String, Object> realDataMap = vo.getReturnData();
|
||
|
||
//数据发送到平台
|
||
if (vo != null && serviceProvider != null && socketGateway != null) {
|
||
SendService service = (SendService) serviceProvider.getByName(ServiceName.Send);
|
||
|
||
//组装数据包
|
||
SocketMessage socketMessage = socketGateway.buildSocketMessage();
|
||
socketMessage.setDeviceId(deviceId);
|
||
|
||
socketMessage.getPropsMap().put(SurfaceVisionConstants.S_V_SEND_PLATFORM_DATA, realDataMap);
|
||
|
||
socketMessage.setMsgKey(msgKey);
|
||
|
||
//发送数据
|
||
service.sendMessage(socketMessage);
|
||
} else {
|
||
logger.info("AMETEKSurfaceVision收到 msgkey: {} 消息:{}, 但是不能发到平台", msgKey, JSON.toJSONString(realDataMap));
|
||
}
|
||
}
|
||
}catch (Exception e){
|
||
logger.error("AMETEKSurfaceVision接收消息匹配错误, msgKey: {}, msg:{}, error", msgKey, vo, e);
|
||
}
|
||
|
||
if(socketGateway!= null && Boolean.TRUE.equals(socketGateway.getInstanceVo().getLogOpen())) {
|
||
logger.info("AMETEKSurfaceVision {} 报文长度:{} vo:{} ", getChannel(), length, JSON.toJSONString(vo));
|
||
}
|
||
|
||
}
|
||
|
||
/** 设置当前下发命令返回信息 */
|
||
private void returnData(ExeResultVo sendResult) {
|
||
if(currentSend == null){
|
||
throw new BusinessException("下发返回消息没有对应的下发命令");
|
||
}
|
||
currentSend.setRealData(sendResult);
|
||
currentSend.setSendReturnFlag(true);
|
||
currentSend = null;
|
||
}
|
||
|
||
@Override
|
||
public void onOpen() {
|
||
super.onOpen();
|
||
logger.info("建立连接,channel:{}", getChannel());
|
||
}
|
||
|
||
@Override
|
||
public void onClose() {
|
||
super.onClose();
|
||
}
|
||
|
||
public void close() {
|
||
if(getChannel() != null) {
|
||
try {
|
||
getChannel().close().sync();
|
||
} catch (InterruptedException e) {
|
||
logger.warn(e.getLocalizedMessage(), e);
|
||
}
|
||
}
|
||
}
|
||
|
||
public String gwPrefix() {
|
||
if(gwPrefixCache != null) {
|
||
return gwPrefixCache;
|
||
}
|
||
|
||
gwPrefixCache = "";
|
||
if(socketGateway != null && socketGateway.getInstanceVo() != null) {
|
||
gwPrefixCache = "网关Id:" + socketGateway.getInstanceVo().getRunId() + "连接:" + getChannel() + " ";
|
||
}else {
|
||
gwPrefixCache = "连接:" + getChannel() + " ";
|
||
}
|
||
|
||
return gwPrefixCache;
|
||
}
|
||
|
||
public long getLastAliveTime() {
|
||
return lastAliveTime;
|
||
}
|
||
|
||
@Override
|
||
public void send(Object message) {
|
||
//下发命令
|
||
SurfaceVisionSocketReturnMessage returnMsg = (SurfaceVisionSocketReturnMessage) message;
|
||
String msgKey = returnMsg.getMsgKey();
|
||
|
||
//与AMETEKSurfaceVisionSocketProtocol类对应
|
||
Map<String, Object> propsMap = (Map<String, Object>)
|
||
returnMsg.getPropsMap().get(SurfaceVisionConstants.S_V_SEND_DATA);
|
||
|
||
//获取下发点位配置
|
||
List<PropertyConfig> propertyConfigList = getPropertyConfig(msgKey);
|
||
|
||
//获取计数器值作为下发命令replayId
|
||
int c = getCount();
|
||
logger.info("下发数据, 数据:{}, 点位配置:{}, 返回ID:{}", propsMap, propertyConfigList, c);
|
||
|
||
ByteBuf byteBuf = SurfaceVisionEncoder.Encode(msgKey, propsMap, propertyConfigList, c);
|
||
logger.info("下发数据的byteBuf:{}", byteBuf);
|
||
|
||
//下发命令编码后发送
|
||
getChannel().writeAndFlush(byteBuf);
|
||
|
||
logger.info("下发数据成功");
|
||
|
||
//缓存当前下发命令信息和replayId
|
||
currentSend = returnMsg;
|
||
currentCount = c;
|
||
|
||
//计数器自增
|
||
increment();
|
||
}
|
||
|
||
public void sendBeat() {
|
||
logger.info("发送心跳");
|
||
ByteBuf byteBuf = Unpooled.wrappedBuffer(beat);
|
||
getChannel().writeAndFlush(byteBuf);
|
||
logger.info("心跳发送成功");
|
||
}
|
||
}
|