设备心跳

This commit is contained in:
shikong 2023-08-12 23:37:02 +08:00
parent b76658ad20
commit 29fd114361
10 changed files with 243 additions and 14 deletions

View File

@ -44,6 +44,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>

View File

@ -48,9 +48,9 @@ public class JsonUtils {
}
}
public static <T> T parse(String json, TypeReference<T> clazz) {
public static <T> T parse(String xml, TypeReference<T> clazz) {
try {
return mapper.readValue(json, clazz);
return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;

View File

@ -0,0 +1,111 @@
package cn.skcks.docking.gb28181.common.xml;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import java.nio.charset.Charset;
@SuppressWarnings({"unused"})
public class XmlUtils {
private static final ObjectMapper mapper = new XmlMapper();
static {
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
// 如果json中有新增的字段并且是实体类类中不存在的不报错
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, false);
// 允许出现特殊字符和转义符
mapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
// 允许出现单引号
mapper.configure(JsonReadFeature.ALLOW_SINGLE_QUOTES.mappedFeature(), true);
// 大驼峰 (首字母大写)
mapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
}
public static String toXml(Object obj) {
try {
return mapper.writeValueAsString(obj);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj) {
try {
return mapper.writeValueAsString(obj).getBytes();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj, Charset charset) {
try {
return mapper.writeValueAsString(obj).getBytes(charset);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static byte[] toByteXml(Object obj, String charset) {
try {
return mapper.writeValueAsString(obj).getBytes(Charset.forName(charset));
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> T parse(byte[] xml, Class<T> clazz) {
return parse(new String(xml), clazz);
}
public static <T> T parse(byte[] xml, Class<T> clazz, Charset charset) {
return parse(new String(xml, charset), clazz);
}
public static <T> T parse(byte[] xml, Class<T> clazz, String charset) {
return parse(new String(xml, Charset.forName(charset)), clazz);
}
public static <T> T parse(String xml, Class<T> clazz) {
try {
return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> T parse(byte[] xml, TypeReference<T> clazz) {
return parse(new String(xml), clazz);
}
public static <T> T parse(byte[] xml, TypeReference<T> clazz, Charset charset) {
return parse(new String(xml, charset), clazz);
}
public static <T> T parse(byte[] xml, TypeReference<T> clazz, String charset) {
return parse(new String(xml, Charset.forName(charset)), clazz);
}
public static <T> T parse(String xml, TypeReference<T> clazz) {
try {
return mapper.readValue(xml, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> T convert(Object object, Class<T> clazz) {
return XmlUtils.parse(XmlUtils.toXml(object), clazz);
}
}

View File

@ -0,0 +1,17 @@
package cn.skcks.docking.gb28181.core.sip.gb28181.constant;
@SuppressWarnings("unused")
public class CmdType {
public static final String KEEPALIVE = "Keepalive";
public static final String DEVICE_CONFIG = "DeviceConfig";
public static final String DEVICE_CONTROL = "DeviceControl";
public static final String DEVICE_STATUS = "DeviceStatus";
public static final String CATALOG = "Catalog";
public static final String ALARM = "Alarm";
public static final String MOBILE_POSITION = "MobilePosition";
public static final String BROADCAST = "Broadcast";
public static final String RECORD_INFO = "RecordInfo";
public static final String MEDIA_STATUS = "MediaStatus";
public static final String CONFIG_DOWNLOAD = "ConfigDownload";
public static final String PRESET_QUERY = "PresetQuery";
}

View File

@ -1,6 +1,6 @@
package cn.skcks.docking.gb28181.core.sip.gb28181.constant;
public class DefaultConstant {
public class GB28181Constant {
public static final String CHARSET = "GB2312";
public static final String GEO_COORD_SYS = "WGS84";
}

View File

@ -1,6 +1,5 @@
package cn.skcks.docking.gb28181.core.sip.message.processor;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,8 +14,10 @@ public interface MessageProcessor {
class Method {
public static final String REGISTER = "REGISTER";
public static final String MESSAGE = "MESSAGE";
}
void init();
void process(RequestEvent requestEvent);
default MessageFactory getMessageFactory() {

View File

@ -0,0 +1,77 @@
package cn.skcks.docking.gb28181.core.sip.message.processor.message.request;
import cn.skcks.docking.gb28181.common.xml.XmlUtils;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.CmdType;
import cn.skcks.docking.gb28181.core.sip.message.processor.message.request.dto.MessageDto;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
import cn.skcks.docking.gb28181.core.sip.listener.SipListener;
import cn.skcks.docking.gb28181.core.sip.message.processor.MessageProcessor;
import cn.skcks.docking.gb28181.core.sip.message.sender.SipMessageSender;
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
import cn.skcks.docking.gb28181.orm.mybatis.dynamic.model.DockingDevice;
import cn.skcks.docking.gb28181.service.docking.device.DockingDeviceService;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
@Slf4j
@RequiredArgsConstructor
@Component
public class MessageRequestProcessor implements MessageProcessor {
private final SipListener sipListener;
private final DockingDeviceService deviceService;
private final SipMessageSender sender;
@PostConstruct
@Override
public void init() {
sipListener.addProcessor(Method.MESSAGE, this);
}
@Override
public void process(RequestEvent requestEvent) {
SIPRequest request = (SIPRequest)requestEvent.getRequest();
String deviceId = SipUtil.getUserIdFromFromHeader(request);
CallIdHeader callIdHeader = request.getCallIdHeader();
MessageDto messageDto = XmlUtils.parse(request.getRawContent(), MessageDto.class, GB28181Constant.CHARSET);
log.debug("接收到的消息 => {}", messageDto);
DockingDevice device = deviceService.getDevice(deviceId);
String senderIp = request.getLocalAddress().getHostAddress();
if(device == null){
log.info("未找到相关设备信息 => {}", deviceId);
Response response = response(request,Response.NOT_FOUND,"设备未注册");
sender.send(senderIp,response);
return;
}
if(messageDto.getCmdType().equalsIgnoreCase(CmdType.KEEPALIVE)){
Response response = response(request,Response.OK,"OK");
// 更新设备在线状态
deviceService.online(device, response);
sender.send(senderIp,response);
}
}
@SneakyThrows
public Response response(SIPRequest request, int status, String message){
if (request.getToHeader().getTag() == null) {
request.getToHeader().setTag(SipUtil.generateTag());
}
SIPResponse response = (SIPResponse)getMessageFactory().createResponse(status, request);
if (message != null) {
response.setReasonPhrase(message);
}
return response;
}
}

View File

@ -0,0 +1,19 @@
package cn.skcks.docking.gb28181.core.sip.message.processor.message.request.dto;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.Data;
@JacksonXmlRootElement(localName = "xml")
@Data
public class MessageDto {
private String cmdType;
@JacksonXmlProperty(localName = "SN")
private String sn;
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
private String status;
}

View File

@ -4,7 +4,7 @@ import cn.hutool.core.date.DateUtil;
import cn.skcks.docking.gb28181.config.sip.SipConfig;
import cn.skcks.docking.gb28181.core.sip.dto.RemoteInfo;
import cn.skcks.docking.gb28181.core.sip.dto.SipTransactionInfo;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.DefaultConstant;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
import cn.skcks.docking.gb28181.core.sip.gb28181.sip.GbSipDate;
import cn.skcks.docking.gb28181.core.sip.listener.SipListener;
import cn.skcks.docking.gb28181.core.sip.message.auth.DigestServerAuthenticationHelper;
@ -46,7 +46,8 @@ public class RegisterRequestProcessor implements MessageProcessor {
private final DockingDeviceService dockingDeviceService;
@PostConstruct
private void init(){
@Override
public void init(){
sipListener.addProcessor(Method.REGISTER,this);
}
@ -61,7 +62,7 @@ public class RegisterRequestProcessor implements MessageProcessor {
SipUri uri = (SipUri)address.getURI();
String deviceId = uri.getUser();
log.debug("请求注册 设备id => {}", deviceId);
DockingDevice device = dockingDeviceService.getDeviceInfo(deviceId);
DockingDevice device = dockingDeviceService.getDevice(deviceId);
String senderIp = request.getLocalAddress().getHostAddress();
RemoteInfo remoteInfo = SipUtil.getRemoteInfoFromRequest(request, false);
log.debug("远程连接信息 => {}", remoteInfo);
@ -135,8 +136,8 @@ public class RegisterRequestProcessor implements MessageProcessor {
if (device == null) {
device = new DockingDevice();
device.setStreamMode(ListeningPoint.UDP);
device.setCharset(DefaultConstant.CHARSET);
device.setGeoCoordSys(DefaultConstant.GEO_COORD_SYS);
device.setCharset(GB28181Constant.CHARSET);
device.setGeoCoordSys(GB28181Constant.GEO_COORD_SYS);
device.setDeviceId(deviceId);
device.setOnLine(false);
} else {
@ -144,10 +145,10 @@ public class RegisterRequestProcessor implements MessageProcessor {
device.setStreamMode(ListeningPoint.UDP);
}
if (ObjectUtils.isEmpty(device.getCharset())) {
device.setCharset(DefaultConstant.CHARSET);
device.setCharset(GB28181Constant.CHARSET);
}
if (ObjectUtils.isEmpty(device.getGeoCoordSys())) {
device.setGeoCoordSys(DefaultConstant.GEO_COORD_SYS);
device.setGeoCoordSys(GB28181Constant.GEO_COORD_SYS);
}
}

View File

@ -16,7 +16,6 @@ import org.mybatis.dynamic.sql.SqlBuilder;
import org.springframework.stereotype.Service;
import javax.sip.message.Response;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
@ -32,7 +31,7 @@ public class DockingDeviceService {
* @param deviceId 设备id
* @return 设备信息
*/
public DockingDevice getDeviceInfo(String deviceId) {
public DockingDevice getDevice(String deviceId) {
DockingDevice device = deviceCacheService.getDevice(deviceId);
if (device == null) {
device = dockingDeviceMapper
@ -65,7 +64,7 @@ public class DockingDeviceService {
dockingDeviceMapper.insert(device);
});
getDeviceInfo(deviceId);
getDevice(deviceId);
onlineCacheService.setOnline(deviceId, DeviceConstant.KEEP_ALIVE_INTERVAL * 3, DeviceConstant.UNIT);
setTransaction(deviceId, response);
}