Browse Source

Merge remote-tracking branch 'origin/wvp-pro-record' into wvp-28181-2.0

# Conflicts:
#	web_src/src/components/control.vue
pull/375/head
648540858 3 years ago
parent
commit
cadd0ee038
  1. 32
      src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java
  2. 43
      src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java
  3. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  4. 15
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  5. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  6. 113
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java
  7. 3
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  8. 6
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  9. 22
      src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java
  10. 6
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
  11. 5
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  12. 2
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
  13. 2
      src/main/resources/all-application.yml
  14. 24
      web_src/src/components/control.vue

32
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java

@ -0,0 +1,32 @@
package com.genersoft.iot.vmp.gb28181.event.record;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import org.springframework.context.ApplicationEvent;
/**
* @description: 录像查询结束时间
* @author: pan
* @data: 2022-02-23
*/
public class RecordEndEvent extends ApplicationEvent {
/**
*
*/
private static final long serialVersionUID = 1L;
public RecordEndEvent(Object source) {
super(source);
}
private RecordInfo recordInfo;
public RecordInfo getRecordInfo() {
return recordInfo;
}
public void setRecordInfo(RecordInfo recordInfo) {
this.recordInfo = recordInfo;
}
}

43
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java

@ -0,0 +1,43 @@
package com.genersoft.iot.vmp.gb28181.event.record;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.*;
/**
* @description: 录像查询结束时间
* @author: pan
* @data: 2022-02-23
*/
@Component
public class RecordEndEventListener implements ApplicationListener<RecordEndEvent> {
private final static Logger logger = LoggerFactory.getLogger(RecordEndEventListener.class);
private static Map<String, SseEmitter> sseEmitters = new Hashtable<>();
public void addSseEmitters(String browserId, SseEmitter sseEmitter) {
sseEmitters.put(browserId, sseEmitter);
}
public interface RecordEndEventHandler{
void handler(List<RecordItem> recordItems);
}
private Map<String, RecordEndEventHandler> handlerMap = new HashMap<>();
@Override
public void onApplicationEvent(RecordEndEvent event) {
if (logger.isDebugEnabled()) {
logger.debug("录像查询完成事件触发,deviceId:{}, channelId: {}, 录像数量{}条", event.getRecordInfo().getDeviceId(),
event.getRecordInfo().getChannelId(), event.getRecordInfo().getRecordList().size() );
}
}
}

2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java

@ -258,7 +258,7 @@ public interface ISIPCommander {
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
* @param sn
*/
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent);
boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent);
/**
* 查询报警信息

15
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@ -1196,8 +1196,13 @@ public class SIPCommander implements ISIPCommander {
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
@Override
public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, SipSubscribe.Event errorEvent) {
public boolean recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
if (secrecy == null) {
secrecy = 0;
}
if (type == null) {
type = "all";
}
try {
StringBuffer recordInfoXml = new StringBuffer(200);
@ -1208,9 +1213,9 @@ public class SIPCommander implements ISIPCommander {
recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
recordInfoXml.append("<Secrecy>0</Secrecy>\r\n");
recordInfoXml.append("<Secrecy> "+ secrecy + " </Secrecy>\r\n");
// 大华NVR要求必须增加一个值为all的文本元素节点Type
recordInfoXml.append("<Type>all</Type>\r\n");
recordInfoXml.append("<Type>" + type+"</Type>\r\n");
recordInfoXml.append("</Query>\r\n");
String tm = Long.toString(System.currentTimeMillis());
@ -1221,7 +1226,7 @@ public class SIPCommander implements ISIPCommander {
Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
"z9hG4bK-ViaRecordInfo-" + tm, "fromRec" + tm, null, callIdHeader);
transmitRequest(device, request, errorEvent);
transmitRequest(device, request, errorEvent, okEvent);
} catch (SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
return false;

2
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@ -91,7 +91,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (event)->{
if (event != null) {
logger.info("向上级平台 [ {} ] 注册发错误: {} ",
logger.info("向上级平台 [ {} ] 注册发错误: {} ",
parentPlatform.getServerGBId(),
event.msg);
}

113
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java

@ -0,0 +1,113 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(RecordInfoQueryMessageHandler.class);
private final String cmdType = "RecordInfo";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SIPCommander commander;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId();
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
Element snElement = rootElement.element("SN");
int sn = Integer.parseInt(snElement.getText());
Element deviceIDElement = rootElement.element("DeviceID");
String channelId = deviceIDElement.getText();
Element startTimeElement = rootElement.element("StartTime");
String startTime = startTimeElement.getText();
Element endTimeElement = rootElement.element("EndTime");
String endTime = endTimeElement.getText();
Element secrecyElement = rootElement.element("Secrecy");
int secrecy = Integer.parseInt(secrecyElement.getText());
Element typeElement = rootElement.element("Type");
String type = typeElement.getText();
// 确认是直播还是国标, 国标直接请求下级,直播请求录像管理服务
List<ChannelSourceInfo> channelSources = storager.getChannelSource(parentPlatform.getServerGBId(), channelId);
if (channelSources.get(0).getCount() > 0) { // 国标
// 向国标设备请求录像数据
Device device = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
commander.recordInfoQuery(device, channelId, DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTime),
DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTime), sn, secrecy, type, (eventResult -> {
// 查询成功
}),(eventResult -> {
// 查询失败
}));
}else if (channelSources.get(0).getCount() > 0) { // 直播流
// TODO
}else { // 错误的请求
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

3
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem;
import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import com.github.pagehelper.PageInfo;
@ -475,4 +476,6 @@ public interface IVideoManagerStorager {
void delRelationByPlatformId(String serverGBId);
PlatformCatalog queryDefaultCatalogInPlatform(String platformId);
List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
}

6
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java

@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.storager.dao;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
import org.apache.ibatis.annotations.*;
import org.springframework.stereotype.Repository;
@ -86,4 +87,9 @@ public interface ParentPlatformMapper {
"WHERE serverGBId=#{platformId}"+
"</script>"})
int setDefaultCatalog(String platformId, String catalogId);
@Select("select 'channel' as name, count(pgc.platformId) count from platform_gb_channel pgc where pgc.platformId=#{platformId} and pgc.channelId =#{gbId} " +
"union " +
"select 'stream' as name, count(pgs.platformId) count from platform_gb_stream pgs left join gb_stream gs on pgs.gbStreamId = gs.id where pgs.platformId=#{platformId} and gs.gbId = #{gbId}")
List<ChannelSourceInfo> getChannelSource(String platformId, String gbId);
}

22
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java

@ -0,0 +1,22 @@
package com.genersoft.iot.vmp.storager.dao.dto;
public class ChannelSourceInfo {
private String name;
private int count;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}

6
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java

@ -14,6 +14,7 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.storager.dao.*;
import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
import com.genersoft.iot.vmp.utils.node.ForestNodeMerger;
import com.genersoft.iot.vmp.vmanager.bean.DeviceChannelTree;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
@ -1104,4 +1105,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
public PlatformCatalog queryDefaultCatalogInPlatform(String platformId) {
return catalogMapper.selectDefaultByPlatFormId(platformId);
}
@Override
public List<ChannelSourceInfo> getChannelSource(String platformId, String gbId) {
return platformMapper.getChannelSource(platformId, gbId);
}
}

5
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java

@ -137,6 +137,11 @@ public class PlatformController {
wvpResult.setMsg("missing parameters");
return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
}
if (parentPlatform.getServerPort()< 0 || parentPlatform.getServerPort() > 65535){
wvpResult.setCode(-1);
wvpResult.setMsg("error severPort");
return new ResponseEntity<>(wvpResult, HttpStatus.BAD_REQUEST);
}
ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());
if (parentPlatformOld != null) {

2
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java

@ -64,7 +64,7 @@ public class GBRecordController {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, (eventResult -> {
cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> {
msg.setData("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg );
resultHolder.invokeResult(msg);
}));

2
src/main/resources/all-application.yml

@ -1,7 +1,7 @@
# 此配置文件只是用作展示所有配置项, 不可直接使用
# 此配置文件只是用作展示所有配置项, 不可直接使用
spring:

24
web_src/src/components/control.vue

@ -37,7 +37,19 @@
</el-popover>
<el-popover placement="bottom" width="900" height="300" trigger="click">
<div style="height: 600px;overflow:auto; padding: 20px">
<el-descriptions title="国标配置" border column="1">
<template slot="extra">
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerConfig.sip)" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
</template>
<el-descriptions-item v-for="(value, key, index) in wvpServerConfig.sip">
<template slot="label">
{{ getNameFromKey(key) }}
</template>
{{ value }}
</el-descriptions-item>
</el-descriptions>
<div style="margin-top: 1rem">
<el-descriptions title="基础配置" border column="1">
<template slot="extra">
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerConfig.base)" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
@ -70,18 +82,6 @@
</el-descriptions-item>
</el-descriptions>
<div style="margin-top: 1rem">
<el-descriptions title="国标配置" border column="1">
<template slot="extra">
<el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerConfig.sip)" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
</template>
<el-descriptions-item v-for="(value, key, index) in wvpServerConfig.sip" :key="key">
<template slot="label">
{{ getNameFromKey(key) }}
</template>
{{ value }}
</el-descriptions-item>
</el-descriptions>
</div>
<div style="margin-top: 1rem">
<el-descriptions title="版本信息" border column="1">

Loading…
Cancel
Save