目录推送 未完

This commit is contained in:
shikong 2023-09-13 12:01:33 +08:00
parent 96021addb4
commit a5fed3e73b
12 changed files with 450 additions and 7 deletions

View File

@ -0,0 +1,70 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request;
import cn.skcks.docking.gb28181.common.json.ResponseStatus;
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.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.processor.message.request.dto.MessageDTO;
import cn.skcks.docking.gb28181.core.sip.message.sender.SipMessageSender;
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
import cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.CatalogCmdProcessor;
import cn.skcks.docking.gb28181.mocking.core.sip.message.subscribe.SipSubscribe;
import cn.skcks.docking.gb28181.mocking.core.sip.response.SipResponseBuilder;
import gov.nist.javax.sip.message.SIPRequest;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.util.EventObject;
@Slf4j
@RequiredArgsConstructor
@Component
public class MessageRequestProcessor implements MessageProcessor {
private final SipListener sipListener;
private final SipSubscribe subscribe;
private final SipMessageSender sender;
private final CatalogCmdProcessor catalogCmdProcessor;
private Response okResponse(SIPRequest request){
return SipResponseBuilder.response(request, Response.OK, "OK");
}
@PostConstruct
@Override
public void init() {
sipListener.addRequestProcessor(Request.MESSAGE, this);
}
@Override
public void process(EventObject eventObject) {
RequestEvent requestEvent = (RequestEvent) eventObject;
SIPRequest request = (SIPRequest)requestEvent.getRequest();
String deviceId = SipUtil.getUserIdFromFromHeader(request);
CallIdHeader callIdHeader = request.getCallIdHeader();
String senderIp = request.getLocalAddress().getHostAddress();
byte[] content = request.getRawContent();
MessageDTO messageDto = XmlUtils.parse(content, MessageDTO.class, GB28181Constant.CHARSET);
log.debug("deviceId:{}, 接收到的消息 => {}", deviceId, messageDto);
Response response = null;
if(messageDto.getCmdType().equalsIgnoreCase(CmdType.CATALOG)) {
catalogCmdProcessor.process(request, content);
} else {
response = SipResponseBuilder.response(request, Response.NOT_IMPLEMENTED, ResponseStatus.NOT_IMPLEMENTED.getMessage());
}
if(response != null){
sender.send(senderIp, response);
}
}
}

View File

@ -0,0 +1,47 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog;
import cn.skcks.docking.gb28181.common.xml.XmlUtils;
import cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto.CatalogDeviceListDTO;
import cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto.CatalogItemDTO;
import cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto.CatalogRequestDTO;
import cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto.CatalogResponseDTO;
import cn.skcks.docking.gb28181.mocking.orm.mybatis.dynamic.model.MockingDevice;
import cn.skcks.docking.gb28181.mocking.service.device.DeviceService;
import gov.nist.javax.sip.message.SIPRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@RequiredArgsConstructor
@Component
public class CatalogCmdProcessor {
private final DeviceService deviceService;
public void process(SIPRequest request, byte[] content){
CatalogRequestDTO catalogRequestDTO = XmlUtils.parse(content, CatalogRequestDTO.class);
String sn = catalogRequestDTO.getSn();
String deviceId = catalogRequestDTO.getDeviceId();
List<MockingDevice> mockingDeviceList = deviceService.getDeviceByGbDeviceId(deviceId);
List<CatalogItemDTO> catalogItemDTOList = mockingDeviceList.stream()
.filter(MockingDevice::getEnable)
.map(item -> CatalogItemDTO.builder()
.deviceId(item.getGbChannelId())
.name(item.getName())
.address(item.getAddress())
.manufacturer(item.getName())
.build()).toList();
CatalogDeviceListDTO catalogDeviceListDTO = new CatalogDeviceListDTO(catalogItemDTOList.size(), catalogItemDTOList);
CatalogResponseDTO catalogResponseDTO = CatalogResponseDTO.builder()
.sn(sn)
.deviceId(deviceId)
.deviceList(catalogDeviceListDTO)
.sumNum(Long.valueOf(catalogDeviceListDTO.getNum()))
.build();
}
}

View File

@ -0,0 +1,22 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@JacksonXmlRootElement(localName = "DeviceList")
@AllArgsConstructor
@NoArgsConstructor
@Data
public class CatalogDeviceListDTO {
@JacksonXmlProperty(isAttribute = true)
private Integer num;
@JacksonXmlProperty(localName = "Item")
@JacksonXmlElementWrapper(useWrapping = false)
private List<CatalogItemDTO> deviceList;
}

View File

@ -0,0 +1,151 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto;
import cn.hutool.core.date.DatePattern;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.GB28181Constant;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@JacksonXmlRootElement(localName = "Item")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CatalogItemDTO {
/**
* 设备/区域/系统编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
/**
* 设备/区域/系统名称(必选)
*/
private String name;
/**
* 当为设备时,设备厂商(必选)
*/
private String manufacturer;
/**
* 当为设备时,设备型号(必选)
*/
private String model;
/**
* 当为设备时,设备归属(必选)
*/
private String owner;
/**
* 行政区域(必选)
*/
@JacksonXmlProperty(localName = "CivilCode")
private String civilCode;
/**
* 警区(可选)
*/
private String block;
/**
* 当为设备时,安装地址(必选)
*/
private String address;
/**
* 当为设备时,是否有子设备(必选)1有, 0没有
*/
@Builder.Default
private Integer parental = 0;
/**
* 父设备/区域/系统ID(必选)
*/
@JacksonXmlProperty(localName = "ParentID")
private String parentId;
/**
* 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/ MIME加密签名同时采用方式;4:数字摘要方式
*/
@Builder.Default
private Integer safetyWay = 0;
/**
* 注册方式(必选)缺省为1;1:符合IETF RFC3261标准的认证注册模 ;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
*/
@Builder.Default
private Integer registerWay = 1;
/**
* 证书序列号(有证书的设备必选)
*/
private String certNum;
/**
* 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1: 有效
*/
@Builder.Default
private Integer certifiable = 0;
/**
* 无效原因码(有证书且证书无效的设备必选)
*/
@Builder.Default
private Integer errCode = 0;
/**
* 证书终止有效期(有证书的设备必选)
*/
@JsonFormat(pattern = DatePattern.UTC_SIMPLE_PATTERN, timezone = GB28181Constant.TIME_ZONE)
private Date endTime;
/**
* 保密属性(必选)缺省为0;0:不涉密,1:涉密
*/
@Builder.Default
private Integer secrecy = 0;
/**
* 设备/区域/系统IP地址(可选)
*/
@JacksonXmlProperty(localName = "IPAddress")
private String ipAddress;
/**
* 设备/区域/系统端口(可选)
*/
private Integer port;
/**
* 设备口令(可选)
*/
private String password;
/**
* 设备状态(必选)
*/
@Builder.Default
private String status = "ON";
/**
* 经度(可选)
*/
@Builder.Default
private String longitude = "0.0";
/**
* 纬度(可选)
*/
@Builder.Default
private String latitude = "0.0";
}

View File

@ -0,0 +1,27 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.CmdType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@JacksonXmlRootElement(localName = "Query")
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class CatalogRequestDTO {
@Builder.Default
private String cmdType = CmdType.CATALOG;
@JacksonXmlProperty(localName = "SN")
private String sn;
/**
* 目标设备的设备编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
}

View File

@ -0,0 +1,31 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto;
import cn.skcks.docking.gb28181.core.sip.gb28181.constant.CmdType;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@JacksonXmlRootElement(localName = "Response")
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class CatalogResponseDTO {
@Builder.Default
private String cmdType = CmdType.CATALOG;
@JacksonXmlProperty(localName = "SN")
private String sn;
/**
* 目标设备的设备编码(必选)
*/
@JacksonXmlProperty(localName = "DeviceID")
private String deviceId;
private Long sumNum;
private CatalogDeviceListDTO deviceList;
}

View File

@ -5,7 +5,6 @@ import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
import cn.skcks.docking.gb28181.mocking.config.sip.ServerConfig;
import cn.skcks.docking.gb28181.mocking.config.sip.SipConfig;
import cn.skcks.docking.gb28181.mocking.orm.mybatis.dynamic.model.MockingDevice;
import cn.skcks.docking.gb28181.orm.mybatis.dynamic.model.DockingDevice;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
@ -15,11 +14,14 @@ import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.PeerUnavailableException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
@ -141,4 +143,39 @@ public class SipRequestBuilder implements ApplicationContextAware {
request.addHeader(authorizationHeader);
return request;
}
public static Request createMessageRequest(MockingDevice device, String ip, int port,String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request;
String target = StringUtils.joinWith(":", serverConfig.getIp(), serverConfig.getPort());
// sip uri
SipURI requestURI = MessageHelper.createSipURI(serverConfig.getId(), target);
// via
List<ViaHeader> viaHeaders = getViaHeaders(serverConfig.getIp(), serverConfig.getPort(), sipConfig.getTransport(), viaTag);
String from = StringUtils.joinWith(":", ip, port);
// from
SipURI fromSipURI = MessageHelper.createSipURI(device.getGbDeviceId(), from);
Address fromAddress = MessageHelper.createAddress(fromSipURI);
FromHeader fromHeader = MessageHelper.createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = MessageHelper.createSipURI(serverConfig.getId(), target);
Address toAddress = MessageHelper.createAddress(toSipURI);
ToHeader toHeader = MessageHelper.createToHeader(toAddress, toTag);
// Forwards
MaxForwardsHeader maxForwards = MessageHelper.createMaxForwardsHeader(70);
// ceq
// CSeqHeader cSeqHeader = getSipFactory().createHeaderFactory().createCSeqHeader(getCSeq(), Request.MESSAGE);
// request = getSipFactory().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
// toHeader, viaHeaders, maxForwards);
// request.addHeader(SipUtil.createUserAgentHeader());
//
// ContentTypeHeader contentTypeHeader = getSipFactory().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
// request.setContent(content, contentTypeHeader);
// return request;
return null;
}
}

View File

@ -0,0 +1,28 @@
package cn.skcks.docking.gb28181.mocking.core.sip.response;
import cn.skcks.docking.gb28181.core.sip.message.MessageHelper;
import cn.skcks.docking.gb28181.core.sip.utils.SipUtil;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import javax.sip.message.MessageFactory;
import javax.sip.message.Response;
@Slf4j
public class SipResponseBuilder {
@SneakyThrows
public static Response response(SIPRequest request, int status, String message){
if (request.getToHeader().getTag() == null) {
request.getToHeader().setTag(SipUtil.generateTag());
}
MessageFactory messageFactory = MessageHelper.getSipFactory().createMessageFactory();
SIPResponse response = (SIPResponse)messageFactory.createResponse(status, request);
if (message != null) {
response.setReasonPhrase(message);
}
return response;
}
}

View File

@ -5,7 +5,6 @@ import cn.skcks.docking.gb28181.mocking.config.sip.SipConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.ListeningPoint;
import javax.sip.SipException;

View File

@ -0,0 +1,30 @@
package cn.skcks.docking.gb28181.mocking.core.sip.message.processor.message.request.catalog.dto;
import cn.skcks.docking.gb28181.common.xml.XmlUtils;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class XmlTest {
@Test
void test(){
CatalogResponseDTO catalogResponseDTO = new CatalogResponseDTO();
CatalogDeviceListDTO catalogDeviceListDTO = new CatalogDeviceListDTO();
List<CatalogItemDTO> itemDTOList = new ArrayList<>();
itemDTOList.add(CatalogItemDTO.builder().build());
itemDTOList.add(CatalogItemDTO.builder().build());
catalogDeviceListDTO.setDeviceList(itemDTOList);
catalogDeviceListDTO.setNum(itemDTOList.size());
catalogResponseDTO.setDeviceList(catalogDeviceListDTO);
String xml = XmlUtils.toXml(catalogResponseDTO);
log.info("{}", xml);
log.info("{}", XmlUtils.toXml(catalogDeviceListDTO));
}
}

View File

@ -12,6 +12,7 @@ import org.springframework.context.annotation.ComponentScan;
"cn.skcks.docking.gb28181.common",
"cn.skcks.docking.gb28181.mocking",
"cn.skcks.docking.gb28181.core.sip.utils",
"cn.skcks.docking.gb28181.core.sip.message.sender",
})
public class Gb28181MockingStarter {
public static void main(String[] args) {

View File

@ -24,8 +24,8 @@ spring:
username: root
password: 123456a
url: jdbc:mysql://192.168.1.241:3306/gb28181_docking_platform?createDatabaseIfNotExist=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
profiles:
active: local
# profiles:
# active: local
gb28181:
# 作为28181服务器的配置
@ -40,7 +40,7 @@ gb28181:
# - 10.10.10.20
# - 10.27.0.6
# [可选] 28181服务监听的端口
port: 5060
port: 15060
# 根据国标6.1.2中规定domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码由省级、市级、区级、基层编号组成参照GB/T 2260-2007
# 后两位为行业编码定义参照附录D.3
# 3701020049标识山东济南历下区 信息行业接入
@ -53,8 +53,8 @@ gb28181:
expire: 3600
transport: "UDP"
server:
ip: 192.168.10.32
# ip: 192.168.3.12
# ip: 192.168.10.32
ip: 192.168.3.12
port: 5060
password: 123456
domain: 4405010000