Commit b4048fbe80dba8e7756ae557a15ab60b4f80a44b

Authored by 648540858
2 parents 786c76ba 053cd130

合并开源主线

Showing 100 changed files with 1881 additions and 660 deletions

Too many changes to show.

To preserve performance only 100 of 165 files are displayed.

README.md
@@ -99,15 +99,16 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git @@ -99,15 +99,16 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
99 - [X] 支持接口鉴权 99 - [X] 支持接口鉴权
100 - [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载 100 - [X] 云端录像,推流/代理/国标视频均可以录制在云端服务器,支持预览和下载
101 - [X] 支持打包可执行jar和war 101 - [X] 支持打包可执行jar和war
  102 +- [X] 支持跨域请求,支持前后端分离部署
102 103
103 104
104 # 遇到问题如何解决 105 # 遇到问题如何解决
105 国标最麻烦的地方在于设备的兼容性,所以需要大量的设备来测试,目前作者手里的设备有限,再加上作者水平有限,所以遇到问题在所难免; 106 国标最麻烦的地方在于设备的兼容性,所以需要大量的设备来测试,目前作者手里的设备有限,再加上作者水平有限,所以遇到问题在所难免;
106 -1. 查看wiki,仔细的阅读可以帮你避免几乎所有的问题 107 +1. 查看文档网站,仔细的阅读可以帮你避免几乎所有的问题
107 2. 搜索issues,这里有大部分的答案 108 2. 搜索issues,这里有大部分的答案
108 3. 加QQ群(901799015),这里有大量热心的小伙伴,但是前提新希望你已经仔细阅读了wiki和搜索了issues。 109 3. 加QQ群(901799015),这里有大量热心的小伙伴,但是前提新希望你已经仔细阅读了wiki和搜索了issues。
109 4. 你可以请作者为你解答,但是我不是免费的。 110 4. 你可以请作者为你解答,但是我不是免费的。
110 -5. 你可以把遇到问题的设备寄给我,可以更容易的复现问题。 111 +5. 你可以把遇到问题的设备寄给我,可以更容易的兼容设备和解决问题。
111 112
112 # 使用帮助 113 # 使用帮助
113 QQ群: 901799015, ZLM使用文档[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit) 114 QQ群: 901799015, ZLM使用文档[https://github.com/ZLMediaKit/ZLMediaKit](https://github.com/ZLMediaKit/ZLMediaKit)
doc/_content/ability/gis.md
@@ -14,7 +14,7 @@ WVP提供了简单的电子地图用于设备的定位以及移动设备的轨 @@ -14,7 +14,7 @@ WVP提供了简单的电子地图用于设备的定位以及移动设备的轨
14 PS: 目前的底图仅用用作演示和学习,商用情况请自行购买授权使用。 14 PS: 目前的底图仅用用作演示和学习,商用情况请自行购买授权使用。
15 15
16 ### 更换底图以及底图配置 16 ### 更换底图以及底图配置
17 -目前WVP支持使用了更换底图,配置文件在web_src/static/js/mapConfig.js,请修改后重新编译前端文件。 17 +目前WVP支持使用了更换底图,配置文件在web_src/static/js/config.js,请修改后重新编译前端文件。
18 ```javascript 18 ```javascript
19 window.mapParam = { 19 window.mapParam = {
20 // 开启/关闭地图功能 20 // 开启/关闭地图功能
doc/_content/introduction/deployment.md
@@ -27,13 +27,32 @@ @@ -27,13 +27,32 @@
27 ```shell 27 ```shell
28 nohup java -jar wvp-pro-*.jar & 28 nohup java -jar wvp-pro-*.jar &
29 ``` 29 ```
30 -war包: 30 +**war包:**
31 下载Tomcat后将war包放入webapps中,启动Tomcat以解压war包,停止Tomcat后,删除ROOT目录以及war包,将解压后的war包目录重命名为ROOT,将配置文件中的Server.port配置为与Tomcat端口一致 31 下载Tomcat后将war包放入webapps中,启动Tomcat以解压war包,停止Tomcat后,删除ROOT目录以及war包,将解压后的war包目录重命名为ROOT,将配置文件中的Server.port配置为与Tomcat端口一致
32 然后启动Tomcat。 32 然后启动Tomcat。
33 **启动ZLM** 33 **启动ZLM**
34 ```shell 34 ```shell
35 nohup ./MediaServer -d -m 3 & 35 nohup ./MediaServer -d -m 3 &
36 ``` 36 ```
37 - 37 +### 前后端分离部署
  38 +前后端部署目前在最新的版本已经支持,请使用3月15日之后的版本部署
  39 +前端编译后的文件在`src/main/resources/static`中,将此目录下的文件部署。
  40 +前后端分离部署最大的问题是跨域的解决,之前版本使用cookie完成登录流程,而cookie是不可以在复杂跨域中使用的。所以当前版本使用JWT生成的TOKEN作为认证凭据,
  41 +部署前端后需要在wvp中配置前端访问的地址以完成跨域流程。
  42 +**配置前端服务器**
  43 +1. 假如你的服务有公网域名为xxx.com,公网IP为11.11.11.11, 那么你可以在wvp中这样配置:
  44 +```yaml
  45 +user-settings:
  46 + # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
  47 + allowed-origins:
  48 + - http://xxx.com:8008
  49 + - http://11.11.11.11:8008
  50 +```
  51 +配置不是必须的,你使用哪个ip/域名访问就配置哪个即可。修改配置后重启wvp以使配置生效。
  52 +2. 在`src/main/resources/static/static/js/config.js`下配置服务器的地址,也就是wvp服务的地址
  53 +```javascript
  54 +window.baseUrl = "http://xxx.com:18080"
  55 +```
  56 +`这里的地址是需要客户电脑能访问到的,因为请求是客户端电脑发起,与代理不同`
38 [接入设备](./_content/ability/device.md) 57 [接入设备](./_content/ability/device.md)
39 58
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 11
12 <groupId>com.genersoft</groupId> 12 <groupId>com.genersoft</groupId>
13 <artifactId>wvp-pro</artifactId> 13 <artifactId>wvp-pro</artifactId>
14 - <version>2.6.7</version> 14 + <version>2.6.8</version>
15 <name>web video platform</name> 15 <name>web video platform</name>
16 <description>国标28181视频平台</description> 16 <description>国标28181视频平台</description>
17 <packaging>${project.packaging}</packaging> 17 <packaging>${project.packaging}</packaging>
@@ -123,11 +123,9 @@ @@ -123,11 +123,9 @@
123 <artifactId>spring-boot-starter-security</artifactId> 123 <artifactId>spring-boot-starter-security</artifactId>
124 </dependency> 124 </dependency>
125 125
126 - <!-- druid数据库连接池 -->  
127 <dependency> 126 <dependency>
128 - <groupId>com.alibaba</groupId>  
129 - <artifactId>druid-spring-boot-starter</artifactId>  
130 - <version>1.2.11</version> 127 + <groupId>org.springframework.boot</groupId>
  128 + <artifactId>spring-boot-starter-jdbc</artifactId>
131 </dependency> 129 </dependency>
132 130
133 <!-- mysql数据库 --> 131 <!-- mysql数据库 -->
@@ -216,8 +214,6 @@ @@ -216,8 +214,6 @@
216 <version>4.10.0</version> 214 <version>4.10.0</version>
217 </dependency> 215 </dependency>
218 216
219 -  
220 -  
221 <!-- okhttp-digest --> 217 <!-- okhttp-digest -->
222 <dependency> 218 <dependency>
223 <groupId>io.github.rburgst</groupId> 219 <groupId>io.github.rburgst</groupId>
@@ -226,10 +222,17 @@ @@ -226,10 +222,17 @@
226 </dependency> 222 </dependency>
227 223
228 <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 --> 224 <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
  225 +<!-- <dependency>-->
  226 +<!-- <groupId>net.sf.kxml</groupId>-->
  227 +<!-- <artifactId>kxml2</artifactId>-->
  228 +<!-- <version>2.3.0</version>-->
  229 +<!-- </dependency>-->
  230 +
  231 + <!-- jwt实现 -->
229 <dependency> 232 <dependency>
230 - <groupId>net.sf.kxml</groupId>  
231 - <artifactId>kxml2</artifactId>  
232 - <version>2.3.0</version> 233 + <groupId>org.bitbucket.b_c</groupId>
  234 + <artifactId>jose4j</artifactId>
  235 + <version>0.9.3</version>
233 </dependency> 236 </dependency>
234 237
235 <!--反向代理--> 238 <!--反向代理-->
@@ -289,7 +292,7 @@ @@ -289,7 +292,7 @@
289 <plugin> 292 <plugin>
290 <groupId>org.springframework.boot</groupId> 293 <groupId>org.springframework.boot</groupId>
291 <artifactId>spring-boot-maven-plugin</artifactId> 294 <artifactId>spring-boot-maven-plugin</artifactId>
292 - <version>2.3.5.RELEASE</version> 295 + <version>2.7.2</version>
293 <configuration> 296 <configuration>
294 <includeSystemScope>true</includeSystemScope> 297 <includeSystemScope>true</includeSystemScope>
295 </configuration> 298 </configuration>
sql/2.6.6-2.6.7更新.sql 0 → 100755
  1 +alter table device
  2 + add asMessageChannel int default 0;
  3 +
  4 +alter table parent_platform
  5 + add asMessageChannel int default 0;
  6 +
  7 +alter table device
  8 + add mediaServerId varchar(50) default null;
  9 +
  10 +
  11 +
  12 +
src/main/resources/db/migration/V2.6.7_20230201__初始化.sql renamed to sql/初始化.sql
@@ -32,6 +32,7 @@ CREATE TABLE `device` ( @@ -32,6 +32,7 @@ CREATE TABLE `device` (
32 `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 32 `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
33 `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 33 `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
34 `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 34 `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
  35 + `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
35 `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 36 `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
36 `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 37 `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
37 `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 38 `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
@@ -47,6 +48,7 @@ CREATE TABLE `device` ( @@ -47,6 +48,7 @@ CREATE TABLE `device` (
47 `mobilePositionSubmissionInterval` int DEFAULT '5', 48 `mobilePositionSubmissionInterval` int DEFAULT '5',
48 `subscribeCycleForAlarm` int DEFAULT NULL, 49 `subscribeCycleForAlarm` int DEFAULT NULL,
49 `ssrcCheck` int DEFAULT '0', 50 `ssrcCheck` int DEFAULT '0',
  51 + `asMessageChannel` int DEFAULT '0',
50 `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 52 `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
51 `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 53 `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
52 `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL, 54 `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
@@ -329,6 +331,7 @@ CREATE TABLE `parent_platform` ( @@ -329,6 +331,7 @@ CREATE TABLE `parent_platform` (
329 `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 331 `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
330 `ptz` int DEFAULT NULL, 332 `ptz` int DEFAULT NULL,
331 `rtcp` int DEFAULT NULL, 333 `rtcp` int DEFAULT NULL,
  334 + `asMessageChannel` int DEFAULT '0',
332 `status` bit(1) DEFAULT NULL, 335 `status` bit(1) DEFAULT NULL,
333 `startOfflinePush` int DEFAULT '0', 336 `startOfflinePush` int DEFAULT '0',
334 `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL, 337 `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
1 package com.genersoft.iot.vmp; 1 package com.genersoft.iot.vmp;
2 2
3 -import com.genersoft.iot.vmp.conf.druid.EnableDruidSupport;  
4 import com.genersoft.iot.vmp.utils.GitUtil; 3 import com.genersoft.iot.vmp.utils.GitUtil;
5 import com.genersoft.iot.vmp.utils.SpringBeanFactory; 4 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
6 import org.slf4j.Logger; 5 import org.slf4j.Logger;
@@ -25,7 +24,6 @@ import java.util.Collections; @@ -25,7 +24,6 @@ import java.util.Collections;
25 @ServletComponentScan("com.genersoft.iot.vmp.conf") 24 @ServletComponentScan("com.genersoft.iot.vmp.conf")
26 @SpringBootApplication 25 @SpringBootApplication
27 @EnableScheduling 26 @EnableScheduling
28 -@EnableDruidSupport  
29 public class VManageBootstrap extends SpringBootServletInitializer { 27 public class VManageBootstrap extends SpringBootServletInitializer {
30 28
31 private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class); 29 private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.common; @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.common;
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4
5 import java.io.Serializable; 5 import java.io.Serializable;
  6 +import java.util.Objects;
6 7
7 @Schema(description = "流信息") 8 @Schema(description = "流信息")
8 public class StreamInfo implements Serializable, Cloneable{ 9 public class StreamInfo implements Serializable, Cloneable{
@@ -168,7 +169,7 @@ public class StreamInfo implements Serializable, Cloneable{ @@ -168,7 +169,7 @@ public class StreamInfo implements Serializable, Cloneable{
168 } 169 }
169 170
170 public void setRtmp(String host, int port, int sslPort, String app, String stream, String callIdParam) { 171 public void setRtmp(String host, int port, int sslPort, String app, String stream, String callIdParam) {
171 - String file = String.format("%s/%s/%s", app, stream, callIdParam); 172 + String file = String.format("%s/%s%s", app, stream, callIdParam);
172 if (port > 0) { 173 if (port > 0) {
173 this.rtmp = new StreamURL("rtmp", host, port, file); 174 this.rtmp = new StreamURL("rtmp", host, port, file);
174 } 175 }
@@ -178,7 +179,7 @@ public class StreamInfo implements Serializable, Cloneable{ @@ -178,7 +179,7 @@ public class StreamInfo implements Serializable, Cloneable{
178 } 179 }
179 180
180 public void setRtsp(String host, int port, int sslPort, String app, String stream, String callIdParam) { 181 public void setRtsp(String host, int port, int sslPort, String app, String stream, String callIdParam) {
181 - String file = String.format("%s/%s/%s", app, stream, callIdParam); 182 + String file = String.format("%s/%s%s", app, stream, callIdParam);
182 if (port > 0) { 183 if (port > 0) {
183 this.rtsp = new StreamURL("rtsp", host, port, file); 184 this.rtsp = new StreamURL("rtsp", host, port, file);
184 } 185 }
@@ -236,8 +237,11 @@ public class StreamInfo implements Serializable, Cloneable{ @@ -236,8 +237,11 @@ public class StreamInfo implements Serializable, Cloneable{
236 } 237 }
237 } 238 }
238 239
239 - public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam, boolean isPlay) {  
240 - String file = String.format("index/api/webrtc?app=%s&stream=%s&type=%s%s", app, stream, isPlay?"play":"push", callIdParam); 240 + public void setRtc(String host, int port, int sslPort, String app, String stream, String callIdParam) {
  241 + if (callIdParam != null) {
  242 + callIdParam = Objects.equals(callIdParam, "") ? callIdParam : callIdParam.replace("?", "&");
  243 + }
  244 + String file = String.format("index/api/webrtc?app=%s&stream=%s&type=play%s", app, stream, callIdParam);
241 if (port > 0) { 245 if (port > 0) {
242 this.rtc = new StreamURL("http", host, port, file); 246 this.rtc = new StreamURL("http", host, port, file);
243 } 247 }
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
@@ -66,9 +66,7 @@ public class ApiAccessFilter extends OncePerRequestFilter { @@ -66,9 +66,7 @@ public class ApiAccessFilter extends OncePerRequestFilter {
66 logDto.setUri(servletRequest.getRequestURI()); 66 logDto.setUri(servletRequest.getRequestURI());
67 logDto.setCreateTime(DateUtil.getNow()); 67 logDto.setCreateTime(DateUtil.getNow());
68 logService.add(logDto); 68 logService.add(logDto);
69 -// logger.warn("[Api Access] [{}] [{}] [{}] [{}] [{}] {}ms",  
70 -// uriName, servletRequest.getMethod(), servletRequest.getRequestURI(), servletRequest.getRemoteAddr(), HttpStatus.valueOf(servletResponse.getStatus()),  
71 -// System.currentTimeMillis() - start); 69 +
72 70
73 } 71 }
74 } 72 }
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory; @@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
8 import org.springframework.http.HttpStatus; 8 import org.springframework.http.HttpStatus;
9 import org.springframework.http.ResponseEntity; 9 import org.springframework.http.ResponseEntity;
10 import org.springframework.security.authentication.BadCredentialsException; 10 import org.springframework.security.authentication.BadCredentialsException;
  11 +import org.springframework.web.HttpRequestMethodNotSupportedException;
11 import org.springframework.web.bind.annotation.ExceptionHandler; 12 import org.springframework.web.bind.annotation.ExceptionHandler;
12 import org.springframework.web.bind.annotation.ResponseStatus; 13 import org.springframework.web.bind.annotation.ResponseStatus;
13 import org.springframework.web.bind.annotation.RestControllerAdvice; 14 import org.springframework.web.bind.annotation.RestControllerAdvice;
@@ -32,6 +33,28 @@ public class GlobalExceptionHandler { @@ -32,6 +33,28 @@ public class GlobalExceptionHandler {
32 return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage()); 33 return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());
33 } 34 }
34 35
  36 + /**
  37 + * 默认异常处理
  38 + * @param e 异常
  39 + * @return 统一返回结果
  40 + */
  41 + @ExceptionHandler(IllegalStateException.class)
  42 + @ResponseStatus(HttpStatus.BAD_REQUEST)
  43 + public WVPResult<String> exceptionHandler(IllegalStateException e) {
  44 + return WVPResult.fail(ErrorCode.ERROR400);
  45 + }
  46 +
  47 + /**
  48 + * 默认异常处理
  49 + * @param e 异常
  50 + * @return 统一返回结果
  51 + */
  52 + @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
  53 + @ResponseStatus(HttpStatus.BAD_REQUEST)
  54 + public WVPResult<String> exceptionHandler(HttpRequestMethodNotSupportedException e) {
  55 + return WVPResult.fail(ErrorCode.ERROR400);
  56 + }
  57 +
35 58
36 /** 59 /**
37 * 自定义异常处理, 处理controller中返回的错误 60 * 自定义异常处理, 处理controller中返回的错误
src/main/java/com/genersoft/iot/vmp/conf/GlobalResponseAdvice.java
@@ -10,14 +10,11 @@ import org.springframework.context.annotation.Bean; @@ -10,14 +10,11 @@ import org.springframework.context.annotation.Bean;
10 import org.springframework.core.MethodParameter; 10 import org.springframework.core.MethodParameter;
11 import org.springframework.http.MediaType; 11 import org.springframework.http.MediaType;
12 import org.springframework.http.converter.HttpMessageConverter; 12 import org.springframework.http.converter.HttpMessageConverter;
13 -import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;  
14 import org.springframework.http.server.ServerHttpRequest; 13 import org.springframework.http.server.ServerHttpRequest;
15 import org.springframework.http.server.ServerHttpResponse; 14 import org.springframework.http.server.ServerHttpResponse;
16 import org.springframework.web.bind.annotation.RestControllerAdvice; 15 import org.springframework.web.bind.annotation.RestControllerAdvice;
17 import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; 16 import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
18 17
19 -import java.util.List;  
20 -  
21 /** 18 /**
22 * 全局统一返回结果 19 * 全局统一返回结果
23 * @author lin 20 * @author lin
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.conf; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.conf;
2 2
3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 3 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
4 import com.genersoft.iot.vmp.service.IMediaServerService; 4 import com.genersoft.iot.vmp.service.IMediaServerService;
  5 +import org.apache.catalina.connector.ClientAbortException;
5 import org.apache.http.HttpHost; 6 import org.apache.http.HttpHost;
6 import org.apache.http.HttpRequest; 7 import org.apache.http.HttpRequest;
7 import org.apache.http.HttpResponse; 8 import org.apache.http.HttpResponse;
@@ -169,13 +170,14 @@ public class ProxyServletConfig { @@ -169,13 +170,14 @@ public class ProxyServletConfig {
169 protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) { 170 protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
170 String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString); 171 String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
171 MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI()); 172 MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
172 - String remoteHost = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());  
173 - if (mediaInfo != null) {  
174 - if (!ObjectUtils.isEmpty(queryStr)) {  
175 - queryStr += "&remoteHost=" + remoteHost;  
176 - }else {  
177 - queryStr = "remoteHost=" + remoteHost;  
178 - } 173 + if (mediaInfo == null) {
  174 + return null;
  175 + }
  176 + String remoteHost = String.format("http://%s:%s", mediaInfo.getStreamIp(), mediaInfo.getRecordAssistPort());
  177 + if (!ObjectUtils.isEmpty(queryStr)) {
  178 + queryStr += "&remoteHost=" + remoteHost;
  179 + }else {
  180 + queryStr = "remoteHost=" + remoteHost;
179 } 181 }
180 return queryStr; 182 return queryStr;
181 } 183 }
@@ -192,6 +194,12 @@ public class ProxyServletConfig { @@ -192,6 +194,12 @@ public class ProxyServletConfig {
192 } catch (IOException ioException) { 194 } catch (IOException ioException) {
193 if (ioException instanceof ConnectException) { 195 if (ioException instanceof ConnectException) {
194 logger.error("录像服务 连接失败"); 196 logger.error("录像服务 连接失败");
  197 + }else if (ioException instanceof ClientAbortException) {
  198 + /**
  199 + * TODO 使用这个代理库实现代理在遇到代理视频文件时,如果是206结果,会遇到报错蛋市目前功能正常,
  200 + * TODO 暂时去除异常处理。后续使用其他代理框架修改测试
  201 + */
  202 +
195 }else { 203 }else {
196 logger.error("录像服务 代理失败: ", e); 204 logger.error("录像服务 代理失败: ", e);
197 } 205 }
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
@@ -4,7 +4,6 @@ package com.genersoft.iot.vmp.conf; @@ -4,7 +4,6 @@ package com.genersoft.iot.vmp.conf;
4 import org.junit.jupiter.api.Order; 4 import org.junit.jupiter.api.Order;
5 import org.springframework.boot.context.properties.ConfigurationProperties; 5 import org.springframework.boot.context.properties.ConfigurationProperties;
6 import org.springframework.stereotype.Component; 6 import org.springframework.stereotype.Component;
7 -import org.springframework.util.ObjectUtils;  
8 7
9 @Component 8 @Component
10 @ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true) 9 @ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true)
@@ -13,6 +12,8 @@ public class SipConfig { @@ -13,6 +12,8 @@ public class SipConfig {
13 12
14 private String ip; 13 private String ip;
15 14
  15 + private String showIp;
  16 +
16 private Integer port; 17 private Integer port;
17 18
18 private String domain; 19 private String domain;
@@ -96,4 +97,14 @@ public class SipConfig { @@ -96,4 +97,14 @@ public class SipConfig {
96 this.alarm = alarm; 97 this.alarm = alarm;
97 } 98 }
98 99
  100 + public String getShowIp() {
  101 + if (this.showIp == null) {
  102 + return this.ip;
  103 + }
  104 + return showIp;
  105 + }
  106 +
  107 + public void setShowIp(String showIp) {
  108 + this.showIp = showIp;
  109 + }
99 } 110 }
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
@@ -40,17 +40,20 @@ public class SipPlatformRunner implements CommandLineRunner { @@ -40,17 +40,20 @@ public class SipPlatformRunner implements CommandLineRunner {
40 List<ParentPlatform> parentPlatforms = storager.queryEnableParentPlatformList(true); 40 List<ParentPlatform> parentPlatforms = storager.queryEnableParentPlatformList(true);
41 41
42 for (ParentPlatform parentPlatform : parentPlatforms) { 42 for (ParentPlatform parentPlatform : parentPlatforms) {
  43 +
  44 + ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
  45 +
43 // 更新缓存 46 // 更新缓存
44 ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch(); 47 ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
45 parentPlatformCatch.setParentPlatform(parentPlatform); 48 parentPlatformCatch.setParentPlatform(parentPlatform);
46 parentPlatformCatch.setId(parentPlatform.getServerGBId()); 49 parentPlatformCatch.setId(parentPlatform.getServerGBId());
47 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); 50 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
48 - // 设置所有平台离线  
49 - platformService.offline(parentPlatform, true);  
50 // 取消订阅 51 // 取消订阅
51 - sipCommanderForPlatform.unregister(parentPlatform, null, (eventResult)->{ 52 + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
52 platformService.login(parentPlatform); 53 platformService.login(parentPlatform);
53 }); 54 });
  55 + // 设置所有平台离线
  56 + platformService.offline(parentPlatform, true);
54 } 57 }
55 } 58 }
56 } 59 }
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -50,15 +50,22 @@ public class UserSetting { @@ -50,15 +50,22 @@ public class UserSetting {
50 private Boolean pushStreamAfterAck = Boolean.FALSE; 50 private Boolean pushStreamAfterAck = Boolean.FALSE;
51 51
52 private Boolean sipLog = Boolean.FALSE; 52 private Boolean sipLog = Boolean.FALSE;
  53 + private Boolean sendToPlatformsWhenIdLost = Boolean.FALSE;
  54 +
  55 + private Boolean refuseChannelStatusChannelFormNotify = Boolean.FALSE;
53 56
54 private String serverId = "000000"; 57 private String serverId = "000000";
55 58
  59 + private String recordPath = null;
  60 +
56 private String thirdPartyGBIdReg = "[\\s\\S]*"; 61 private String thirdPartyGBIdReg = "[\\s\\S]*";
57 62
58 private String broadcastForPlatform = "UDP"; 63 private String broadcastForPlatform = "UDP";
59 64
60 private List<String> interfaceAuthenticationExcludes = new ArrayList<>(); 65 private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
61 66
  67 + private List<String> allowedOrigins = new ArrayList<>();
  68 +
62 public Boolean getSavePositionHistory() { 69 public Boolean getSavePositionHistory() {
63 return savePositionHistory; 70 return savePositionHistory;
64 } 71 }
@@ -238,4 +245,36 @@ public class UserSetting { @@ -238,4 +245,36 @@ public class UserSetting {
238 public void setSipLog(Boolean sipLog) { 245 public void setSipLog(Boolean sipLog) {
239 this.sipLog = sipLog; 246 this.sipLog = sipLog;
240 } 247 }
  248 +
  249 + public List<String> getAllowedOrigins() {
  250 + return allowedOrigins;
  251 + }
  252 +
  253 + public void setAllowedOrigins(List<String> allowedOrigins) {
  254 + this.allowedOrigins = allowedOrigins;
  255 + }
  256 +
  257 + public Boolean getSendToPlatformsWhenIdLost() {
  258 + return sendToPlatformsWhenIdLost;
  259 + }
  260 +
  261 + public void setSendToPlatformsWhenIdLost(Boolean sendToPlatformsWhenIdLost) {
  262 + this.sendToPlatformsWhenIdLost = sendToPlatformsWhenIdLost;
  263 + }
  264 +
  265 + public Boolean getRefuseChannelStatusChannelFormNotify() {
  266 + return refuseChannelStatusChannelFormNotify;
  267 + }
  268 +
  269 + public void setRefuseChannelStatusChannelFormNotify(Boolean refuseChannelStatusChannelFormNotify) {
  270 + this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify;
  271 + }
  272 +
  273 + public String getRecordPath() {
  274 + return recordPath;
  275 + }
  276 +
  277 + public void setRecordPath(String recordPath) {
  278 + this.recordPath = recordPath;
  279 + }
241 } 280 }
src/main/java/com/genersoft/iot/vmp/conf/druid/DruidConfiguration.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.conf.druid;  
2 -  
3 -import com.alibaba.druid.support.http.StatViewServlet;  
4 -import com.alibaba.druid.support.http.WebStatFilter;  
5 -import org.springframework.beans.factory.annotation.Value;  
6 -import org.springframework.boot.web.servlet.FilterRegistrationBean;  
7 -import org.springframework.boot.web.servlet.ServletRegistrationBean;  
8 -import org.springframework.context.annotation.Bean;  
9 -  
10 -import javax.servlet.Filter;  
11 -import javax.servlet.Servlet;  
12 -  
13 -/**  
14 - * druid监控配置  
15 - * @author  
16 - */  
17 -public class DruidConfiguration {  
18 -  
19 - @Value("${rj-druid-manage.allow:127.0.0.1}")  
20 - private String allow;  
21 -  
22 - @Value("${rj-druid-manage.deny:}")  
23 - private String deny;  
24 -  
25 - @Value("${rj-druid-manage.loginUsername:admin}")  
26 - private String loginUsername;  
27 -  
28 - @Value("${rj-druid-manage.loginPassword:admin}")  
29 - private String loginPassword;  
30 -  
31 - @Value("${rj-druid-manage.resetEnable:false}")  
32 - private String resetEnable;  
33 -  
34 - /**  
35 - * druid监控页面开启  
36 - */  
37 - @Bean  
38 - public ServletRegistrationBean druidServlet() {  
39 - ServletRegistrationBean<Servlet> servletRegistrationBean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");  
40 - // IP白名单  
41 - servletRegistrationBean.addInitParameter("allow", allow);  
42 - // IP黑名单(共同存在时,deny优先于allow)  
43 - servletRegistrationBean.addInitParameter("deny", deny);  
44 - //控制台管理用户  
45 - servletRegistrationBean.addInitParameter("loginUsername", loginUsername);  
46 - servletRegistrationBean.addInitParameter("loginPassword", loginPassword);  
47 - //是否能够重置数据 禁用HTML页面上的“Reset All”功能  
48 - servletRegistrationBean.addInitParameter("resetEnable", resetEnable);  
49 - return servletRegistrationBean;  
50 - }  
51 -  
52 - /**  
53 - * druid url监控配置  
54 - */  
55 - @Bean  
56 - public FilterRegistrationBean filterRegistrationBean() {  
57 - FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>(new WebStatFilter());  
58 - filterRegistrationBean.addUrlPatterns("/*");  
59 - filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");  
60 - return filterRegistrationBean;  
61 - }  
62 -  
63 -  
64 -}  
65 \ No newline at end of file 0 \ No newline at end of file
src/main/java/com/genersoft/iot/vmp/conf/druid/EnableDruidSupport.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.conf.druid;  
2 -  
3 -import org.springframework.boot.web.servlet.ServletComponentScan;  
4 -import org.springframework.context.annotation.Import;  
5 -  
6 -import java.lang.annotation.*;  
7 -  
8 -/**  
9 - * druid监控支持注解  
10 - *  
11 - * @author  
12 - * {@link DruidConfiguration} druid监控页面安全配置支持  
13 - * {@link ServletComponentScan} druid监控页面需要扫描servlet  
14 - */  
15 -@Target(ElementType.TYPE)  
16 -@Retention(RetentionPolicy.RUNTIME)  
17 -@Documented  
18 -@Inherited  
19 -@Import({  
20 - DruidConfiguration.class,  
21 -})  
22 -@ServletComponentScan  
23 -public @interface EnableDruidSupport {  
24 -}  
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
1 package com.genersoft.iot.vmp.conf.security; 1 package com.genersoft.iot.vmp.conf.security;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
4 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 5 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
5 -import org.apache.poi.hssf.eventmodel.ERFListener;  
6 -import org.slf4j.Logger;  
7 -import org.slf4j.LoggerFactory; 6 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
8 import org.springframework.security.core.AuthenticationException; 7 import org.springframework.security.core.AuthenticationException;
  8 +import org.springframework.security.core.context.SecurityContextHolder;
9 import org.springframework.security.web.AuthenticationEntryPoint; 9 import org.springframework.security.web.AuthenticationEntryPoint;
10 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
11 11
@@ -18,17 +18,15 @@ import java.io.IOException; @@ -18,17 +18,15 @@ import java.io.IOException;
18 * @author lin 18 * @author lin
19 */ 19 */
20 @Component 20 @Component
21 -public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {  
22 -  
23 - private final static Logger logger = LoggerFactory.getLogger(DefaultUserDetailsServiceImpl.class); 21 +public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
24 22
25 @Override 23 @Override
26 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) { 24 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
27 - // 允许跨域  
28 - response.setHeader("Access-Control-Allow-Origin", "*");  
29 - // 允许自定义请求头token(允许head跨域)  
30 - response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");  
31 - response.setHeader("Content-type", "application/json;charset=UTF-8"); 25 + String jwt = request.getHeader(JwtUtils.getHeader());
  26 + JwtUser jwtUser = JwtUtils.verifyToken(jwt);
  27 + String username = jwtUser.getUserName();
  28 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword() );
  29 + SecurityContextHolder.getContext().setAuthentication(token);
32 JSONObject jsonObject = new JSONObject(); 30 JSONObject jsonObject = new JSONObject();
33 jsonObject.put("code", ErrorCode.ERROR401.getCode()); 31 jsonObject.put("code", ErrorCode.ERROR401.getCode());
34 jsonObject.put("msg", ErrorCode.ERROR401.getMsg()); 32 jsonObject.put("msg", ErrorCode.ERROR401.getMsg());
src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
1 package com.genersoft.iot.vmp.conf.security; 1 package com.genersoft.iot.vmp.conf.security;
2 2
3 -import java.time.LocalDateTime;  
4 - 3 +import com.alibaba.excel.util.StringUtils;
  4 +import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
  5 +import com.genersoft.iot.vmp.service.IUserService;
  6 +import com.genersoft.iot.vmp.storager.dao.dto.User;
5 import org.slf4j.Logger; 7 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory; 8 import org.slf4j.LoggerFactory;
7 import org.springframework.beans.factory.annotation.Autowired; 9 import org.springframework.beans.factory.annotation.Autowired;
@@ -10,10 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService; @@ -10,10 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
10 import org.springframework.security.core.userdetails.UsernameNotFoundException; 12 import org.springframework.security.core.userdetails.UsernameNotFoundException;
11 import org.springframework.stereotype.Component; 13 import org.springframework.stereotype.Component;
12 14
13 -import com.alibaba.excel.util.StringUtils;  
14 -import com.genersoft.iot.vmp.conf.security.dto.LoginUser;  
15 -import com.genersoft.iot.vmp.service.IUserService;  
16 -import com.genersoft.iot.vmp.storager.dao.dto.User; 15 +import java.time.LocalDateTime;
17 16
18 /** 17 /**
19 * 用户登录认证逻辑 18 * 用户登录认证逻辑
@@ -45,4 +44,8 @@ public class DefaultUserDetailsServiceImpl implements UserDetailsService { @@ -45,4 +44,8 @@ public class DefaultUserDetailsServiceImpl implements UserDetailsService {
45 } 44 }
46 45
47 46
  47 +
  48 +
  49 +
  50 +
48 } 51 }
src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.conf.security;  
2 -  
3 -import org.slf4j.Logger;  
4 -import org.slf4j.LoggerFactory;  
5 -import org.springframework.security.web.session.InvalidSessionStrategy;  
6 -  
7 -import javax.servlet.ServletException;  
8 -import javax.servlet.http.HttpServletRequest;  
9 -import javax.servlet.http.HttpServletResponse;  
10 -import java.io.IOException;  
11 -  
12 -/**  
13 - * 登录超时的处理  
14 - */  
15 -public class InvalidSessionHandler implements InvalidSessionStrategy {  
16 -  
17 - private final static Logger logger = LoggerFactory.getLogger(InvalidSessionHandler.class);  
18 -  
19 - @Override  
20 - public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException, ServletException {  
21 - String username = request.getParameter("username");  
22 - logger.info("[登录超时] - [{}]", username);  
23 - }  
24 -}  
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security;
  2 +
  3 +import com.genersoft.iot.vmp.conf.UserSetting;
  4 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
  5 +import org.apache.commons.lang3.StringUtils;
  6 +import org.springframework.beans.factory.annotation.Autowired;
  7 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  8 +import org.springframework.security.core.context.SecurityContextHolder;
  9 +import org.springframework.stereotype.Component;
  10 +import org.springframework.web.filter.OncePerRequestFilter;
  11 +
  12 +import javax.servlet.FilterChain;
  13 +import javax.servlet.ServletException;
  14 +import javax.servlet.http.HttpServletRequest;
  15 +import javax.servlet.http.HttpServletResponse;
  16 +import java.io.IOException;
  17 +import java.util.ArrayList;
  18 +
  19 +/**
  20 + * jwt token 过滤器
  21 + */
  22 +
  23 +@Component
  24 +public class JwtAuthenticationFilter extends OncePerRequestFilter {
  25 +
  26 +
  27 + @Autowired
  28 + private UserSetting userSetting;
  29 +
  30 +
  31 + @Override
  32 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
  33 +
  34 + // 忽略登录请求的token验证
  35 + String requestURI = request.getRequestURI();
  36 + if (requestURI.equalsIgnoreCase("/api/user/login")) {
  37 + chain.doFilter(request, response);
  38 + return;
  39 + }
  40 + if (!userSetting.isInterfaceAuthentication()) {
  41 + // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
  42 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(null, null, new ArrayList<>() );
  43 + SecurityContextHolder.getContext().setAuthentication(token);
  44 + chain.doFilter(request, response);
  45 + return;
  46 + }
  47 + String jwt = request.getHeader(JwtUtils.getHeader());
  48 + // 这里如果没有jwt,继续往后走,因为后面还有鉴权管理器等去判断是否拥有身份凭证,所以是可以放行的
  49 + // 没有jwt相当于匿名访问,若有一些接口是需要权限的,则不能访问这些接口
  50 + if (StringUtils.isBlank(jwt)) {
  51 + jwt = request.getParameter(JwtUtils.getHeader());
  52 + if (StringUtils.isBlank(jwt)) {
  53 + chain.doFilter(request, response);
  54 + return;
  55 + }
  56 + }
  57 +
  58 + JwtUser jwtUser = JwtUtils.verifyToken(jwt);
  59 + String username = jwtUser.getUserName();
  60 + // TODO 处理各个状态
  61 + switch (jwtUser.getStatus()){
  62 + case EXPIRED:
  63 + response.setStatus(400);
  64 + chain.doFilter(request, response);
  65 + // 异常
  66 + return;
  67 + case EXCEPTION:
  68 + // 过期
  69 + response.setStatus(400);
  70 + chain.doFilter(request, response);
  71 + return;
  72 + case EXPIRING_SOON:
  73 + // 即将过期
  74 +// return;
  75 + default:
  76 + }
  77 +
  78 + // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
  79 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword(), new ArrayList<>() );
  80 + SecurityContextHolder.getContext().setAuthentication(token);
  81 + chain.doFilter(request, response);
  82 + }
  83 +
  84 +}
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security;
  2 +
  3 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
  4 +import org.jose4j.json.JsonUtil;
  5 +import org.jose4j.jwk.RsaJsonWebKey;
  6 +import org.jose4j.jws.AlgorithmIdentifiers;
  7 +import org.jose4j.jws.JsonWebSignature;
  8 +import org.jose4j.jwt.JwtClaims;
  9 +import org.jose4j.jwt.NumericDate;
  10 +import org.jose4j.jwt.consumer.ErrorCodes;
  11 +import org.jose4j.jwt.consumer.InvalidJwtException;
  12 +import org.jose4j.jwt.consumer.JwtConsumer;
  13 +import org.jose4j.jwt.consumer.JwtConsumerBuilder;
  14 +import org.jose4j.lang.JoseException;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +
  18 +import java.security.PrivateKey;
  19 +import java.time.LocalDateTime;
  20 +import java.time.ZoneOffset;
  21 +
  22 +public class JwtUtils {
  23 +
  24 + private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
  25 +
  26 + private static final String HEADER = "access-token";
  27 + private static final String AUDIENCE = "Audience";
  28 +
  29 + private static final long EXPIRED_THRESHOLD = 10 * 60;
  30 +
  31 + private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
  32 + private static final String privateKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\",\"d\":\"ed7U_k3rJ4yTk70JtRSIfjKGiEb67BO1TabcymnljKO7RU8nage84zZYuSu_XpQsHk6P1f0Gzxkicghm_Er-FrfVn2pp70Xu52z3yRd6BJUgWLDFk97ngScIyw5OiULKU9SrZk2frDpftNCSUcIgb50F8m0QAnBa_CdPsQKbuuhLv8V8tBAV7F_lAwvSBgu56wRo3hPz5dWH8YeXM7XBfQ9viFMNEKd21sP_j5C7ueUnXT66nBxe3ZJEU3iuMYM6D6dB_KW2GfZC6WmTgvGhhxJD0h7aYmfjkD99MDleB7SkpbvoODOqiQ5Epb7Nyh6kv5u4KUv2CJYtATLZkUeMkQ\",\"p\":\"uBUjWPWtlGksmOqsqCNWksfqJvMcnP_8TDYN7e4-WnHL4N-9HjRuPDnp6kHvCIEi9SEfxm7gNxlRcWegvNQr3IZCz7TnCTexXc5NOklB9OavWFla6u-s3Thn6Tz45-EUjpJr0VJMxhO-KxGmuTwUXBBp4vN6K2qV6rQNFmgkWzk\",\"q\":\"tW_i7cCec56bHkhITL_79dXHz_PLC_f7xlynmlZJGU_d6mqOKmLBNBbTMLnYW8uAFiFzWxDeDHh1o5uF0mSQR-Z1Fg35OftnpbWpy0Cbc2la5WgXQjOwtG1eLYIY2BD3-wQ1VYDBCvowr4FDi-sngxwLqvwmrJ0xjhi99O-Gzcs\",\"dp\":\"q1d5jE85Hz_6M-eTh_lEluEf0NtPEc-vvhw-QO4V-cecNpbrCBdTWBmr4dE3NdpFeJc5ZVFEv-SACyei1MBEh0ItI_pFZi4BmMfy2ELh8ptaMMkTOESYyVy8U7veDq9RnBcr5i1Nqr0rsBkA77-9T6gzdvycBZdzLYAkAmwzEvk\",\"dq\":\"q29A2K08Crs-jmp2Bi8Q_8QzvIX6wSBbwZ4ir24AO-5_HNP56IrPS0yV2GCB0pqCOGb6_Hz_koDvhtuYoqdqvMVAtMoXR3YJBUaVXPt65p4RyNmFwIPe31zHs_BNUTsXVRMw4c16mci03-Af1sEm4HdLfxAp6sfM3xr5wcnhcek\",\"qi\":\"rHPgVTyHUHuYzcxfouyBfb1XAY8nshwn0ddo81o1BccD4Z7zo5It6SefDHjxCAbcmbiCcXBSooLcY-NF5FMv3fg19UE21VyLQltHcVjRRp2tRs4OHcM8yaXIU2x6N6Z6BP2tOksHb9MOBY1wAQzFOAKg_G4Sxev6-_6ud6RISuc\"}";
  33 + private static final String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\"}";
  34 +
  35 + /**
  36 + * token过期时间(分钟)
  37 + */
  38 + public static final long expirationTime = 30;
  39 +
  40 + public static String createToken(String username, String password) {
  41 + try {
  42 + /**
  43 + * “iss” (issuer) 发行人
  44 + *
  45 + * “sub” (subject) 主题
  46 + *
  47 + * “aud” (audience) 接收方 用户
  48 + *
  49 + * “exp” (expiration time) 到期时间
  50 + *
  51 + * “nbf” (not before) 在此之前不可用
  52 + *
  53 + * “iat” (issued at) jwt的签发时间
  54 + */
  55 + //Payload
  56 + JwtClaims claims = new JwtClaims();
  57 + claims.setGeneratedJwtId();
  58 + claims.setIssuedAtToNow();
  59 + // 令牌将过期的时间 分钟
  60 + claims.setExpirationTimeMinutesInTheFuture(expirationTime);
  61 + claims.setNotBeforeMinutesInThePast(0);
  62 + claims.setSubject("login");
  63 + claims.setAudience(AUDIENCE);
  64 + //添加自定义参数,必须是字符串类型
  65 + claims.setClaim("username", username);
  66 + claims.setClaim("password", password);
  67 +
  68 + //jws
  69 + JsonWebSignature jws = new JsonWebSignature();
  70 + //签名算法RS256
  71 + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
  72 + jws.setKeyIdHeaderValue(keyId);
  73 + jws.setPayload(claims.toJson());
  74 +
  75 + PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
  76 + jws.setKey(privateKey);
  77 +
  78 + //get token
  79 + String idToken = jws.getCompactSerialization();
  80 + return idToken;
  81 + } catch (JoseException e) {
  82 + logger.error("[Token生成失败]: {}", e.getMessage());
  83 + }
  84 +
  85 + return null;
  86 + }
  87 +
  88 + public static String getHeader() {
  89 + return HEADER;
  90 + }
  91 +
  92 +
  93 + public static JwtUser verifyToken(String token) {
  94 +
  95 + JwtUser jwtUser = new JwtUser();
  96 +
  97 + try {
  98 + JwtConsumer consumer = new JwtConsumerBuilder()
  99 + .setRequireExpirationTime()
  100 + .setMaxFutureValidityInMinutes(5256000)
  101 + .setAllowedClockSkewInSeconds(30)
  102 + .setRequireSubject()
  103 + //.setExpectedIssuer("")
  104 + .setExpectedAudience(AUDIENCE)
  105 + .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
  106 + .build();
  107 +
  108 + JwtClaims claims = consumer.processToClaims(token);
  109 + NumericDate expirationTime = claims.getExpirationTime();
  110 + // 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
  111 + // 剩余时间 (秒)
  112 + long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
  113 + if (timeRemaining < 5 * 60) {
  114 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
  115 + }else {
  116 + jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
  117 + }
  118 +
  119 + String username = (String) claims.getClaimValue("username");
  120 + String password = (String) claims.getClaimValue("password");
  121 + jwtUser.setUserName(username);
  122 + jwtUser.setPassword(password);
  123 +
  124 + return jwtUser;
  125 + } catch (InvalidJwtException e) {
  126 + if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
  127 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
  128 + }else {
  129 + jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
  130 + }
  131 + return jwtUser;
  132 + }catch (Exception e) {
  133 + logger.error("[Token解析失败]: {}", e.getMessage());
  134 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
  135 + return jwtUser;
  136 + }
  137 + }
  138 +}
src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
@@ -21,7 +21,16 @@ public class LoginSuccessHandler implements AuthenticationSuccessHandler { @@ -21,7 +21,16 @@ public class LoginSuccessHandler implements AuthenticationSuccessHandler {
21 21
22 @Override 22 @Override
23 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { 23 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
24 - String username = request.getParameter("username");  
25 - logger.info("[登录成功] - [{}]", username); 24 +// String username = request.getParameter("username");
  25 +// httpServletResponse.setContentType("application/json;charset=UTF-8");
  26 +// // 生成JWT,并放置到请求头中
  27 +// String jwt = JwtUtils.createToken(authentication.getName(), );
  28 +// httpServletResponse.setHeader(JwtUtils.getHeader(), jwt);
  29 +// ServletOutputStream outputStream = httpServletResponse.getOutputStream();
  30 +// outputStream.write(JSON.toJSONString(ErrorCode.SUCCESS).getBytes(StandardCharsets.UTF_8));
  31 +// outputStream.flush();
  32 +// outputStream.close();
  33 +
  34 +// logger.info("[登录成功] - [{}]", username);
26 } 35 }
27 } 36 }
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
1 package com.genersoft.iot.vmp.conf.security; 1 package com.genersoft.iot.vmp.conf.security;
2 2
3 import com.genersoft.iot.vmp.conf.security.dto.LoginUser; 3 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
  4 +import com.genersoft.iot.vmp.storager.dao.dto.User;
4 import org.springframework.security.authentication.AuthenticationManager; 5 import org.springframework.security.authentication.AuthenticationManager;
5 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 6 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
6 import org.springframework.security.core.Authentication; 7 import org.springframework.security.core.Authentication;
@@ -9,6 +10,7 @@ import org.springframework.security.core.context.SecurityContextHolder; @@ -9,6 +10,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
9 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 10 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 11
11 import javax.security.sasl.AuthenticationException; 12 import javax.security.sasl.AuthenticationException;
  13 +import java.time.LocalDateTime;
12 14
13 public class SecurityUtils { 15 public class SecurityUtils {
14 16
@@ -25,9 +27,12 @@ public class SecurityUtils { @@ -25,9 +27,12 @@ public class SecurityUtils {
25 public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException { 27 public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException {
26 //使用security框架自带的验证token生成器 也可以自定义。 28 //使用security框架自带的验证token生成器 也可以自定义。
27 UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password); 29 UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password);
  30 + //认证 如果失败,这里会自动异常后返回,所以这里不需要判断返回值是否为空,确定是否登录成功
28 Authentication authenticate = authenticationManager.authenticate(token); 31 Authentication authenticate = authenticationManager.authenticate(token);
29 - SecurityContextHolder.getContext().setAuthentication(authenticate);  
30 LoginUser user = (LoginUser) authenticate.getPrincipal(); 32 LoginUser user = (LoginUser) authenticate.getPrincipal();
  33 +
  34 + SecurityContextHolder.getContext().setAuthentication(token);
  35 +
31 return user; 36 return user;
32 } 37 }
33 38
@@ -49,8 +54,13 @@ public class SecurityUtils { @@ -49,8 +54,13 @@ public class SecurityUtils {
49 if(authentication!=null){ 54 if(authentication!=null){
50 Object principal = authentication.getPrincipal(); 55 Object principal = authentication.getPrincipal();
51 if(principal!=null && !"anonymousUser".equals(principal)){ 56 if(principal!=null && !"anonymousUser".equals(principal)){
52 - LoginUser user = (LoginUser) authentication.getPrincipal();  
53 - return user; 57 +// LoginUser user = (LoginUser) authentication.getPrincipal();
  58 +
  59 + String username = (String) principal;
  60 + User user = new User();
  61 + user.setUsername(username);
  62 + LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
  63 + return loginUser;
54 } 64 }
55 } 65 }
56 return null; 66 return null;
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -15,9 +15,16 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -15,9 +15,16 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15 import org.springframework.security.config.annotation.web.builders.WebSecurity; 15 import org.springframework.security.config.annotation.web.builders.WebSecurity;
16 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 16 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
17 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 17 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  18 +import org.springframework.security.config.http.SessionCreationPolicy;
18 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 19 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  20 +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  21 +import org.springframework.web.cors.CorsConfiguration;
  22 +import org.springframework.web.cors.CorsConfigurationSource;
  23 +import org.springframework.web.cors.CorsUtils;
  24 +import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
19 25
20 -import java.util.List; 26 +import java.util.ArrayList;
  27 +import java.util.Arrays;
21 28
22 /** 29 /**
23 * 配置Spring Security 30 * 配置Spring Security
@@ -56,22 +63,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -56,22 +63,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
56 */ 63 */
57 @Autowired 64 @Autowired
58 private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint; 65 private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint;
59 -// /**  
60 -// * 超时处理  
61 -// */  
62 -// @Autowired  
63 -// private InvalidSessionHandler invalidSessionHandler;  
64 -  
65 -// /**  
66 -// * 顶号处理  
67 -// */  
68 -// @Autowired  
69 -// private SessionInformationExpiredHandler sessionInformationExpiredHandler;  
70 -// /**  
71 -// * 登录用户没有权限访问资源  
72 -// */  
73 -// @Autowired  
74 -// private LoginUserAccessDeniedHandler accessDeniedHandler; 66 + @Autowired
  67 + private JwtAuthenticationFilter jwtAuthenticationFilter;
75 68
76 69
77 /** 70 /**
@@ -80,31 +73,21 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -80,31 +73,21 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
80 @Override 73 @Override
81 public void configure(WebSecurity web) { 74 public void configure(WebSecurity web) {
82 75
83 - if (!userSetting.isInterfaceAuthentication()) {  
84 - web.ignoring().antMatchers("**");  
85 - }else {  
86 - // 可以直接访问的静态数据  
87 - web.ignoring()  
88 - .antMatchers("/")  
89 - .antMatchers("/#/**")  
90 - .antMatchers("/static/**")  
91 - .antMatchers("/index.html")  
92 - .antMatchers("/doc.html") // "/webjars/**", "/swagger-resources/**", "/v3/api-docs/**"  
93 - .antMatchers("/webjars/**")  
94 - .antMatchers("/swagger-resources/**")  
95 - .antMatchers("/v3/api-docs/**")  
96 - .antMatchers("/favicon.ico")  
97 - .antMatchers("/js/**");  
98 - List<String> interfaceAuthenticationExcludes = userSetting.getInterfaceAuthenticationExcludes();  
99 - for (String interfaceAuthenticationExclude : interfaceAuthenticationExcludes) {  
100 - if (interfaceAuthenticationExclude.split("/").length < 4 ) {  
101 - logger.warn("{}不满足两级目录,已忽略", interfaceAuthenticationExclude);  
102 - }else {  
103 - web.ignoring().antMatchers(interfaceAuthenticationExclude);  
104 - }  
105 -  
106 - }  
107 - } 76 + ArrayList<String> matchers = new ArrayList<>();
  77 + matchers.add("/");
  78 + matchers.add("/#/**");
  79 + matchers.add("/static/**");
  80 + matchers.add("/index.html");
  81 + matchers.add("/doc.html");
  82 + matchers.add("/webjars/**");
  83 + matchers.add("/swagger-resources/**");
  84 + matchers.add("/v3/api-docs/**");
  85 + matchers.add("/js/**");
  86 + matchers.add("/api/device/query/snap/**");
  87 + matchers.add("/record_proxy/*/**");
  88 + matchers.addAll(userSetting.getInterfaceAuthenticationExcludes());
  89 + // 可以直接访问的静态数据
  90 + web.ignoring().antMatchers(matchers.toArray(new String[0]));
108 } 91 }
109 92
110 /** 93 /**
@@ -126,36 +109,43 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @@ -126,36 +109,43 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
126 109
127 @Override 110 @Override
128 protected void configure(HttpSecurity http) throws Exception { 111 protected void configure(HttpSecurity http) throws Exception {
129 - http.cors().and().csrf().disable();  
130 - // 设置允许添加静态文件  
131 - http.headers().contentTypeOptions().disable();  
132 - http.authorizeRequests()  
133 - // 放行接口  
134 - .antMatchers("/api/user/login","/index/hook/**").permitAll()  
135 - // 除上面外的所有请求全部需要鉴权认证 112 + http.headers().contentTypeOptions().disable()
  113 + .and().cors().configurationSource(configurationSource())
  114 + .and().csrf().disable()
  115 + .sessionManagement()
  116 + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  117 +
  118 + // 配置拦截规则
  119 + .and()
  120 + .authorizeRequests()
  121 + .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
  122 + .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
  123 + .antMatchers("/api/user/login","/index/hook/**","/zlm_Proxy/FhTuMYqB2HeCuNOb/record/t/1/2023-03-25/16:35:07-16:35:16-9353.mp4").permitAll()
136 .anyRequest().authenticated() 124 .anyRequest().authenticated()
137 - // 异常处理(权限拒绝、登录失效等)  
138 - .and().exceptionHandling()  
139 - //匿名用户访问无权限资源时的异常处理 125 + // 异常处理器
  126 + .and()
  127 + .exceptionHandling()
140 .authenticationEntryPoint(anonymousAuthenticationEntryPoint) 128 .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
141 -// .accessDeniedHandler(accessDeniedHandler)//登录用户没有权限访问资源  
142 - // 登入 允许所有用户  
143 - .and().formLogin().permitAll()  
144 - //登录成功处理逻辑  
145 - .successHandler(loginSuccessHandler)  
146 - //登录失败处理逻辑  
147 - .failureHandler(loginFailureHandler)  
148 - // 登出  
149 .and().logout().logoutUrl("/api/user/logout").permitAll() 129 .and().logout().logoutUrl("/api/user/logout").permitAll()
150 - //登出成功处理逻辑  
151 .logoutSuccessHandler(logoutHandler) 130 .logoutSuccessHandler(logoutHandler)
152 - .deleteCookies("JSESSIONID")  
153 - // 会话管理  
154 -// .and().sessionManagement().invalidSessionStrategy(invalidSessionHandler) // 超时处理  
155 -// .maximumSessions(1)//同一账号同时登录最大用户数  
156 -// .expiredSessionStrategy(sessionInformationExpiredHandler) // 顶号处理  
157 ; 131 ;
  132 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
  133 +
  134 + }
158 135
  136 + CorsConfigurationSource configurationSource(){
  137 + // 配置跨域
  138 + CorsConfiguration corsConfiguration = new CorsConfiguration();
  139 + corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
  140 + corsConfiguration.setAllowedMethods(Arrays.asList("*"));
  141 + corsConfiguration.setMaxAge(3600L);
  142 + corsConfiguration.setAllowCredentials(true);
  143 + corsConfiguration.setAllowedOrigins(userSetting.getAllowedOrigins());
  144 + corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader()));
  145 +
  146 + UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource();
  147 + url.registerCorsConfiguration("/**",corsConfiguration);
  148 + return url;
159 } 149 }
160 150
161 /** 151 /**
src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security.dto;
  2 +
  3 +public class JwtUser {
  4 +
  5 + public enum TokenStatus{
  6 + /**
  7 + * 正常的使用状态
  8 + */
  9 + NORMAL,
  10 + /**
  11 + * 过期而失效
  12 + */
  13 + EXPIRED,
  14 + /**
  15 + * 即将过期
  16 + */
  17 + EXPIRING_SOON,
  18 + /**
  19 + * 异常
  20 + */
  21 + EXCEPTION
  22 + }
  23 +
  24 + private String userName;
  25 +
  26 + private String password;
  27 +
  28 + private TokenStatus status;
  29 +
  30 + public String getUserName() {
  31 + return userName;
  32 + }
  33 +
  34 + public void setUserName(String userName) {
  35 + this.userName = userName;
  36 + }
  37 +
  38 + public TokenStatus getStatus() {
  39 + return status;
  40 + }
  41 +
  42 + public void setStatus(TokenStatus status) {
  43 + this.status = status;
  44 + }
  45 +
  46 + public String getPassword() {
  47 + return password;
  48 + }
  49 +
  50 + public void setPassword(String password) {
  51 + this.password = password;
  52 + }
  53 +}
src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
@@ -19,6 +19,8 @@ public class LoginUser implements UserDetails, CredentialsContainer { @@ -19,6 +19,8 @@ public class LoginUser implements UserDetails, CredentialsContainer {
19 */ 19 */
20 private User user; 20 private User user;
21 21
  22 + private String accessToken;
  23 +
22 24
23 /** 25 /**
24 * 登录时间 26 * 登录时间
@@ -102,4 +104,11 @@ public class LoginUser implements UserDetails, CredentialsContainer { @@ -102,4 +104,11 @@ public class LoginUser implements UserDetails, CredentialsContainer {
102 return user.getPushKey(); 104 return user.getPushKey();
103 } 105 }
104 106
  107 + public String getAccessToken() {
  108 + return accessToken;
  109 + }
  110 +
  111 + public void setAccessToken(String accessToken) {
  112 + this.accessToken = accessToken;
  113 + }
105 } 114 }
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -171,7 +171,7 @@ public class DigestServerAuthenticationHelper { @@ -171,7 +171,7 @@ public class DigestServerAuthenticationHelper {
171 */ 171 */
172 public boolean doAuthenticatePlainTextPassword(Request request, String pass) { 172 public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
173 AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); 173 AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
174 - if ( authHeader == null ) { 174 + if ( authHeader == null || authHeader.getRealm() == null) {
175 return false; 175 return false;
176 } 176 }
177 String realm = authHeader.getRealm().trim(); 177 String realm = authHeader.getRealm().trim();
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
@@ -188,6 +188,13 @@ public class Device { @@ -188,6 +188,13 @@ public class Device {
188 @Schema(description = "SIP交互IP(设备访问平台的IP)") 188 @Schema(description = "SIP交互IP(设备访问平台的IP)")
189 private String localIp; 189 private String localIp;
190 190
  191 + @Schema(description = "是否作为消息通道")
  192 + private boolean asMessageChannel;
  193 +
  194 + @Schema(description = "设备注册的事务信息")
  195 + private SipTransactionInfo sipTransactionInfo;
  196 +
  197 +
191 public String getDeviceId() { 198 public String getDeviceId() {
192 return deviceId; 199 return deviceId;
193 } 200 }
@@ -428,4 +435,20 @@ public class Device { @@ -428,4 +435,20 @@ public class Device {
428 public void setKeepaliveIntervalTime(int keepaliveIntervalTime) { 435 public void setKeepaliveIntervalTime(int keepaliveIntervalTime) {
429 this.keepaliveIntervalTime = keepaliveIntervalTime; 436 this.keepaliveIntervalTime = keepaliveIntervalTime;
430 } 437 }
  438 +
  439 + public boolean isAsMessageChannel() {
  440 + return asMessageChannel;
  441 + }
  442 +
  443 + public void setAsMessageChannel(boolean asMessageChannel) {
  444 + this.asMessageChannel = asMessageChannel;
  445 + }
  446 +
  447 + public SipTransactionInfo getSipTransactionInfo() {
  448 + return sipTransactionInfo;
  449 + }
  450 +
  451 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  452 + this.sipTransactionInfo = sipTransactionInfo;
  453 + }
431 } 454 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java
@@ -189,6 +189,9 @@ public class ParentPlatform { @@ -189,6 +189,9 @@ public class ParentPlatform {
189 @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou") 189 @Schema(description = "树类型 国标规定了两种树的展现方式 行政区划 CivilCode 和业务分组:BusinessGrou")
190 private String treeType; 190 private String treeType;
191 191
  192 + @Schema(description = "是否作为消息通道")
  193 + private boolean asMessageChannel;
  194 +
192 public Integer getId() { 195 public Integer getId() {
193 return id; 196 return id;
194 } 197 }
@@ -428,4 +431,12 @@ public class ParentPlatform { @@ -428,4 +431,12 @@ public class ParentPlatform {
428 public void setTreeType(String treeType) { 431 public void setTreeType(String treeType) {
429 this.treeType = treeType; 432 this.treeType = treeType;
430 } 433 }
  434 +
  435 + public boolean isAsMessageChannel() {
  436 + return asMessageChannel;
  437 + }
  438 +
  439 + public void setAsMessageChannel(boolean asMessageChannel) {
  440 + this.asMessageChannel = asMessageChannel;
  441 + }
431 } 442 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
@@ -16,6 +16,8 @@ public class ParentPlatformCatch { @@ -16,6 +16,8 @@ public class ParentPlatformCatch {
16 16
17 private ParentPlatform parentPlatform; 17 private ParentPlatform parentPlatform;
18 18
  19 + private SipTransactionInfo sipTransactionInfo;
  20 +
19 public String getId() { 21 public String getId() {
20 return id; 22 return id;
21 } 23 }
@@ -55,4 +57,12 @@ public class ParentPlatformCatch { @@ -55,4 +57,12 @@ public class ParentPlatformCatch {
55 public void setCallId(String callId) { 57 public void setCallId(String callId) {
56 this.callId = callId; 58 this.callId = callId;
57 } 59 }
  60 +
  61 + public SipTransactionInfo getSipTransactionInfo() {
  62 + return sipTransactionInfo;
  63 + }
  64 +
  65 + public void setSipTransactionInfo(SipTransactionInfo sipTransactionInfo) {
  66 + this.sipTransactionInfo = sipTransactionInfo;
  67 + }
58 } 68 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 3
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +
4 import java.time.Instant; 6 import java.time.Instant;
5 import java.util.List; 7 import java.util.List;
6 8
@@ -9,22 +11,29 @@ import java.util.List; @@ -9,22 +11,29 @@ import java.util.List;
9 * @author: swwheihei 11 * @author: swwheihei
10 * @date: 2020年5月8日 下午2:05:56 12 * @date: 2020年5月8日 下午2:05:56
11 */ 13 */
  14 +@Schema(description = "设备录像查询结果信息")
12 public class RecordInfo { 15 public class RecordInfo {
13 16
  17 + @Schema(description = "设备编号")
14 private String deviceId; 18 private String deviceId;
15 19
  20 + @Schema(description = "通道编号")
16 private String channelId; 21 private String channelId;
17 22
  23 + @Schema(description = "命令序列号")
18 private String sn; 24 private String sn;
19 25
  26 + @Schema(description = "设备名称")
20 private String name; 27 private String name;
21 - 28 +
  29 + @Schema(description = "列表总数")
22 private int sumNum; 30 private int sumNum;
23 31
24 private int count; 32 private int count;
25 33
26 private Instant lastTime; 34 private Instant lastTime;
27 - 35 +
  36 + @Schema(description = "")
28 private List<RecordItem> recordList; 37 private List<RecordItem> recordList;
29 38
30 public String getDeviceId() { 39 public String getDeviceId() {
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
@@ -2,9 +2,9 @@ package com.genersoft.iot.vmp.gb28181.bean; @@ -2,9 +2,9 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 3
4 import com.genersoft.iot.vmp.utils.DateUtil; 4 import com.genersoft.iot.vmp.utils.DateUtil;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
5 import org.jetbrains.annotations.NotNull; 6 import org.jetbrains.annotations.NotNull;
6 7
7 -import java.text.ParseException;  
8 import java.time.Instant; 8 import java.time.Instant;
9 import java.time.temporal.TemporalAccessor; 9 import java.time.temporal.TemporalAccessor;
10 10
@@ -13,26 +13,37 @@ import java.time.temporal.TemporalAccessor; @@ -13,26 +13,37 @@ import java.time.temporal.TemporalAccessor;
13 * @author: swwheihei 13 * @author: swwheihei
14 * @date: 2020年5月8日 下午2:06:54 14 * @date: 2020年5月8日 下午2:06:54
15 */ 15 */
  16 +@Schema(description = "设备录像详情")
16 public class RecordItem implements Comparable<RecordItem>{ 17 public class RecordItem implements Comparable<RecordItem>{
17 18
  19 + @Schema(description = "设备编号")
18 private String deviceId; 20 private String deviceId;
19 - 21 +
  22 + @Schema(description = "名称")
20 private String name; 23 private String name;
21 - 24 +
  25 + @Schema(description = "文件路径名 (可选)")
22 private String filePath; 26 private String filePath;
23 27
  28 + @Schema(description = "录像文件大小,单位:Byte(可选)")
24 private String fileSize; 29 private String fileSize;
25 30
  31 + @Schema(description = "录像地址(可选)")
26 private String address; 32 private String address;
27 - 33 +
  34 + @Schema(description = "录像开始时间(可选)")
28 private String startTime; 35 private String startTime;
29 - 36 +
  37 + @Schema(description = "录像结束时间(可选)")
30 private String endTime; 38 private String endTime;
31 - 39 +
  40 + @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密")
32 private int secrecy; 41 private int secrecy;
33 - 42 +
  43 + @Schema(description = "录像产生类型(可选)time或alarm 或 manua")
34 private String type; 44 private String type;
35 - 45 +
  46 + @Schema(description = "录像触发者ID(可选)")
36 private String recorderId; 47 private String recorderId;
37 48
38 public String getDeviceId() { 49 public String getDeviceId() {
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java
1 package com.genersoft.iot.vmp.gb28181.event.device; 1 package com.genersoft.iot.vmp.gb28181.event.device;
2 2
3 import com.genersoft.iot.vmp.gb28181.bean.Device; 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
5 import com.genersoft.iot.vmp.service.IDeviceService; 4 import com.genersoft.iot.vmp.service.IDeviceService;
6 import org.springframework.beans.factory.annotation.Autowired; 5 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.context.ApplicationListener; 6 import org.springframework.context.ApplicationListener;
@@ -9,8 +8,6 @@ import org.springframework.stereotype.Component; @@ -9,8 +8,6 @@ import org.springframework.stereotype.Component;
9 8
10 import javax.sip.ClientTransaction; 9 import javax.sip.ClientTransaction;
11 import javax.sip.address.SipURI; 10 import javax.sip.address.SipURI;
12 -import javax.sip.header.CallIdHeader;  
13 -import javax.sip.header.ToHeader;  
14 import javax.sip.message.Request; 11 import javax.sip.message.Request;
15 12
16 /** 13 /**
@@ -34,7 +31,7 @@ public class RequestTimeoutEventImpl implements ApplicationListener&lt;RequestTimeo @@ -34,7 +31,7 @@ public class RequestTimeoutEventImpl implements ApplicationListener&lt;RequestTimeo
34 if (device == null) { 31 if (device == null) {
35 return; 32 return;
36 } 33 }
37 - deviceService.offline(device.getDeviceId()); 34 + deviceService.offline(device.getDeviceId(), "等待消息超时");
38 } 35 }
39 36
40 } 37 }
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
@@ -61,9 +61,9 @@ public class SipRunner implements CommandLineRunner { @@ -61,9 +61,9 @@ public class SipRunner implements CommandLineRunner {
61 61
62 for (Device device : deviceList) { 62 for (Device device : deviceList) {
63 if (deviceService.expire(device)){ 63 if (deviceService.expire(device)){
64 - deviceService.offline(device.getDeviceId()); 64 + deviceService.offline(device.getDeviceId(), "注册已过期");
65 }else { 65 }else {
66 - deviceService.online(device); 66 + deviceService.online(device, null);
67 } 67 }
68 } 68 }
69 // 重置cseq计数 69 // 重置cseq计数
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -120,7 +120,7 @@ public interface ISIPCommander { @@ -120,7 +120,7 @@ public interface ISIPCommander {
120 */ 120 */
121 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 121 void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
122 String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent, 122 String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
123 - SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; 123 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
124 124
125 125
126 /** 126 /**
@@ -217,7 +217,6 @@ public interface ISIPCommander { @@ -217,7 +217,6 @@ public interface ISIPCommander {
217 * 217 *
218 * @param device 视频设备 218 * @param device 视频设备
219 * @param channelId 通道id,非通道则是设备本身 219 * @param channelId 通道id,非通道则是设备本身
220 - * @param frontCmd 上级平台的指令,如果存在则直接下发  
221 * @param enabled 看守位使能:1 = 开启,0 = 关闭 220 * @param enabled 看守位使能:1 = 开启,0 = 关闭
222 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) 221 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
223 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 222 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
@@ -22,12 +22,10 @@ public interface ISIPCommanderForPlatform { @@ -22,12 +22,10 @@ public interface ISIPCommanderForPlatform {
22 * @param parentPlatform 22 * @param parentPlatform
23 * @return 23 * @return
24 */ 24 */
25 - void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)  
26 - throws InvalidArgumentException, ParseException, SipException; 25 + void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
27 26
28 - void register(ParentPlatform parentPlatform, String callId, WWWAuthenticateHeader www,  
29 - SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister)  
30 - throws SipException, InvalidArgumentException, ParseException; 27 + void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
  28 + void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
31 29
32 /** 30 /**
33 * 向上级平台注销 31 * 向上级平台注销
@@ -35,8 +33,7 @@ public interface ISIPCommanderForPlatform { @@ -35,8 +33,7 @@ public interface ISIPCommanderForPlatform {
35 * @param parentPlatform 33 * @param parentPlatform
36 * @return 34 * @return
37 */ 35 */
38 - void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent)  
39 - throws InvalidArgumentException, ParseException, SipException; 36 + void unregister(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
40 37
41 38
42 /** 39 /**
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
@@ -46,7 +46,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -46,7 +46,7 @@ public class SIPRequestHeaderPlarformProvider {
46 @Autowired 46 @Autowired
47 private IRedisCatchStorage redisCatchStorage; 47 private IRedisCatchStorage redisCatchStorage;
48 48
49 - public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, long CSeq, String fromTag, String viaTag, CallIdHeader callIdHeader, boolean isRegister) throws ParseException, InvalidArgumentException, PeerUnavailableException { 49 + public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, long CSeq, String fromTag, String toTag, CallIdHeader callIdHeader, boolean isRegister) throws ParseException, InvalidArgumentException, PeerUnavailableException {
50 Request request = null; 50 Request request = null;
51 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort(); 51 String sipAddress = parentPlatform.getDeviceIp() + ":" + parentPlatform.getDevicePort();
52 //请求行 52 //请求行
@@ -54,7 +54,8 @@ public class SIPRequestHeaderPlarformProvider { @@ -54,7 +54,8 @@ public class SIPRequestHeaderPlarformProvider {
54 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); 54 parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
55 //via 55 //via
56 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); 56 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
57 - ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(), parentPlatform.getServerPort(), parentPlatform.getTransport(), viaTag); 57 + ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(parentPlatform.getServerIP(),
  58 + parentPlatform.getServerPort(), parentPlatform.getTransport(), SipUtils.getNewViaTag());
58 viaHeader.setRPort(); 59 viaHeader.setRPort();
59 viaHeaders.add(viaHeader); 60 viaHeaders.add(viaHeader);
60 //from 61 //from
@@ -64,7 +65,7 @@ public class SIPRequestHeaderPlarformProvider { @@ -64,7 +65,7 @@ public class SIPRequestHeaderPlarformProvider {
64 //to 65 //to
65 SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain()); 66 SipURI toSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(), sipConfig.getDomain());
66 Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI); 67 Address toAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(toSipURI);
67 - ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,null); 68 + ToHeader toHeader = sipLayer.getSipFactory().createHeaderFactory().createToHeader(toAddress,toTag);
68 69
69 //Forwards 70 //Forwards
70 MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70); 71 MaxForwardsHeader maxForwards = sipLayer.getSipFactory().createHeaderFactory().createMaxForwardsHeader(70);
@@ -86,15 +87,21 @@ public class SIPRequestHeaderPlarformProvider { @@ -86,15 +87,21 @@ public class SIPRequestHeaderPlarformProvider {
86 return request; 87 return request;
87 } 88 }
88 89
89 - public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag,  
90 - String callId, WWWAuthenticateHeader www , CallIdHeader callIdHeader, boolean isRegister) throws ParseException, PeerUnavailableException, InvalidArgumentException { 90 + public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String toTag,
  91 + WWWAuthenticateHeader www , CallIdHeader callIdHeader, boolean isRegister) throws ParseException, PeerUnavailableException, InvalidArgumentException {
91 92
92 93
93 - Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, viaTag, callIdHeader, isRegister); 94 + Request registerRequest = createRegisterRequest(parentPlatform, redisCatchStorage.getCSEQ(), fromTag, toTag, callIdHeader, isRegister);
94 SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort()); 95 SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
95 if (www == null) { 96 if (www == null) {
96 AuthorizationHeader authorizationHeader = sipLayer.getSipFactory().createHeaderFactory().createAuthorizationHeader("Digest"); 97 AuthorizationHeader authorizationHeader = sipLayer.getSipFactory().createHeaderFactory().createAuthorizationHeader("Digest");
97 - authorizationHeader.setUsername(parentPlatform.getDeviceGBId()); 98 + String username = parentPlatform.getUsername();
  99 + if ( username == null || username == "" )
  100 + {
  101 + authorizationHeader.setUsername(parentPlatform.getDeviceGBId());
  102 + } else {
  103 + authorizationHeader.setUsername(username);
  104 + }
98 authorizationHeader.setURI(requestURI); 105 authorizationHeader.setURI(requestURI);
99 authorizationHeader.setAlgorithm("MD5"); 106 authorizationHeader.setAlgorithm("MD5");
100 registerRequest.addHeader(authorizationHeader); 107 registerRequest.addHeader(authorizationHeader);
@@ -108,8 +115,6 @@ public class SIPRequestHeaderPlarformProvider { @@ -108,8 +115,6 @@ public class SIPRequestHeaderPlarformProvider {
108 // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略 115 // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
109 String qop = www.getQop(); 116 String qop = www.getQop();
110 117
111 - callIdHeader.setCallId(callId);  
112 -  
113 String cNonce = null; 118 String cNonce = null;
114 String nc = "00000001"; 119 String nc = "00000001";
115 if (qop != null) { 120 if (qop != null) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -276,7 +276,7 @@ public class SIPCommander implements ISIPCommander { @@ -276,7 +276,7 @@ public class SIPCommander implements ISIPCommander {
276 return; 276 return;
277 } 277 }
278 278
279 - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); 279 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
280 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId()); 280 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
281 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 281 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
282 if (event != null) { 282 if (event != null) {
@@ -377,7 +377,7 @@ public class SIPCommander implements ISIPCommander { @@ -377,7 +377,7 @@ public class SIPCommander implements ISIPCommander {
377 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { 377 SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
378 378
379 379
380 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); 380 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort());
381 String sdpIp; 381 String sdpIp;
382 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 382 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
383 sdpIp = device.getSdpIp(); 383 sdpIp = device.getSdpIp();
@@ -479,10 +479,11 @@ public class SIPCommander implements ISIPCommander { @@ -479,10 +479,11 @@ public class SIPCommander implements ISIPCommander {
479 */ 479 */
480 @Override 480 @Override
481 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, 481 public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
482 - String startTime, String endTime, int downloadSpeed, InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,  
483 - SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { 482 + String startTime, String endTime, int downloadSpeed,
  483 + InviteStreamCallback inviteStreamCallback, InviteStreamCallback hookEvent,
  484 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
484 485
485 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort()); 486 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getSdpIp(), mediaServerItem.getIp(), ssrcInfo.getPort());
486 String sdpIp; 487 String sdpIp;
487 if (!ObjectUtils.isEmpty(device.getSdpIp())) { 488 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
488 sdpIp = device.getSdpIp(); 489 sdpIp = device.getSdpIp();
@@ -549,11 +550,14 @@ public class SIPCommander implements ISIPCommander { @@ -549,11 +550,14 @@ public class SIPCommander implements ISIPCommander {
549 content.append("a=downloadspeed:" + downloadSpeed + "\r\n"); 550 content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
550 551
551 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc 552 content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
552 - 553 + logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
553 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId()); 554 HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, null, mediaServerItem.getId());
554 // 添加订阅 555 // 添加订阅
  556 + CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
  557 + String callId=newCallIdHeader.getCallId();
555 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> { 558 subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject json) -> {
556 - hookEvent.call(new InviteStreamInfo(mediaServerItem, json,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream())); 559 + logger.debug("sipc 添加订阅===callId {}",callId);
  560 + hookEvent.call(new InviteStreamInfo(mediaServerItem, json,callId, "rtp", ssrcInfo.getStream()));
557 subscribe.removeSubscribe(hookSubscribe); 561 subscribe.removeSubscribe(hookSubscribe);
558 hookSubscribe.getContent().put("regist", false); 562 hookSubscribe.getContent().put("regist", false);
559 hookSubscribe.getContent().put("schema", "rtsp"); 563 hookSubscribe.getContent().put("schema", "rtsp");
@@ -562,7 +566,7 @@ public class SIPCommander implements ISIPCommander { @@ -562,7 +566,7 @@ public class SIPCommander implements ISIPCommander {
562 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> { 566 (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd) -> {
563 logger.info("[录像]下载结束, 发送BYE"); 567 logger.info("[录像]下载结束, 发送BYE");
564 try { 568 try {
565 - streamByeCmd(device, channelId, ssrcInfo.getStream(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId()); 569 + streamByeCmd(device, channelId, ssrcInfo.getStream(),callId);
566 } catch (InvalidArgumentException | ParseException | SipException | 570 } catch (InvalidArgumentException | ParseException | SipException |
567 SsrcTransactionNotFoundException e) { 571 SsrcTransactionNotFoundException e) {
568 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage()); 572 logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
@@ -570,15 +574,24 @@ public class SIPCommander implements ISIPCommander { @@ -570,15 +574,24 @@ public class SIPCommander implements ISIPCommander {
570 }); 574 });
571 }); 575 });
572 576
573 - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc()); 577 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
574 if (inviteStreamCallback != null) { 578 if (inviteStreamCallback != null) {
575 - inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), "rtp", ssrcInfo.getStream())); 579 + inviteStreamCallback.call(new InviteStreamInfo(mediaServerItem, null,callId, "rtp", ssrcInfo.getStream()));
576 } 580 }
577 581
578 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent -> {  
579 - ResponseEvent responseEvent = (ResponseEvent) okEvent.event; 582 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
  583 + ResponseEvent responseEvent = (ResponseEvent) event.event;
580 SIPResponse response = (SIPResponse) responseEvent.getResponse(); 584 SIPResponse response = (SIPResponse) responseEvent.getResponse();
581 - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download); 585 + String contentString =new String(response.getRawContent());
  586 + int ssrcIndex = contentString.indexOf("y=");
  587 + String ssrc=ssrcInfo.getSsrc();
  588 + if (ssrcIndex >= 0) {
  589 + ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  590 + }
  591 + logger.debug("接收到的下载响应ssrc====>{}",ssrcInfo.getSsrc());
  592 + logger.debug("接收到的下载响应ssrc====>{}",ssrc);
  593 + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, VideoStreamSessionManager.SessionType.download);
  594 + okEvent.response(event);
582 }); 595 });
583 } 596 }
584 597
@@ -778,7 +791,7 @@ public class SIPCommander implements ISIPCommander { @@ -778,7 +791,7 @@ public class SIPCommander implements ISIPCommander {
778 cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n"); 791 cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
779 cmdXml.append("</Control>\r\n"); 792 cmdXml.append("</Control>\r\n");
780 793
781 - 794 +
782 795
783 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); 796 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
784 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); 797 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
@@ -854,7 +867,6 @@ public class SIPCommander implements ISIPCommander { @@ -854,7 +867,6 @@ public class SIPCommander implements ISIPCommander {
854 * 867 *
855 * @param device 视频设备 868 * @param device 视频设备
856 * @param channelId 通道id,非通道则是设备本身 869 * @param channelId 通道id,非通道则是设备本身
857 - * @param frontCmd 上级平台的指令,如果存在则直接下发  
858 * @param enabled 看守位使能:1 = 开启,0 = 关闭 870 * @param enabled 看守位使能:1 = 开启,0 = 关闭
859 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s) 871 * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
860 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 872 * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
@@ -978,7 +990,7 @@ public class SIPCommander implements ISIPCommander { @@ -978,7 +990,7 @@ public class SIPCommander implements ISIPCommander {
978 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); 990 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
979 catalogXml.append("</Query>\r\n"); 991 catalogXml.append("</Query>\r\n");
980 992
981 - 993 +
982 994
983 Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); 995 Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
984 996
@@ -1181,7 +1193,6 @@ public class SIPCommander implements ISIPCommander { @@ -1181,7 +1193,6 @@ public class SIPCommander implements ISIPCommander {
1181 cmdXml.append("</Query>\r\n"); 1193 cmdXml.append("</Query>\r\n");
1182 1194
1183 1195
1184 -  
1185 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); 1196 Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
1186 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); 1197 sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
1187 } 1198 }
@@ -1427,7 +1438,7 @@ public class SIPCommander implements ISIPCommander { @@ -1427,7 +1438,7 @@ public class SIPCommander implements ISIPCommander {
1427 if (device == null) { 1438 if (device == null) {
1428 return; 1439 return;
1429 } 1440 }
1430 - logger.info("[发送 报警通知] {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(), 1441 + logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
1431 deviceAlarm.getLongitude(), deviceAlarm.getLatitude()); 1442 deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
1432 1443
1433 String characterSet = device.getCharset(); 1444 String characterSet = device.getCharset();
@@ -1439,7 +1450,7 @@ public class SIPCommander implements ISIPCommander { @@ -1439,7 +1450,7 @@ public class SIPCommander implements ISIPCommander {
1439 deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n"); 1450 deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
1440 deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n"); 1451 deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
1441 deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n"); 1452 deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
1442 - deviceStatusXml.append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n"); 1453 + deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n");
1443 deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n"); 1454 deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
1444 deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n"); 1455 deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
1445 deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n"); 1456 deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -24,6 +24,7 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; @@ -24,6 +24,7 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo;
24 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 24 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
25 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 25 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
26 import com.genersoft.iot.vmp.utils.DateUtil; 26 import com.genersoft.iot.vmp.utils.DateUtil;
  27 +import com.genersoft.iot.vmp.utils.GitUtil;
27 import gov.nist.javax.sip.message.MessageFactoryImpl; 28 import gov.nist.javax.sip.message.MessageFactoryImpl;
28 import gov.nist.javax.sip.message.SIPRequest; 29 import gov.nist.javax.sip.message.SIPRequest;
29 import gov.nist.javax.sip.message.SIPResponse; 30 import gov.nist.javax.sip.message.SIPResponse;
@@ -85,26 +86,49 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -85,26 +86,49 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
85 @Autowired 86 @Autowired
86 private DynamicTask dynamicTask; 87 private DynamicTask dynamicTask;
87 88
  89 + @Autowired
  90 + private GitUtil gitUtil;
  91 +
88 @Override 92 @Override
89 public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException { 93 public void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
90 register(parentPlatform, null, null, errorEvent, okEvent, false, true); 94 register(parentPlatform, null, null, errorEvent, okEvent, false, true);
91 } 95 }
92 96
93 @Override 97 @Override
94 - public void unregister(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {  
95 - register(parentPlatform, null, null, errorEvent, okEvent, false, false); 98 + public void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
  99 +
  100 + register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, false, true);
96 } 101 }
97 102
98 @Override 103 @Override
99 - public void register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable WWWAuthenticateHeader www, 104 + public void unregister(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException {
  105 + register(parentPlatform, sipTransactionInfo, null, errorEvent, okEvent, false, false);
  106 + }
  107 +
  108 + @Override
  109 + public void register(ParentPlatform parentPlatform, @Nullable SipTransactionInfo sipTransactionInfo, @Nullable WWWAuthenticateHeader www,
100 SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException { 110 SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean registerAgain, boolean isRegister) throws SipException, InvalidArgumentException, ParseException {
101 Request request; 111 Request request;
102 - if (!registerAgain ) {  
103 - CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());  
104 112
  113 + CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());
  114 + String fromTag = SipUtils.getNewFromTag();
  115 + String toTag = null;
  116 + if (sipTransactionInfo != null ) {
  117 + if (sipTransactionInfo.getCallId() != null) {
  118 + callIdHeader.setCallId(sipTransactionInfo.getCallId());
  119 + }
  120 + if (sipTransactionInfo.getFromTag() != null) {
  121 + fromTag = sipTransactionInfo.getFromTag();
  122 + }
  123 + if (sipTransactionInfo.getToTag() != null) {
  124 + toTag = sipTransactionInfo.getToTag();
  125 + }
  126 + }
  127 +
  128 + if (!registerAgain ) {
105 request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, 129 request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform,
106 - redisCatchStorage.getCSEQ(), SipUtils.getNewFromTag(),  
107 - SipUtils.getNewViaTag(), callIdHeader, isRegister); 130 + redisCatchStorage.getCSEQ(), fromTag,
  131 + toTag, callIdHeader, isRegister);
108 // 将 callid 写入缓存, 等注册成功可以更新状态 132 // 将 callid 写入缓存, 等注册成功可以更新状态
109 String callIdFromHeader = callIdHeader.getCallId(); 133 String callIdFromHeader = callIdHeader.getCallId();
110 redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister)); 134 redisCatchStorage.updatePlatformRegisterInfo(callIdFromHeader, PlatformRegisterInfo.getInstance(parentPlatform.getServerGBId(), isRegister));
@@ -122,8 +146,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -122,8 +146,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
122 }); 146 });
123 147
124 }else { 148 }else {
125 - CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(parentPlatform.getDeviceIp(),parentPlatform.getTransport());  
126 - request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, SipUtils.getNewFromTag(), null, callId, www, callIdHeader, isRegister); 149 + request = headerProviderPlatformProvider.createRegisterRequest(parentPlatform, fromTag, toTag, www, callIdHeader, isRegister);
127 } 150 }
128 151
129 sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, okEvent); 152 sipSender.transmitRequest(parentPlatform.getDeviceIp(), request, null, okEvent);
@@ -245,6 +268,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -245,6 +268,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
245 catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); 268 catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n");
246 catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); 269 catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n");
247 catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n"); 270 catalogXml.append("<Password>" + channel.getPort() + "</Password>\r\n");
  271 + catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n");
248 catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n"); 272 catalogXml.append("<Status>" + (channel.getStatus() == 1?"ON":"OFF") + "</Status>\r\n");
249 catalogXml.append("<Longitude>" + 273 catalogXml.append("<Longitude>" +
250 (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude()) 274 (channel.getLongitudeWgs84() != 0? channel.getLongitudeWgs84():channel.getLongitude())
@@ -285,6 +309,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -285,6 +309,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
285 309
286 String callId = request.getCallIdHeader().getCallId(); 310 String callId = request.getCallIdHeader().getCallId();
287 311
  312 + logger.info("[命令发送] 国标级联{} 目录查询回复: 共{}条,已发送{}条", parentPlatform.getServerGBId(),
  313 + channels.size(), Math.min(index + parentPlatform.getCatalogGroup(), channels.size()));
  314 + logger.debug(catalogXml);
288 if (sendAfterResponse) { 315 if (sendAfterResponse) {
289 // 默认按照收到200回复后发送下一条, 如果超时收不到回复,就以30毫秒的间隔直接发送。 316 // 默认按照收到200回复后发送下一条, 如果超时收不到回复,就以30毫秒的间隔直接发送。
290 dynamicTask.startDelay(timeoutTaskKey, ()->{ 317 dynamicTask.startDelay(timeoutTaskKey, ()->{
@@ -336,17 +363,22 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -336,17 +363,22 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
336 if (parentPlatform == null) { 363 if (parentPlatform == null) {
337 return; 364 return;
338 } 365 }
  366 + String deviceId = device == null ? parentPlatform.getDeviceGBId() : device.getDeviceId();
  367 + String deviceName = device == null ? parentPlatform.getName() : device.getName();
  368 + String manufacturer = device == null ? "WVP-28181-PRO" : device.getManufacturer();
  369 + String model = device == null ? "platform" : device.getModel();
  370 + String firmware = device == null ? gitUtil.getBuildVersion() : device.getFirmware();
339 String characterSet = parentPlatform.getCharacterSet(); 371 String characterSet = parentPlatform.getCharacterSet();
340 StringBuffer deviceInfoXml = new StringBuffer(600); 372 StringBuffer deviceInfoXml = new StringBuffer(600);
341 deviceInfoXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n"); 373 deviceInfoXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
342 deviceInfoXml.append("<Response>\r\n"); 374 deviceInfoXml.append("<Response>\r\n");
343 deviceInfoXml.append("<CmdType>DeviceInfo</CmdType>\r\n"); 375 deviceInfoXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
344 deviceInfoXml.append("<SN>" +sn + "</SN>\r\n"); 376 deviceInfoXml.append("<SN>" +sn + "</SN>\r\n");
345 - deviceInfoXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
346 - deviceInfoXml.append("<DeviceName>" + device.getName() + "</DeviceName>\r\n");  
347 - deviceInfoXml.append("<Manufacturer>" + device.getManufacturer() + "</Manufacturer>\r\n");  
348 - deviceInfoXml.append("<Model>" + device.getModel() + "</Model>\r\n");  
349 - deviceInfoXml.append("<Firmware>" + device.getFirmware() + "</Firmware>\r\n"); 377 + deviceInfoXml.append("<DeviceID>" + deviceId + "</DeviceID>\r\n");
  378 + deviceInfoXml.append("<DeviceName>" + deviceName + "</DeviceName>\r\n");
  379 + deviceInfoXml.append("<Manufacturer>" + manufacturer + "</Manufacturer>\r\n");
  380 + deviceInfoXml.append("<Model>" + model + "</Model>\r\n");
  381 + deviceInfoXml.append("<Firmware>" + firmware + "</Firmware>\r\n");
350 deviceInfoXml.append("<Result>OK</Result>\r\n"); 382 deviceInfoXml.append("<Result>OK</Result>\r\n");
351 deviceInfoXml.append("</Response>\r\n"); 383 deviceInfoXml.append("</Response>\r\n");
352 384
@@ -423,7 +455,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -423,7 +455,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
423 if (parentPlatform == null) { 455 if (parentPlatform == null) {
424 return; 456 return;
425 } 457 }
426 - logger.info("[发送报警通知] {}/{}->{},{}: {}", parentPlatform.getServerGBId(), deviceAlarm.getChannelId(), 458 + logger.info("[发送报警通知]平台: {}/{}->{},{}: {}", parentPlatform.getServerGBId(), deviceAlarm.getChannelId(),
427 deviceAlarm.getLongitude(), deviceAlarm.getLatitude(), JSON.toJSONString(deviceAlarm)); 459 deviceAlarm.getLongitude(), deviceAlarm.getLatitude(), JSON.toJSONString(deviceAlarm));
428 String characterSet = parentPlatform.getCharacterSet(); 460 String characterSet = parentPlatform.getCharacterSet();
429 StringBuffer deviceStatusXml = new StringBuffer(600); 461 StringBuffer deviceStatusXml = new StringBuffer(600);
@@ -434,7 +466,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -434,7 +466,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
434 .append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n") 466 .append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n")
435 .append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n") 467 .append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n")
436 .append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n") 468 .append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n")
437 - .append("<AlarmTime>" + deviceAlarm.getAlarmTime() + "</AlarmTime>\r\n") 469 + .append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n")
438 .append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n") 470 .append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n")
439 .append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n") 471 .append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n")
440 .append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n") 472 .append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n")
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
@@ -45,7 +45,7 @@ public abstract class SIPRequestProcessorParent { @@ -45,7 +45,7 @@ public abstract class SIPRequestProcessorParent {
45 try { 45 try {
46 return SipFactory.getInstance().createHeaderFactory(); 46 return SipFactory.getInstance().createHeaderFactory();
47 } catch (PeerUnavailableException e) { 47 } catch (PeerUnavailableException e) {
48 - e.printStackTrace(); 48 + logger.error("未处理的异常 ", e);
49 } 49 }
50 return null; 50 return null;
51 } 51 }
@@ -54,7 +54,7 @@ public abstract class SIPRequestProcessorParent { @@ -54,7 +54,7 @@ public abstract class SIPRequestProcessorParent {
54 try { 54 try {
55 return SipFactory.getInstance().createMessageFactory(); 55 return SipFactory.getInstance().createMessageFactory();
56 } catch (PeerUnavailableException e) { 56 } catch (PeerUnavailableException e) {
57 - e.printStackTrace(); 57 + logger.error("未处理的异常 ", e);
58 } 58 }
59 return null; 59 return null;
60 } 60 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
8 import com.genersoft.iot.vmp.gb28181.bean.*; 8 import com.genersoft.iot.vmp.gb28181.bean.*;
9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; 9 import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; 10 import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager;
  11 +import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
11 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 12 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
12 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 13 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
13 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 14 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -457,12 +458,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -457,12 +458,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
457 if (!userSetting.getPushStreamAfterAck()) { 458 if (!userSetting.getPushStreamAfterAck()) {
458 playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader()); 459 playService.startPushStream(sendRtpItem, sipResponse, platform, request.getCallIdHeader());
459 } 460 }
460 - } catch (SipException e) {  
461 - e.printStackTrace();  
462 - } catch (InvalidArgumentException e) {  
463 - e.printStackTrace();  
464 - } catch (ParseException e) {  
465 - e.printStackTrace(); 461 + } catch (SipException | InvalidArgumentException | ParseException e) {
  462 + logger.error("[命令发送失败] 国标级联 回复SdpAck", e);
466 } 463 }
467 }; 464 };
468 SipSubscribe.Event errorEvent = ((event) -> { 465 SipSubscribe.Event errorEvent = ((event) -> {
@@ -471,7 +468,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -471,7 +468,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
471 Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest()); 468 Response response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
472 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); 469 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
473 } catch (ParseException | SipException e) { 470 } catch (ParseException | SipException e) {
474 - e.printStackTrace(); 471 + logger.error("未处理的异常 ", e);
475 } 472 }
476 }); 473 });
477 sendRtpItem.setApp("rtp"); 474 sendRtpItem.setApp("rtp");
@@ -543,6 +540,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -543,6 +540,15 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
543 } 540 }
544 } 541 }
545 } else if (gbStream != null) { 542 } else if (gbStream != null) {
  543 + if(ssrc.equals(ssrcDefault))
  544 + {
  545 + SsrcConfig ssrcConfig = mediaServerItem.getSsrcConfig();
  546 + if(ssrcConfig != null)
  547 + {
  548 + ssrc = ssrcConfig.getPlaySsrc();
  549 + ssrcConfig.releaseSsrc(ssrc);
  550 + }
  551 + }
546 if("push".equals(gbStream.getStreamType())) { 552 if("push".equals(gbStream.getStreamType())) {
547 if (streamPushItem != null && streamPushItem.isPushIng()) { 553 if (streamPushItem != null && streamPushItem.isPushIng()) {
548 // 推流状态 554 // 推流状态
@@ -572,7 +578,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -572,7 +578,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
572 } catch (SdpParseException e) { 578 } catch (SdpParseException e) {
573 logger.error("sdp解析错误", e); 579 logger.error("sdp解析错误", e);
574 } catch (SdpException e) { 580 } catch (SdpException e) {
575 - e.printStackTrace(); 581 + logger.error("未处理的异常 ", e);
576 } 582 }
577 } 583 }
578 584
@@ -727,11 +733,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -727,11 +733,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
727 mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); 733 mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream());
728 responseAck(request, Response.REQUEST_TIMEOUT); // 超时 734 responseAck(request, Response.REQUEST_TIMEOUT); // 超时
729 } catch (SipException e) { 735 } catch (SipException e) {
730 - e.printStackTrace(); 736 + logger.error("未处理的异常 ", e);
731 } catch (InvalidArgumentException e) { 737 } catch (InvalidArgumentException e) {
732 - e.printStackTrace(); 738 + logger.error("未处理的异常 ", e);
733 } catch (ParseException e) { 739 } catch (ParseException e) {
734 - e.printStackTrace(); 740 + logger.error("未处理的异常 ", e);
735 } 741 }
736 }, userSetting.getPlatformPlayTimeout()); 742 }, userSetting.getPlatformPlayTimeout());
737 // 添加监听 743 // 添加监听
@@ -750,11 +756,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -750,11 +756,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
750 try { 756 try {
751 responseAck(request, Response.BUSY_HERE); 757 responseAck(request, Response.BUSY_HERE);
752 } catch (SipException e) { 758 } catch (SipException e) {
753 - e.printStackTrace(); 759 + logger.error("未处理的异常 ", e);
754 } catch (InvalidArgumentException e) { 760 } catch (InvalidArgumentException e) {
755 - e.printStackTrace(); 761 + logger.error("未处理的异常 ", e);
756 } catch (ParseException e) { 762 } catch (ParseException e) {
757 - e.printStackTrace(); 763 + logger.error("未处理的异常 ", e);
758 } 764 }
759 return; 765 return;
760 } 766 }
@@ -812,11 +818,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -812,11 +818,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
812 try { 818 try {
813 responseAck(request, Response.BUSY_HERE); 819 responseAck(request, Response.BUSY_HERE);
814 } catch (SipException e) { 820 } catch (SipException e) {
815 - e.printStackTrace(); 821 + logger.error("未处理的异常 ", e);
816 } catch (InvalidArgumentException e) { 822 } catch (InvalidArgumentException e) {
817 - e.printStackTrace(); 823 + logger.error("未处理的异常 ", e);
818 } catch (ParseException e) { 824 } catch (ParseException e) {
819 - e.printStackTrace(); 825 + logger.error("未处理的异常 ", e);
820 } 826 }
821 return; 827 return;
822 } 828 }
@@ -869,7 +875,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -869,7 +875,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
869 content.append("s=Play\r\n"); 875 content.append("s=Play\r\n");
870 content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); 876 content.append("c=IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
871 content.append("t=0 0\r\n"); 877 content.append("t=0 0\r\n");
872 - content.append("m=video " + sendRtpItem.getLocalPort() + " RTP/AVP 96\r\n"); 878 + // 非严格模式端口不统一, 增加兼容性,修改为一个不为0的端口
  879 + int localPort = sendRtpItem.getLocalPort();
  880 + if(localPort == 0)
  881 + {
  882 + localPort = new Random().nextInt(65535) + 1;
  883 + }
  884 + content.append("m=video " + localPort + " RTP/AVP 96\r\n");
873 content.append("a=sendonly\r\n"); 885 content.append("a=sendonly\r\n");
874 content.append("a=rtpmap:96 PS/90000\r\n"); 886 content.append("a=rtpmap:96 PS/90000\r\n");
875 if (sendRtpItem.isTcp()) { 887 if (sendRtpItem.isTcp()) {
@@ -890,11 +902,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -890,11 +902,11 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
890 } 902 }
891 return sipResponse; 903 return sipResponse;
892 } catch (SipException e) { 904 } catch (SipException e) {
893 - e.printStackTrace(); 905 + logger.error("未处理的异常 ", e);
894 } catch (InvalidArgumentException e) { 906 } catch (InvalidArgumentException e) {
895 - e.printStackTrace(); 907 + logger.error("未处理的异常 ", e);
896 } catch (ParseException e) { 908 } catch (ParseException e) {
897 - e.printStackTrace(); 909 + logger.error("未处理的异常 ", e);
898 } 910 }
899 return null; 911 return null;
900 } 912 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -93,7 +93,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -93,7 +93,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
93 try { 93 try {
94 responseAck((SIPRequest) evt.getRequest(), Response.OK, null, null); 94 responseAck((SIPRequest) evt.getRequest(), Response.OK, null, null);
95 }catch (SipException | InvalidArgumentException | ParseException e) { 95 }catch (SipException | InvalidArgumentException | ParseException e) {
96 - e.printStackTrace(); 96 + logger.error("未处理的异常 ", e);
97 } 97 }
98 boolean runed = !taskQueue.isEmpty(); 98 boolean runed = !taskQueue.isEmpty();
99 taskQueue.offer(new HandlerCatchData(evt, null, null)); 99 taskQueue.offer(new HandlerCatchData(evt, null, null));
@@ -229,7 +229,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -229,7 +229,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
229 jsonObject.put("speed", mobilePosition.getSpeed()); 229 jsonObject.put("speed", mobilePosition.getSpeed());
230 redisCatchStorage.sendMobilePositionMsg(jsonObject); 230 redisCatchStorage.sendMobilePositionMsg(jsonObject);
231 } catch (DocumentException e) { 231 } catch (DocumentException e) {
232 - e.printStackTrace(); 232 + logger.error("未处理的异常 ", e);
233 } 233 }
234 } 234 }
235 235
@@ -339,7 +339,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -339,7 +339,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
339 publisher.deviceAlarmEventPublish(deviceAlarm); 339 publisher.deviceAlarmEventPublish(deviceAlarm);
340 } 340 }
341 } catch (DocumentException e) { 341 } catch (DocumentException e) {
342 - e.printStackTrace(); 342 + logger.error("未处理的异常 ", e);
343 } 343 }
344 } 344 }
345 345
@@ -397,12 +397,20 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -397,12 +397,20 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
397 case CatalogEvent.OFF : 397 case CatalogEvent.OFF :
398 // 离线 398 // 离线
399 logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); 399 logger.info("[收到通道离线通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
400 - storager.deviceChannelOffline(deviceId, channel.getChannelId()); 400 + if (userSetting.getRefuseChannelStatusChannelFormNotify()) {
  401 + storager.deviceChannelOffline(deviceId, channel.getChannelId());
  402 + }else {
  403 + logger.info("[收到通道离线通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  404 + }
401 break; 405 break;
402 case CatalogEvent.VLOST: 406 case CatalogEvent.VLOST:
403 // 视频丢失 407 // 视频丢失
404 logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); 408 logger.info("[收到通道视频丢失通知] 来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
405 - storager.deviceChannelOffline(deviceId, channel.getChannelId()); 409 + if (userSetting.getRefuseChannelStatusChannelFormNotify()) {
  410 + storager.deviceChannelOffline(deviceId, channel.getChannelId());
  411 + }else {
  412 + logger.info("[收到通道视频丢失通知] 但是平台已配置拒绝此消息,来自设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId());
  413 + }
406 break; 414 break;
407 case CatalogEvent.DEFECT: 415 case CatalogEvent.DEFECT:
408 // 故障 416 // 故障
@@ -432,7 +440,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -432,7 +440,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
432 } 440 }
433 } 441 }
434 } catch (DocumentException e) { 442 } catch (DocumentException e) {
435 - e.printStackTrace(); 443 + logger.error("未处理的异常 ", e);
436 } 444 }
437 } 445 }
438 446
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper; 5 import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
6 import com.genersoft.iot.vmp.gb28181.bean.Device; 6 import com.genersoft.iot.vmp.gb28181.bean.Device;
7 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; 7 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
  8 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
8 import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate; 9 import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
10 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 11 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -18,6 +19,7 @@ import gov.nist.javax.sip.address.AddressImpl; @@ -18,6 +19,7 @@ import gov.nist.javax.sip.address.AddressImpl;
18 import gov.nist.javax.sip.address.SipUri; 19 import gov.nist.javax.sip.address.SipUri;
19 import gov.nist.javax.sip.header.SIPDateHeader; 20 import gov.nist.javax.sip.header.SIPDateHeader;
20 import gov.nist.javax.sip.message.SIPRequest; 21 import gov.nist.javax.sip.message.SIPRequest;
  22 +import gov.nist.javax.sip.message.SIPResponse;
21 import org.slf4j.Logger; 23 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory; 24 import org.slf4j.LoggerFactory;
23 import org.springframework.beans.factory.InitializingBean; 25 import org.springframework.beans.factory.InitializingBean;
@@ -34,6 +36,7 @@ import javax.sip.header.AuthorizationHeader; @@ -34,6 +36,7 @@ import javax.sip.header.AuthorizationHeader;
34 import javax.sip.header.ContactHeader; 36 import javax.sip.header.ContactHeader;
35 import javax.sip.header.FromHeader; 37 import javax.sip.header.FromHeader;
36 import javax.sip.header.ViaHeader; 38 import javax.sip.header.ViaHeader;
  39 +import javax.sip.message.Request;
37 import javax.sip.message.Response; 40 import javax.sip.message.Response;
38 import java.security.NoSuchAlgorithmException; 41 import java.security.NoSuchAlgorithmException;
39 import java.text.ParseException; 42 import java.text.ParseException;
@@ -105,6 +108,30 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -105,6 +108,30 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
105 SipUri uri = (SipUri) address.getURI(); 108 SipUri uri = (SipUri) address.getURI();
106 String deviceId = uri.getUser(); 109 String deviceId = uri.getUser();
107 Device device = deviceService.getDevice(deviceId); 110 Device device = deviceService.getDevice(deviceId);
  111 +
  112 + RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
  113 + userSetting.getSipUseSourceIpAsRemoteAddress());
  114 +
  115 + if (device != null &&
  116 + device.getSipTransactionInfo() != null &&
  117 + request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
  118 + logger.info("[注册请求] 注册续订: {}", device.getDeviceId());
  119 + device.setExpires(request.getExpires().getExpires());
  120 + device.setIp(remoteAddressInfo.getIp());
  121 + device.setPort(remoteAddressInfo.getPort());
  122 + device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
  123 + device.setLocalIp(request.getLocalAddress().getHostAddress());
  124 + Response registerOkResponse = getRegisterOkResponse(request);
  125 + // 判断TCP还是UDP
  126 + ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
  127 + String transport = reqViaHeader.getTransport();
  128 + device.setTransport("TCP".equalsIgnoreCase(transport) ? "TCP" : "UDP");
  129 + sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), registerOkResponse);
  130 + device.setRegisterTime(DateUtil.getNow());
  131 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)registerOkResponse);
  132 + deviceService.online(device, sipTransactionInfo);
  133 + return;
  134 + }
108 String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword(); 135 String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword();
109 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); 136 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
110 if (authHead == null && !ObjectUtils.isEmpty(password)) { 137 if (authHead == null && !ObjectUtils.isEmpty(password)) {
@@ -147,9 +174,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -147,9 +174,6 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
147 // 添加Expires头 174 // 添加Expires头
148 response.addHeader(request.getExpires()); 175 response.addHeader(request.getExpires());
149 176
150 - RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,  
151 - userSetting.getSipUseSourceIpAsRemoteAddress());  
152 -  
153 if (device == null) { 177 if (device == null) {
154 device = new Device(); 178 device = new Device();
155 device.setStreamMode("UDP"); 179 device.setStreamMode("UDP");
@@ -182,13 +206,33 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -182,13 +206,33 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
182 if (registerFlag) { 206 if (registerFlag) {
183 logger.info("[注册成功] deviceId: {}->{}", deviceId, requestAddress); 207 logger.info("[注册成功] deviceId: {}->{}", deviceId, requestAddress);
184 device.setRegisterTime(DateUtil.getNow()); 208 device.setRegisterTime(DateUtil.getNow());
185 - deviceService.online(device); 209 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo((SIPResponse)response);
  210 + deviceService.online(device, sipTransactionInfo);
186 } else { 211 } else {
187 logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress); 212 logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress);
188 - deviceService.offline(deviceId); 213 + deviceService.offline(deviceId, "主动注销");
189 } 214 }
190 } catch (SipException | NoSuchAlgorithmException | ParseException e) { 215 } catch (SipException | NoSuchAlgorithmException | ParseException e) {
191 - e.printStackTrace(); 216 + logger.error("未处理的异常 ", e);
192 } 217 }
193 } 218 }
  219 +
  220 + private Response getRegisterOkResponse(Request request) throws ParseException {
  221 + // 携带授权头并且密码正确
  222 + Response response = getMessageFactory().createResponse(Response.OK, request);
  223 + // 添加date头
  224 + SIPDateHeader dateHeader = new SIPDateHeader();
  225 + // 使用自己修改的
  226 + WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
  227 + dateHeader.setDate(wvpSipDate);
  228 + response.addHeader(dateHeader);
  229 +
  230 + // 添加Contact头
  231 + response.addHeader(request.getHeader(ContactHeader.NAME));
  232 + // 添加Expires头
  233 + response.addHeader(request.getExpires());
  234 +
  235 + return response;
  236 +
  237 + }
194 } 238 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
2 2
  3 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
3 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
4 import com.genersoft.iot.vmp.conf.UserSetting; 5 import com.genersoft.iot.vmp.conf.UserSetting;
5 import com.genersoft.iot.vmp.gb28181.bean.CmdType; 6 import com.genersoft.iot.vmp.gb28181.bean.CmdType;
@@ -8,14 +9,11 @@ import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; @@ -8,14 +9,11 @@ import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
8 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; 9 import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo;
9 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 10 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
10 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; 11 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
11 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;  
12 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;  
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
14 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
15 import com.genersoft.iot.vmp.gb28181.utils.SipUtils; 14 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
16 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; 15 import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
17 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
18 -import gov.nist.javax.sip.SipProviderImpl;  
19 import gov.nist.javax.sip.message.SIPRequest; 17 import gov.nist.javax.sip.message.SIPRequest;
20 import gov.nist.javax.sip.message.SIPResponse; 18 import gov.nist.javax.sip.message.SIPResponse;
21 import org.dom4j.DocumentException; 19 import org.dom4j.DocumentException;
@@ -26,7 +24,9 @@ import org.springframework.beans.factory.InitializingBean; @@ -26,7 +24,9 @@ import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.beans.factory.annotation.Autowired; 24 import org.springframework.beans.factory.annotation.Autowired;
27 import org.springframework.stereotype.Component; 25 import org.springframework.stereotype.Component;
28 26
29 -import javax.sip.*; 27 +import javax.sip.InvalidArgumentException;
  28 +import javax.sip.RequestEvent;
  29 +import javax.sip.SipException;
30 import javax.sip.header.ExpiresHeader; 30 import javax.sip.header.ExpiresHeader;
31 import javax.sip.message.Response; 31 import javax.sip.message.Response;
32 import java.text.ParseException; 32 import java.text.ParseException;
@@ -93,7 +93,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -93,7 +93,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
93 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response); 93 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
94 } 94 }
95 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { 95 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
96 - e.printStackTrace(); 96 + logger.error("未处理的异常 ", e);
97 } 97 }
98 98
99 } 99 }
@@ -146,7 +146,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -146,7 +146,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
146 } 146 }
147 147
148 } catch (SipException | InvalidArgumentException | ParseException e) { 148 } catch (SipException | InvalidArgumentException | ParseException e) {
149 - e.printStackTrace(); 149 + logger.error("未处理的异常 ", e);
150 } 150 }
151 } 151 }
152 152
@@ -192,7 +192,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -192,7 +192,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
192 subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo); 192 subscribeHolder.putCatalogSubscribe(platformId, subscribeInfo);
193 } 193 }
194 } catch (SipException | InvalidArgumentException | ParseException e) { 194 } catch (SipException | InvalidArgumentException | ParseException e) {
195 - e.printStackTrace(); 195 + logger.error("未处理的异常 ", e);
196 } 196 }
197 } 197 }
198 } 198 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
@@ -73,35 +73,38 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent @@ -73,35 +73,38 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent
73 String channelId = getText(rootElement, "DeviceID"); 73 String channelId = getText(rootElement, "DeviceID");
74 // 远程启动功能 74 // 远程启动功能
75 if (!ObjectUtils.isEmpty(getText(rootElement, "TeleBoot"))) { 75 if (!ObjectUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
76 - if (parentPlatform.getServerGBId().equals(targetGBId)) {  
77 - // 远程启动本平台:需要在重新启动程序后先对SipStack解绑  
78 - logger.info("执行远程启动本平台命令");  
79 - try {  
80 - cmderFroPlatform.unregister(parentPlatform, null, null);  
81 - } catch (InvalidArgumentException | ParseException | SipException e) {  
82 - logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());  
83 - }  
84 - taskExecutor.execute(() -> {  
85 - // 远程启动  
86 -// try {  
87 -// Thread.sleep(3000);  
88 -// SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");  
89 -// SipStackImpl stack = (SipStackImpl)up.getSipStack();  
90 -// stack.stop();  
91 -// Iterator listener = stack.getListeningPoints();  
92 -// while (listener.hasNext()) {  
93 -// stack.deleteListeningPoint((ListeningPoint) listener.next());  
94 -// }  
95 -// Iterator providers = stack.getSipProviders();  
96 -// while (providers.hasNext()) {  
97 -// stack.deleteSipProvider((SipProvider) providers.next());  
98 -// }  
99 -// VManageBootstrap.restart();  
100 -// } catch (InterruptedException | ObjectInUseException e) {  
101 -// logger.error("[任务执行失败] 服务重启: {}", e.getMessage());  
102 -// }  
103 - });  
104 - } 76 + // TODO 拒绝远程启动命令
  77 + logger.warn("[国标级联]收到平台的远程启动命令, 不处理");
  78 +
  79 +// if (parentPlatform.getServerGBId().equals(targetGBId)) {
  80 +// // 远程启动本平台:需要在重新启动程序后先对SipStack解绑
  81 +// logger.info("执行远程启动本平台命令");
  82 +// try {
  83 +// cmderFroPlatform.unregister(parentPlatform, null, null);
  84 +// } catch (InvalidArgumentException | ParseException | SipException e) {
  85 +// logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
  86 +// }
  87 +// taskExecutor.execute(() -> {
  88 +// // 远程启动
  89 +//// try {
  90 +//// Thread.sleep(3000);
  91 +//// SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
  92 +//// SipStackImpl stack = (SipStackImpl)up.getSipStack();
  93 +//// stack.stop();
  94 +//// Iterator listener = stack.getListeningPoints();
  95 +//// while (listener.hasNext()) {
  96 +//// stack.deleteListeningPoint((ListeningPoint) listener.next());
  97 +//// }
  98 +//// Iterator providers = stack.getSipProviders();
  99 +//// while (providers.hasNext()) {
  100 +//// stack.deleteSipProvider((SipProvider) providers.next());
  101 +//// }
  102 +//// VManageBootstrap.restart();
  103 +//// } catch (InterruptedException | ObjectInUseException e) {
  104 +//// logger.error("[任务执行失败] 服务重启: {}", e.getMessage());
  105 +//// }
  106 +// });
  107 +// }
105 } 108 }
106 DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement); 109 DeviceControlType deviceControlType = DeviceControlType.typeOf(rootElement);
107 logger.info("[接受deviceControl命令] 命令: {}", deviceControlType); 110 logger.info("[接受deviceControl命令] 命令: {}", deviceControlType);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
@@ -186,9 +186,13 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme @@ -186,9 +186,13 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
186 // 发送给平台的报警信息。 发送redis通知 186 // 发送给平台的报警信息。 发送redis通知
187 logger.info("[发送给平台的报警信息]内容:{}", JSONObject.toJSONString(deviceAlarm)); 187 logger.info("[发送给平台的报警信息]内容:{}", JSONObject.toJSONString(deviceAlarm));
188 AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage(); 188 AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
189 - alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod())); 189 + if (deviceAlarm.getAlarmMethod() != null) {
  190 + alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
  191 + }
190 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription()); 192 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
191 - alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType())); 193 + if (deviceAlarm.getAlarmType() != null) {
  194 + alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
  195 + }
192 alarmChannelMessage.setGbId(channelId); 196 alarmChannelMessage.setGbId(channelId);
193 redisCatchStorage.sendAlarmMsg(alarmChannelMessage); 197 redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
194 continue; 198 continue;
@@ -204,6 +208,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme @@ -204,6 +208,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
204 publisher.deviceAlarmEventPublish(deviceAlarm); 208 publisher.deviceAlarmEventPublish(deviceAlarm);
205 } 209 }
206 }catch (Exception e) { 210 }catch (Exception e) {
  211 + logger.error("未处理的异常 ", e);
207 logger.warn("[收到报警通知] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest()); 212 logger.warn("[收到报警通知] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest());
208 } 213 }
209 } 214 }
@@ -264,12 +269,15 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme @@ -264,12 +269,15 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
264 if (channelId.equals(parentPlatform.getDeviceGBId())) { 269 if (channelId.equals(parentPlatform.getDeviceGBId())) {
265 // 发送给平台的报警信息。 发送redis通知 270 // 发送给平台的报警信息。 发送redis通知
266 AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage(); 271 AlarmChannelMessage alarmChannelMessage = new AlarmChannelMessage();
267 - alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod())); 272 + if (deviceAlarm.getAlarmMethod() != null) {
  273 + alarmChannelMessage.setAlarmSn(Integer.parseInt(deviceAlarm.getAlarmMethod()));
  274 + }
268 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription()); 275 alarmChannelMessage.setAlarmDescription(deviceAlarm.getAlarmDescription());
269 alarmChannelMessage.setGbId(channelId); 276 alarmChannelMessage.setGbId(channelId);
270 - alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType())); 277 + if (deviceAlarm.getAlarmType() != null) {
  278 + alarmChannelMessage.setAlarmType(Integer.parseInt(deviceAlarm.getAlarmType()));
  279 + }
271 redisCatchStorage.sendAlarmMsg(alarmChannelMessage); 280 redisCatchStorage.sendAlarmMsg(alarmChannelMessage);
272 - return;  
273 } 281 }
274 } 282 }
275 } 283 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -88,13 +88,13 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -88,13 +88,13 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
88 // 对于已经离线的设备判断他的注册是否已经过期 88 // 对于已经离线的设备判断他的注册是否已经过期
89 if (!deviceService.expire(device)){ 89 if (!deviceService.expire(device)){
90 device.setOnline(0); 90 device.setOnline(0);
91 - deviceService.online(device); 91 + deviceService.online(device, null);
92 } 92 }
93 } 93 }
94 // 刷新过期任务 94 // 刷新过期任务
95 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); 95 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
96 // 如果三次心跳失败,则设置设备离线 96 // 如果三次心跳失败,则设置设备离线
97 - dynamicTask.startDelay(registerExpireTaskKey, ()-> deviceService.offline(device.getDeviceId()), device.getKeepaliveIntervalTime()*1000*3); 97 + dynamicTask.startDelay(registerExpireTaskKey, ()-> deviceService.offline(device.getDeviceId(), "三次心跳失败"), device.getKeepaliveIntervalTime()*1000*3);
98 98
99 } 99 }
100 100
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
@@ -149,9 +149,10 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen @@ -149,9 +149,10 @@ public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParen
149 redisCatchStorage.sendMobilePositionMsg(jsonObject); 149 redisCatchStorage.sendMobilePositionMsg(jsonObject);
150 150
151 } catch (DocumentException e) { 151 } catch (DocumentException e) {
152 - e.printStackTrace(); 152 + logger.error("未处理的异常 ", e);
153 } catch (Exception e) { 153 } catch (Exception e) {
154 - logger.warn("[移动位置通知] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest()); 154 + logger.warn("[移动位置通知] 发现未处理的异常, \r\n{}", evt.getRequest());
  155 + logger.error("[移动位置通知] 异常内容: ", e);
155 } 156 }
156 } 157 }
157 }); 158 });
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java
@@ -60,17 +60,24 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp @@ -60,17 +60,24 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp
60 return; 60 return;
61 } 61 }
62 String sn = rootElement.element("SN").getText(); 62 String sn = rootElement.element("SN").getText();
  63 +
63 /*根据WVP原有的数据结构,设备和通道是分开放置,设备信息都是存放在设备表里,通道表里的设备信息不可作为真实信息处理 64 /*根据WVP原有的数据结构,设备和通道是分开放置,设备信息都是存放在设备表里,通道表里的设备信息不可作为真实信息处理
64 大部分NVR/IPC设备对他的通道信息实现都是返回默认的值没有什么参考价值。NVR/IPC通道我们统一使用设备表的设备信息来作为返回。 65 大部分NVR/IPC设备对他的通道信息实现都是返回默认的值没有什么参考价值。NVR/IPC通道我们统一使用设备表的设备信息来作为返回。
65 我们这里使用查询数据库的方式来实现这个设备信息查询的功能,在其他地方对设备信息更新达到正确的目的。*/ 66 我们这里使用查询数据库的方式来实现这个设备信息查询的功能,在其他地方对设备信息更新达到正确的目的。*/
  67 +
66 String channelId = getText(rootElement, "DeviceID"); 68 String channelId = getText(rootElement, "DeviceID");
67 - Device device = storager.queryDeviceInfoByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);  
68 - if (device ==null){  
69 - logger.error("[平台没有该通道的使用权限]:platformId"+parentPlatform.getServerGBId()+" deviceID:"+channelId);  
70 - return; 69 + // 查询这是通道id还是设备id
  70 + Device device = null;
  71 + // 如果id指向平台的国标编号,那么就是查询平台的信息
  72 + if (!parentPlatform.getDeviceGBId().equals(channelId)) {
  73 + device = storager.queryDeviceInfoByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
  74 + if (device ==null){
  75 + logger.error("[平台没有该通道的使用权限]:platformId"+parentPlatform.getServerGBId()+" deviceID:"+channelId);
  76 + return;
  77 + }
71 } 78 }
72 try { 79 try {
73 - cmderFroPlatform.deviceInfoResponse(parentPlatform,device, sn, fromHeader.getTag()); 80 + cmderFroPlatform.deviceInfoResponse(parentPlatform, device, sn, fromHeader.getTag());
74 } catch (SipException | InvalidArgumentException | ParseException e) { 81 } catch (SipException | InvalidArgumentException | ParseException e) {
75 logger.error("[命令发送失败] 国标级联 DeviceInfo查询回复: {}", e.getMessage()); 82 logger.error("[命令发送失败] 国标级联 DeviceInfo查询回复: {}", e.getMessage());
76 } 83 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -132,7 +132,8 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @@ -132,7 +132,8 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
132 132
133 } 133 }
134 }catch (Exception e) { 134 }catch (Exception e) {
135 - logger.warn("[收到通道] 发现未处理的异常, {}\r\n{}",e.getMessage(), evt.getRequest()); 135 + logger.warn("[收到通道] 发现未处理的异常, \r\n{}", evt.getRequest());
  136 + logger.error("[收到通道] 异常内容: ", e);
136 } 137 }
137 } 138 }
138 }); 139 });
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; 1 package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
2 2
3 import com.alibaba.fastjson2.JSONObject; 3 import com.alibaba.fastjson2.JSONObject;
4 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 5 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 -import com.genersoft.iot.vmp.gb28181.event.EventPublisher;  
8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 7 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
10 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 8 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
@@ -26,7 +24,6 @@ import javax.sip.RequestEvent; @@ -26,7 +24,6 @@ import javax.sip.RequestEvent;
26 import javax.sip.SipException; 24 import javax.sip.SipException;
27 import javax.sip.message.Response; 25 import javax.sip.message.Response;
28 import java.text.ParseException; 26 import java.text.ParseException;
29 -import java.util.Objects;  
30 27
31 @Component 28 @Component
32 public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { 29 public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
@@ -74,9 +71,9 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen @@ -74,9 +71,9 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen
74 } 71 }
75 String text = onlineElement.getText(); 72 String text = onlineElement.getText();
76 if ("ONLINE".equalsIgnoreCase(text.trim())) { 73 if ("ONLINE".equalsIgnoreCase(text.trim())) {
77 - deviceService.online(device); 74 + deviceService.online(device, null);
78 }else { 75 }else {
79 - deviceService.offline(device.getDeviceId()); 76 + deviceService.offline(device.getDeviceId(), "设备状态查询结果:" + text.trim());
80 } 77 }
81 RequestMessage msg = new RequestMessage(); 78 RequestMessage msg = new RequestMessage();
82 msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId()); 79 msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
@@ -142,7 +142,7 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar @@ -142,7 +142,7 @@ public class MobilePositionResponseMessageHandler extends SIPRequestProcessorPar
142 } 142 }
143 143
144 } catch (DocumentException e) { 144 } catch (DocumentException e) {
145 - e.printStackTrace(); 145 + logger.error("未处理的异常 ", e);
146 } 146 }
147 } 147 }
148 148
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -150,7 +150,8 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -150,7 +150,8 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
150 } 150 }
151 } 151 }
152 } catch (Exception e) { 152 } catch (Exception e) {
153 - logger.error("[国标录像] 发现未处理的异常, "+e.getMessage(), e); 153 + logger.error("[国标录像] 发现未处理的异常, \r\n{}", evt.getRequest());
  154 + logger.error("[国标录像] 异常内容: ", e);
154 } 155 }
155 }); 156 });
156 } 157 }
@@ -163,7 +164,11 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -163,7 +164,11 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
163 public void releaseRequest(String deviceId, String sn,RecordInfo recordInfo){ 164 public void releaseRequest(String deviceId, String sn,RecordInfo recordInfo){
164 String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; 165 String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn;
165 // 对数据进行排序 166 // 对数据进行排序
166 - Collections.sort(recordInfo.getRecordList()); 167 + if(recordInfo!=null && recordInfo.getRecordList()!=null) {
  168 + Collections.sort(recordInfo.getRecordList());
  169 + }else{
  170 + recordInfo.setRecordList(new ArrayList<>());
  171 + }
167 172
168 RequestMessage msg = new RequestMessage(); 173 RequestMessage msg = new RequestMessage();
169 msg.setKey(key); 174 msg.setKey(key);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.response.impl;
2 2
3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 3 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
5 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; 6 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
6 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; 7 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.service.IPlatformService; @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.service.IPlatformService;
10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 11 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 12 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
12 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo; 13 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
  14 +import gov.nist.javax.sip.message.SIPResponse;
13 import org.slf4j.Logger; 15 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory; 16 import org.slf4j.LoggerFactory;
15 import org.springframework.beans.factory.annotation.Autowired; 17 import org.springframework.beans.factory.annotation.Autowired;
@@ -18,7 +20,6 @@ import org.springframework.stereotype.Component; @@ -18,7 +20,6 @@ import org.springframework.stereotype.Component;
18 import javax.sip.InvalidArgumentException; 20 import javax.sip.InvalidArgumentException;
19 import javax.sip.ResponseEvent; 21 import javax.sip.ResponseEvent;
20 import javax.sip.SipException; 22 import javax.sip.SipException;
21 -import javax.sip.header.CallIdHeader;  
22 import javax.sip.header.WWWAuthenticateHeader; 23 import javax.sip.header.WWWAuthenticateHeader;
23 import javax.sip.message.Response; 24 import javax.sip.message.Response;
24 import java.text.ParseException; 25 import java.text.ParseException;
@@ -65,9 +66,8 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { @@ -65,9 +66,8 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
65 */ 66 */
66 @Override 67 @Override
67 public void process(ResponseEvent evt) { 68 public void process(ResponseEvent evt) {
68 - Response response = evt.getResponse();  
69 - CallIdHeader callIdHeader = (CallIdHeader) response.getHeader(CallIdHeader.NAME);  
70 - String callId = callIdHeader.getCallId(); 69 + SIPResponse response = (SIPResponse)evt.getResponse();
  70 + String callId = response.getCallIdHeader().getCallId();
71 PlatformRegisterInfo platformRegisterInfo = redisCatchStorage.queryPlatformRegisterInfo(callId); 71 PlatformRegisterInfo platformRegisterInfo = redisCatchStorage.queryPlatformRegisterInfo(callId);
72 if (platformRegisterInfo == null) { 72 if (platformRegisterInfo == null) {
73 logger.info(String.format("[国标级联]未找到callId: %s 的注册/注销平台id", callId )); 73 logger.info(String.format("[国标级联]未找到callId: %s 的注册/注销平台id", callId ));
@@ -90,15 +90,17 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract { @@ -90,15 +90,17 @@ public class RegisterResponseProcessor extends SIPResponseProcessorAbstract {
90 90
91 if (response.getStatusCode() == Response.UNAUTHORIZED) { 91 if (response.getStatusCode() == Response.UNAUTHORIZED) {
92 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME); 92 WWWAuthenticateHeader www = (WWWAuthenticateHeader)response.getHeader(WWWAuthenticateHeader.NAME);
  93 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
93 try { 94 try {
94 - sipCommanderForPlatform.register(parentPlatform, callId, www, null, null, true, platformRegisterInfo.isRegister()); 95 + sipCommanderForPlatform.register(parentPlatform, sipTransactionInfo, www, null, null, true, platformRegisterInfo.isRegister());
95 } catch (SipException | InvalidArgumentException | ParseException e) { 96 } catch (SipException | InvalidArgumentException | ParseException e) {
96 logger.error("[命令发送失败] 国标级联 再次注册: {}", e.getMessage()); 97 logger.error("[命令发送失败] 国标级联 再次注册: {}", e.getMessage());
97 } 98 }
98 }else if (response.getStatusCode() == Response.OK){ 99 }else if (response.getStatusCode() == Response.OK){
99 100
100 if (platformRegisterInfo.isRegister()) { 101 if (platformRegisterInfo.isRegister()) {
101 - platformService.online(parentPlatform); 102 + SipTransactionInfo sipTransactionInfo = new SipTransactionInfo(response);
  103 + platformService.online(parentPlatform, sipTransactionInfo);
102 }else { 104 }else {
103 platformService.offline(parentPlatform, false); 105 platformService.offline(parentPlatform, false);
104 } 106 }
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
@@ -9,17 +9,12 @@ import org.jetbrains.annotations.NotNull; @@ -9,17 +9,12 @@ import org.jetbrains.annotations.NotNull;
9 import org.slf4j.Logger; 9 import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory; 10 import org.slf4j.LoggerFactory;
11 import org.springframework.stereotype.Component; 11 import org.springframework.stereotype.Component;
12 -import org.springframework.util.ObjectUtils;  
13 -import org.springframework.util.StringUtils;  
14 12
15 -import java.io.File;  
16 -import java.io.FileOutputStream;  
17 import java.io.IOException; 13 import java.io.IOException;
18 import java.net.ConnectException; 14 import java.net.ConnectException;
19 import java.util.HashMap; 15 import java.util.HashMap;
20 import java.util.Map; 16 import java.util.Map;
21 import java.util.Objects; 17 import java.util.Objects;
22 -import java.util.concurrent.TimeUnit;  
23 18
24 @Component 19 @Component
25 public class AssistRESTfulUtils { 20 public class AssistRESTfulUtils {
@@ -137,6 +132,11 @@ public class AssistRESTfulUtils { @@ -137,6 +132,11 @@ public class AssistRESTfulUtils {
137 return sendGet(mediaServerItem, "api/record/file/duration",param, callback); 132 return sendGet(mediaServerItem, "api/record/file/duration",param, callback);
138 } 133 }
139 134
  135 + public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){
  136 + Map<String, Object> param = new HashMap<>();
  137 + return sendGet(mediaServerItem, "api/record/info",param, callback);
  138 + }
  139 +
140 public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){ 140 public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){
141 Map<String, Object> param = new HashMap<>(); 141 Map<String, Object> param = new HashMap<>();
142 param.put("app",app); 142 param.put("app",app);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
@@ -119,10 +119,11 @@ public class ZLMHttpHookListener { @@ -119,10 +119,11 @@ public class ZLMHttpHookListener {
119 * 服务器定时上报时间,上报间隔可配置,默认10s上报一次 119 * 服务器定时上报时间,上报间隔可配置,默认10s上报一次
120 */ 120 */
121 @ResponseBody 121 @ResponseBody
  122 +
122 @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8") 123 @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
123 public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) { 124 public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
124 125
125 - logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId()); 126 +// logger.info("[ZLM HOOK] 收到zlm心跳:" + param.getMediaServerId());
126 127
127 taskExecutor.execute(() -> { 128 taskExecutor.execute(() -> {
128 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive); 129 List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
@@ -142,6 +143,7 @@ public class ZLMHttpHookListener { @@ -142,6 +143,7 @@ public class ZLMHttpHookListener {
142 * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。 143 * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。
143 */ 144 */
144 @ResponseBody 145 @ResponseBody
  146 +
145 @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8") 147 @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
146 public HookResult onPlay(@RequestBody OnPlayHookParam param) { 148 public HookResult onPlay(@RequestBody OnPlayHookParam param) {
147 if (logger.isDebugEnabled()) { 149 if (logger.isDebugEnabled()) {
@@ -264,9 +266,28 @@ public class ZLMHttpHookListener { @@ -264,9 +266,28 @@ public class ZLMHttpHookListener {
264 } 266 }
265 267
266 } 268 }
  269 + if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
  270 + logger.info("推流时发现尚未设置录像路径,从assist服务中读取");
  271 + JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);
  272 + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
  273 + JSONObject dataJson = info.getJSONObject("data");
  274 + if (dataJson != null) {
  275 + String recordPath = dataJson.getString("record");
  276 + userSetting.setRecordPath(recordPath);
  277 + result.setMp4_save_path(recordPath);
  278 + // 修改zlm中的录像路径
  279 + if (mediaInfo.isAutoConfig()) {
  280 + taskExecutor.execute(() -> {
  281 + mediaServerService.setZLMConfig(mediaInfo, false);
  282 + });
  283 + }
  284 + }
  285 + }
  286 + }
267 return result; 287 return result;
268 } 288 }
269 289
  290 +
270 /** 291 /**
271 * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。 292 * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。
272 */ 293 */
@@ -293,8 +314,12 @@ public class ZLMHttpHookListener { @@ -293,8 +314,12 @@ public class ZLMHttpHookListener {
293 subscribe.response(mediaInfo, json); 314 subscribe.response(mediaInfo, json);
294 } 315 }
295 } 316 }
296 - // 流消失移除redis play 317 +
  318 + List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
  319 + // TODO 重构此处逻辑
  320 +
297 if (param.isRegist()) { 321 if (param.isRegist()) {
  322 + // 处理流注册的鉴权信息
298 if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() 323 if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
299 || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() 324 || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
300 || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { 325 || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
@@ -334,9 +334,9 @@ public class ZLMRESTfulUtils { @@ -334,9 +334,9 @@ public class ZLMRESTfulUtils {
334 sendPost(mediaServerItem, "kick_sessions",param, null); 334 sendPost(mediaServerItem, "kick_sessions",param, null);
335 } 335 }
336 336
337 - public void getSnap(MediaServerItem mediaServerItem, String flvUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) { 337 + public void getSnap(MediaServerItem mediaServerItem, String streamUrl, int timeout_sec, int expire_sec, String targetPath, String fileName) {
338 Map<String, Object> param = new HashMap<>(3); 338 Map<String, Object> param = new HashMap<>(3);
339 - param.put("url", flvUrl); 339 + param.put("url", streamUrl);
340 param.put("timeout_sec", timeout_sec); 340 param.put("timeout_sec", timeout_sec);
341 param.put("expire_sec", expire_sec); 341 param.put("expire_sec", expire_sec);
342 sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName); 342 sendGetForImg(mediaServerItem, "getSnap", param, targetPath, fileName);
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
@@ -262,8 +262,11 @@ public class ZLMRTPServerFactory { @@ -262,8 +262,11 @@ public class ZLMRTPServerFactory {
262 logger.info("[保持端口] {}->监听端口到期继续保持监听", ssrc); 262 logger.info("[保持端口] {}->监听端口到期继续保持监听", ssrc);
263 keepPort(serverItem, ssrc); 263 keepPort(serverItem, ssrc);
264 }); 264 });
265 - }  
266 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort); 265 logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
  266 + logger.info("[保持端口] {}->监听端口: {}", ssrc, localPort);
  267 + }else {
  268 + logger.info("[保持端口] 监听端口失败: {}", ssrc);
  269 + }
267 return localPort; 270 return localPort;
268 } 271 }
269 272
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java
@@ -10,21 +10,87 @@ public class ZLMServerConfig { @@ -10,21 +10,87 @@ public class ZLMServerConfig {
10 @JSONField(name = "api.secret") 10 @JSONField(name = "api.secret")
11 private String apiSecret; 11 private String apiSecret;
12 12
  13 + @JSONField(name = "api.snapRoot")
  14 + private String apiSnapRoot;
  15 +
  16 + @JSONField(name = "api.defaultSnap")
  17 + private String apiDefaultSnap;
  18 +
13 @JSONField(name = "ffmpeg.bin") 19 @JSONField(name = "ffmpeg.bin")
14 private String ffmpegBin; 20 private String ffmpegBin;
15 21
16 @JSONField(name = "ffmpeg.cmd") 22 @JSONField(name = "ffmpeg.cmd")
17 private String ffmpegCmd; 23 private String ffmpegCmd;
18 24
  25 + @JSONField(name = "ffmpeg.snap")
  26 + private String ffmpegSnap;
  27 +
19 @JSONField(name = "ffmpeg.log") 28 @JSONField(name = "ffmpeg.log")
20 private String ffmpegLog; 29 private String ffmpegLog;
21 30
  31 + @JSONField(name = "ffmpeg.restart_sec")
  32 + private String ffmpegRestartSec;
  33 +
  34 + @JSONField(name = "protocol.modify_stamp")
  35 + private String protocolModifyStamp;
  36 +
  37 + @JSONField(name = "protocol.enable_audio")
  38 + private String protocolEnableAudio;
  39 +
  40 + @JSONField(name = "protocol.add_mute_audio")
  41 + private String protocolAddMuteAudio;
  42 +
  43 + @JSONField(name = "protocol.continue_push_ms")
  44 + private String protocolContinuePushMs;
  45 +
  46 + @JSONField(name = "protocol.enable_hls")
  47 + private String protocolEnableHls;
  48 +
  49 + @JSONField(name = "protocol.enable_mp4")
  50 + private String protocolEnableMp4;
  51 +
  52 + @JSONField(name = "protocol.enable_rtsp")
  53 + private String protocolEnableRtsp;
  54 +
  55 + @JSONField(name = "protocol.enable_rtmp")
  56 + private String protocolEnableRtmp;
  57 +
  58 + @JSONField(name = "protocol.enable_ts")
  59 + private String protocolEnableTs;
  60 +
  61 + @JSONField(name = "protocol.enable_fmp4")
  62 + private String protocolEnableFmp4;
  63 +
  64 + @JSONField(name = "protocol.mp4_as_player")
  65 + private String protocolMp4AsPlayer;
  66 +
  67 + @JSONField(name = "protocol.mp4_max_second")
  68 + private String protocolMp4MaxSecond;
  69 +
  70 + @JSONField(name = "protocol.mp4_save_path")
  71 + private String protocolMp4SavePath;
  72 +
  73 + @JSONField(name = "protocol.hls_save_path")
  74 + private String protocolHlsSavePath;
  75 +
  76 + @JSONField(name = "protocol.hls_demand")
  77 + private String protocolHlsDemand;
  78 +
  79 + @JSONField(name = "protocol.rtsp_demand")
  80 + private String protocolRtspDemand;
  81 +
  82 + @JSONField(name = "protocol.rtmp_demand")
  83 + private String protocolRtmpDemand;
  84 +
  85 + @JSONField(name = "protocol.ts_demand")
  86 + private String protocolTsDemand;
  87 +
  88 + @JSONField(name = "protocol.fmp4_demand")
  89 + private String protocolFmp4Demand;
  90 +
22 @JSONField(name = "general.enableVhost") 91 @JSONField(name = "general.enableVhost")
23 private String generalEnableVhost; 92 private String generalEnableVhost;
24 93
25 - @JSONField(name = "general.mediaServerId")  
26 - private String generalMediaServerId;  
27 -  
28 @JSONField(name = "general.flowThreshold") 94 @JSONField(name = "general.flowThreshold")
29 private String generalFlowThreshold; 95 private String generalFlowThreshold;
30 96
@@ -34,6 +100,25 @@ public class ZLMServerConfig { @@ -34,6 +100,25 @@ public class ZLMServerConfig {
34 @JSONField(name = "general.streamNoneReaderDelayMS") 100 @JSONField(name = "general.streamNoneReaderDelayMS")
35 private int generalStreamNoneReaderDelayMS; 101 private int generalStreamNoneReaderDelayMS;
36 102
  103 + @JSONField(name = "general.resetWhenRePlay")
  104 + private String generalResetWhenRePlay;
  105 +
  106 + @JSONField(name = "general.mergeWriteMS")
  107 + private String generalMergeWriteMS;
  108 +
  109 + @JSONField(name = "general.mediaServerId")
  110 + private String generalMediaServerId;
  111 +
  112 + @JSONField(name = "general.wait_track_ready_ms")
  113 + private String generalWaitTrackReadyMs;
  114 +
  115 + @JSONField(name = "general.wait_add_track_ms")
  116 + private String generalWaitAddTrackMs;
  117 +
  118 + @JSONField(name = "general.unready_frame_cache")
  119 + private String generalUnreadyFrameCache;
  120 +
  121 +
37 @JSONField(name = "ip") 122 @JSONField(name = "ip")
38 private String ip; 123 private String ip;
39 124
@@ -59,6 +144,18 @@ public class ZLMServerConfig { @@ -59,6 +144,18 @@ public class ZLMServerConfig {
59 @JSONField(name = "hls.segNum") 144 @JSONField(name = "hls.segNum")
60 private String hlsSegNum; 145 private String hlsSegNum;
61 146
  147 + @JSONField(name = "hls.segRetain")
  148 + private String hlsSegRetain;
  149 +
  150 + @JSONField(name = "hls.broadcastRecordTs")
  151 + private String hlsBroadcastRecordTs;
  152 +
  153 + @JSONField(name = "hls.deleteDelaySec")
  154 + private String hlsDeleteDelaySec;
  155 +
  156 + @JSONField(name = "hls.segKeep")
  157 + private String hlsSegKeep;
  158 +
62 @JSONField(name = "hook.access_file_except_hls") 159 @JSONField(name = "hook.access_file_except_hls")
63 private String hookAccessFileExceptHLS; 160 private String hookAccessFileExceptHLS;
64 161
@@ -104,6 +201,18 @@ public class ZLMServerConfig { @@ -104,6 +201,18 @@ public class ZLMServerConfig {
104 @JSONField(name = "hook.on_stream_not_found") 201 @JSONField(name = "hook.on_stream_not_found")
105 private String hookOnStreamNotFound; 202 private String hookOnStreamNotFound;
106 203
  204 + @JSONField(name = "hook.on_server_started")
  205 + private String hookOnServerStarted;
  206 +
  207 + @JSONField(name = "hook.on_server_keepalive")
  208 + private String hookOnServerKeepalive;
  209 +
  210 + @JSONField(name = "hook.on_send_rtp_stopped")
  211 + private String hookOnSendRtpStopped;
  212 +
  213 + @JSONField(name = "hook.on_rtp_server_timeout")
  214 + private String hookOnRtpServerTimeout;
  215 +
107 @JSONField(name = "hook.timeoutSec") 216 @JSONField(name = "hook.timeoutSec")
108 private String hookTimeoutSec; 217 private String hookTimeoutSec;
109 218
@@ -813,4 +922,292 @@ public class ZLMServerConfig { @@ -813,4 +922,292 @@ public class ZLMServerConfig {
813 public void setPortRange(String portRange) { 922 public void setPortRange(String portRange) {
814 this.portRange = portRange; 923 this.portRange = portRange;
815 } 924 }
  925 +
  926 + public String getApiSnapRoot() {
  927 + return apiSnapRoot;
  928 + }
  929 +
  930 + public void setApiSnapRoot(String apiSnapRoot) {
  931 + this.apiSnapRoot = apiSnapRoot;
  932 + }
  933 +
  934 + public String getApiDefaultSnap() {
  935 + return apiDefaultSnap;
  936 + }
  937 +
  938 + public void setApiDefaultSnap(String apiDefaultSnap) {
  939 + this.apiDefaultSnap = apiDefaultSnap;
  940 + }
  941 +
  942 + public String getFfmpegSnap() {
  943 + return ffmpegSnap;
  944 + }
  945 +
  946 + public void setFfmpegSnap(String ffmpegSnap) {
  947 + this.ffmpegSnap = ffmpegSnap;
  948 + }
  949 +
  950 + public String getFfmpegRestartSec() {
  951 + return ffmpegRestartSec;
  952 + }
  953 +
  954 + public void setFfmpegRestartSec(String ffmpegRestartSec) {
  955 + this.ffmpegRestartSec = ffmpegRestartSec;
  956 + }
  957 +
  958 + public String getProtocolModifyStamp() {
  959 + return protocolModifyStamp;
  960 + }
  961 +
  962 + public void setProtocolModifyStamp(String protocolModifyStamp) {
  963 + this.protocolModifyStamp = protocolModifyStamp;
  964 + }
  965 +
  966 + public String getProtocolEnableAudio() {
  967 + return protocolEnableAudio;
  968 + }
  969 +
  970 + public void setProtocolEnableAudio(String protocolEnableAudio) {
  971 + this.protocolEnableAudio = protocolEnableAudio;
  972 + }
  973 +
  974 + public String getProtocolAddMuteAudio() {
  975 + return protocolAddMuteAudio;
  976 + }
  977 +
  978 + public void setProtocolAddMuteAudio(String protocolAddMuteAudio) {
  979 + this.protocolAddMuteAudio = protocolAddMuteAudio;
  980 + }
  981 +
  982 + public String getProtocolContinuePushMs() {
  983 + return protocolContinuePushMs;
  984 + }
  985 +
  986 + public void setProtocolContinuePushMs(String protocolContinuePushMs) {
  987 + this.protocolContinuePushMs = protocolContinuePushMs;
  988 + }
  989 +
  990 + public String getProtocolEnableHls() {
  991 + return protocolEnableHls;
  992 + }
  993 +
  994 + public void setProtocolEnableHls(String protocolEnableHls) {
  995 + this.protocolEnableHls = protocolEnableHls;
  996 + }
  997 +
  998 + public String getProtocolEnableMp4() {
  999 + return protocolEnableMp4;
  1000 + }
  1001 +
  1002 + public void setProtocolEnableMp4(String protocolEnableMp4) {
  1003 + this.protocolEnableMp4 = protocolEnableMp4;
  1004 + }
  1005 +
  1006 + public String getProtocolEnableRtsp() {
  1007 + return protocolEnableRtsp;
  1008 + }
  1009 +
  1010 + public void setProtocolEnableRtsp(String protocolEnableRtsp) {
  1011 + this.protocolEnableRtsp = protocolEnableRtsp;
  1012 + }
  1013 +
  1014 + public String getProtocolEnableRtmp() {
  1015 + return protocolEnableRtmp;
  1016 + }
  1017 +
  1018 + public void setProtocolEnableRtmp(String protocolEnableRtmp) {
  1019 + this.protocolEnableRtmp = protocolEnableRtmp;
  1020 + }
  1021 +
  1022 + public String getProtocolEnableTs() {
  1023 + return protocolEnableTs;
  1024 + }
  1025 +
  1026 + public void setProtocolEnableTs(String protocolEnableTs) {
  1027 + this.protocolEnableTs = protocolEnableTs;
  1028 + }
  1029 +
  1030 + public String getProtocolEnableFmp4() {
  1031 + return protocolEnableFmp4;
  1032 + }
  1033 +
  1034 + public void setProtocolEnableFmp4(String protocolEnableFmp4) {
  1035 + this.protocolEnableFmp4 = protocolEnableFmp4;
  1036 + }
  1037 +
  1038 + public String getProtocolMp4AsPlayer() {
  1039 + return protocolMp4AsPlayer;
  1040 + }
  1041 +
  1042 + public void setProtocolMp4AsPlayer(String protocolMp4AsPlayer) {
  1043 + this.protocolMp4AsPlayer = protocolMp4AsPlayer;
  1044 + }
  1045 +
  1046 + public String getProtocolMp4MaxSecond() {
  1047 + return protocolMp4MaxSecond;
  1048 + }
  1049 +
  1050 + public void setProtocolMp4MaxSecond(String protocolMp4MaxSecond) {
  1051 + this.protocolMp4MaxSecond = protocolMp4MaxSecond;
  1052 + }
  1053 +
  1054 + public String getProtocolMp4SavePath() {
  1055 + return protocolMp4SavePath;
  1056 + }
  1057 +
  1058 + public void setProtocolMp4SavePath(String protocolMp4SavePath) {
  1059 + this.protocolMp4SavePath = protocolMp4SavePath;
  1060 + }
  1061 +
  1062 + public String getProtocolHlsSavePath() {
  1063 + return protocolHlsSavePath;
  1064 + }
  1065 +
  1066 + public void setProtocolHlsSavePath(String protocolHlsSavePath) {
  1067 + this.protocolHlsSavePath = protocolHlsSavePath;
  1068 + }
  1069 +
  1070 + public String getProtocolHlsDemand() {
  1071 + return protocolHlsDemand;
  1072 + }
  1073 +
  1074 + public void setProtocolHlsDemand(String protocolHlsDemand) {
  1075 + this.protocolHlsDemand = protocolHlsDemand;
  1076 + }
  1077 +
  1078 + public String getProtocolRtspDemand() {
  1079 + return protocolRtspDemand;
  1080 + }
  1081 +
  1082 + public void setProtocolRtspDemand(String protocolRtspDemand) {
  1083 + this.protocolRtspDemand = protocolRtspDemand;
  1084 + }
  1085 +
  1086 + public String getProtocolRtmpDemand() {
  1087 + return protocolRtmpDemand;
  1088 + }
  1089 +
  1090 + public void setProtocolRtmpDemand(String protocolRtmpDemand) {
  1091 + this.protocolRtmpDemand = protocolRtmpDemand;
  1092 + }
  1093 +
  1094 + public String getProtocolTsDemand() {
  1095 + return protocolTsDemand;
  1096 + }
  1097 +
  1098 + public void setProtocolTsDemand(String protocolTsDemand) {
  1099 + this.protocolTsDemand = protocolTsDemand;
  1100 + }
  1101 +
  1102 + public String getProtocolFmp4Demand() {
  1103 + return protocolFmp4Demand;
  1104 + }
  1105 +
  1106 + public void setProtocolFmp4Demand(String protocolFmp4Demand) {
  1107 + this.protocolFmp4Demand = protocolFmp4Demand;
  1108 + }
  1109 +
  1110 + public String getGeneralResetWhenRePlay() {
  1111 + return generalResetWhenRePlay;
  1112 + }
  1113 +
  1114 + public void setGeneralResetWhenRePlay(String generalResetWhenRePlay) {
  1115 + this.generalResetWhenRePlay = generalResetWhenRePlay;
  1116 + }
  1117 +
  1118 + public String getGeneralMergeWriteMS() {
  1119 + return generalMergeWriteMS;
  1120 + }
  1121 +
  1122 + public void setGeneralMergeWriteMS(String generalMergeWriteMS) {
  1123 + this.generalMergeWriteMS = generalMergeWriteMS;
  1124 + }
  1125 +
  1126 + public String getGeneralWaitTrackReadyMs() {
  1127 + return generalWaitTrackReadyMs;
  1128 + }
  1129 +
  1130 + public void setGeneralWaitTrackReadyMs(String generalWaitTrackReadyMs) {
  1131 + this.generalWaitTrackReadyMs = generalWaitTrackReadyMs;
  1132 + }
  1133 +
  1134 + public String getGeneralWaitAddTrackMs() {
  1135 + return generalWaitAddTrackMs;
  1136 + }
  1137 +
  1138 + public void setGeneralWaitAddTrackMs(String generalWaitAddTrackMs) {
  1139 + this.generalWaitAddTrackMs = generalWaitAddTrackMs;
  1140 + }
  1141 +
  1142 + public String getGeneralUnreadyFrameCache() {
  1143 + return generalUnreadyFrameCache;
  1144 + }
  1145 +
  1146 + public void setGeneralUnreadyFrameCache(String generalUnreadyFrameCache) {
  1147 + this.generalUnreadyFrameCache = generalUnreadyFrameCache;
  1148 + }
  1149 +
  1150 + public String getHlsSegRetain() {
  1151 + return hlsSegRetain;
  1152 + }
  1153 +
  1154 + public void setHlsSegRetain(String hlsSegRetain) {
  1155 + this.hlsSegRetain = hlsSegRetain;
  1156 + }
  1157 +
  1158 + public String getHlsBroadcastRecordTs() {
  1159 + return hlsBroadcastRecordTs;
  1160 + }
  1161 +
  1162 + public void setHlsBroadcastRecordTs(String hlsBroadcastRecordTs) {
  1163 + this.hlsBroadcastRecordTs = hlsBroadcastRecordTs;
  1164 + }
  1165 +
  1166 + public String getHlsDeleteDelaySec() {
  1167 + return hlsDeleteDelaySec;
  1168 + }
  1169 +
  1170 + public void setHlsDeleteDelaySec(String hlsDeleteDelaySec) {
  1171 + this.hlsDeleteDelaySec = hlsDeleteDelaySec;
  1172 + }
  1173 +
  1174 + public String getHlsSegKeep() {
  1175 + return hlsSegKeep;
  1176 + }
  1177 +
  1178 + public void setHlsSegKeep(String hlsSegKeep) {
  1179 + this.hlsSegKeep = hlsSegKeep;
  1180 + }
  1181 +
  1182 + public String getHookOnServerStarted() {
  1183 + return hookOnServerStarted;
  1184 + }
  1185 +
  1186 + public void setHookOnServerStarted(String hookOnServerStarted) {
  1187 + this.hookOnServerStarted = hookOnServerStarted;
  1188 + }
  1189 +
  1190 + public String getHookOnServerKeepalive() {
  1191 + return hookOnServerKeepalive;
  1192 + }
  1193 +
  1194 + public void setHookOnServerKeepalive(String hookOnServerKeepalive) {
  1195 + this.hookOnServerKeepalive = hookOnServerKeepalive;
  1196 + }
  1197 +
  1198 + public String getHookOnSendRtpStopped() {
  1199 + return hookOnSendRtpStopped;
  1200 + }
  1201 +
  1202 + public void setHookOnSendRtpStopped(String hookOnSendRtpStopped) {
  1203 + this.hookOnSendRtpStopped = hookOnSendRtpStopped;
  1204 + }
  1205 +
  1206 + public String getHookOnRtpServerTimeout() {
  1207 + return hookOnRtpServerTimeout;
  1208 + }
  1209 +
  1210 + public void setHookOnRtpServerTimeout(String hookOnRtpServerTimeout) {
  1211 + this.hookOnRtpServerTimeout = hookOnRtpServerTimeout;
  1212 + }
816 } 1213 }
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
@@ -5,6 +5,7 @@ public class HookResultForOnPublish extends HookResult{ @@ -5,6 +5,7 @@ public class HookResultForOnPublish extends HookResult{
5 private boolean enable_audio; 5 private boolean enable_audio;
6 private boolean enable_mp4; 6 private boolean enable_mp4;
7 private int mp4_max_second; 7 private int mp4_max_second;
  8 + private String mp4_save_path;
8 9
9 public HookResultForOnPublish() { 10 public HookResultForOnPublish() {
10 } 11 }
@@ -41,4 +42,12 @@ public class HookResultForOnPublish extends HookResult{ @@ -41,4 +42,12 @@ public class HookResultForOnPublish extends HookResult{
41 public void setMp4_max_second(int mp4_max_second) { 42 public void setMp4_max_second(int mp4_max_second) {
42 this.mp4_max_second = mp4_max_second; 43 this.mp4_max_second = mp4_max_second;
43 } 44 }
  45 +
  46 + public String getMp4_save_path() {
  47 + return mp4_save_path;
  48 + }
  49 +
  50 + public void setMp4_save_path(String mp4_save_path) {
  51 + this.mp4_save_path = mp4_save_path;
  52 + }
44 } 53 }
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service; @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.service;
2 2
3 import com.genersoft.iot.vmp.gb28181.bean.Device; 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 4 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  5 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
5 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; 6 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
6 import com.genersoft.iot.vmp.vmanager.bean.BaseTree; 7 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
7 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; 8 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
@@ -18,13 +19,13 @@ public interface IDeviceService { @@ -18,13 +19,13 @@ public interface IDeviceService {
18 * 设备上线 19 * 设备上线
19 * @param device 设备信息 20 * @param device 设备信息
20 */ 21 */
21 - void online(Device device); 22 + void online(Device device, SipTransactionInfo sipTransactionInfo);
22 23
23 /** 24 /**
24 * 设备下线 25 * 设备下线
25 * @param deviceId 设备编号 26 * @param deviceId 设备编号
26 */ 27 */
27 - void offline(String deviceId); 28 + void offline(String deviceId, String reason);
28 29
29 /** 30 /**
30 * 添加目录订阅 31 * 添加目录订阅
src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java
@@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
6 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 6 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; 7 import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
8 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; 8 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
  9 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
9 import com.github.pagehelper.PageInfo; 10 import com.github.pagehelper.PageInfo;
10 11
11 import javax.sip.InvalidArgumentException; 12 import javax.sip.InvalidArgumentException;
@@ -35,10 +36,16 @@ public interface IPlatformService { @@ -35,10 +36,16 @@ public interface IPlatformService {
35 boolean add(ParentPlatform parentPlatform); 36 boolean add(ParentPlatform parentPlatform);
36 37
37 /** 38 /**
  39 + * 添加级联平台
  40 + * @param parentPlatform 级联平台
  41 + */
  42 + boolean update(ParentPlatform parentPlatform);
  43 +
  44 + /**
38 * 平台上线 45 * 平台上线
39 * @param parentPlatform 平台信息 46 * @param parentPlatform 平台信息
40 */ 47 */
41 - void online(ParentPlatform parentPlatform); 48 + void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo);
42 49
43 /** 50 /**
44 * 平台离线 51 * 平台离线
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -96,7 +96,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -96,7 +96,7 @@ public class DeviceServiceImpl implements IDeviceService {
96 private ZLMRESTfulUtils zlmresTfulUtils; 96 private ZLMRESTfulUtils zlmresTfulUtils;
97 97
98 @Override 98 @Override
99 - public void online(Device device) { 99 + public void online(Device device, SipTransactionInfo sipTransactionInfo) {
100 logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort()); 100 logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort());
101 Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId()); 101 Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId());
102 Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId()); 102 Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
@@ -111,6 +111,14 @@ public class DeviceServiceImpl implements IDeviceService { @@ -111,6 +111,14 @@ public class DeviceServiceImpl implements IDeviceService {
111 // 默认心跳间隔60 111 // 默认心跳间隔60
112 device.setKeepaliveIntervalTime(60); 112 device.setKeepaliveIntervalTime(60);
113 } 113 }
  114 + if (sipTransactionInfo != null) {
  115 + device.setSipTransactionInfo(sipTransactionInfo);
  116 + }else {
  117 + if (deviceInRedis != null) {
  118 + device.setSipTransactionInfo(deviceInRedis.getSipTransactionInfo());
  119 + }
  120 + }
  121 +
114 // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询 122 // 第一次上线 或则设备之前是离线状态--进行通道同步和设备信息查询
115 if (device.getCreateTime() == null) { 123 if (device.getCreateTime() == null) {
116 device.setOnline(1); 124 device.setOnline(1);
@@ -163,12 +171,12 @@ public class DeviceServiceImpl implements IDeviceService { @@ -163,12 +171,12 @@ public class DeviceServiceImpl implements IDeviceService {
163 // 刷新过期任务 171 // 刷新过期任务
164 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); 172 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId();
165 // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 173 // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线
166 - dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getKeepaliveIntervalTime() * 1000 * 3); 174 + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3);
167 } 175 }
168 176
169 @Override 177 @Override
170 - public void offline(String deviceId) {  
171 - logger.error("[设备离线], device:{}", deviceId); 178 + public void offline(String deviceId, String reason) {
  179 + logger.error("[设备离线],{}, device:{}", reason, deviceId);
172 Device device = deviceMapper.getDeviceByDeviceId(deviceId); 180 Device device = deviceMapper.getDeviceByDeviceId(deviceId);
173 if (device == null) { 181 if (device == null) {
174 return; 182 return;
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
@@ -41,6 +41,9 @@ public class GbStreamServiceImpl implements IGbStreamService { @@ -41,6 +41,9 @@ public class GbStreamServiceImpl implements IGbStreamService {
41 private PlatformGbStreamMapper platformGbStreamMapper; 41 private PlatformGbStreamMapper platformGbStreamMapper;
42 42
43 @Autowired 43 @Autowired
  44 + private SubscribeHolder subscribeHolder;
  45 +
  46 + @Autowired
44 private ParentPlatformMapper platformMapper; 47 private ParentPlatformMapper platformMapper;
45 48
46 @Autowired 49 @Autowired
@@ -73,16 +76,23 @@ public class GbStreamServiceImpl implements IGbStreamService { @@ -73,16 +76,23 @@ public class GbStreamServiceImpl implements IGbStreamService {
73 } 76 }
74 try { 77 try {
75 List<DeviceChannel> deviceChannelList = new ArrayList<>(); 78 List<DeviceChannel> deviceChannelList = new ArrayList<>();
76 - for (GbStream gbStream : gbStreams) { 79 +
  80 +
  81 + for (int i = 0; i < gbStreams.size(); i++) {
  82 + GbStream gbStream = gbStreams.get(i);
77 gbStream.setCatalogId(catalogId); 83 gbStream.setCatalogId(catalogId);
78 gbStream.setPlatformId(platformId); 84 gbStream.setPlatformId(platformId);
79 // TODO 修改为批量提交 85 // TODO 修改为批量提交
80 platformGbStreamMapper.add(gbStream); 86 platformGbStreamMapper.add(gbStream);
  87 + logger.info("[关联通道]直播流通道 平台:{}, 共需关联通道数:{}, 已关联:{}", platformId, gbStreams.size(), i + 1);
81 DeviceChannel deviceChannelListByStream = getDeviceChannelListByStreamWithStatus(gbStream, catalogId, parentPlatform); 88 DeviceChannel deviceChannelListByStream = getDeviceChannelListByStreamWithStatus(gbStream, catalogId, parentPlatform);
82 deviceChannelList.add(deviceChannelListByStream); 89 deviceChannelList.add(deviceChannelListByStream);
83 } 90 }
84 dataSourceTransactionManager.commit(transactionStatus); //手动提交 91 dataSourceTransactionManager.commit(transactionStatus); //手动提交
85 - eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD); 92 + if (subscribeHolder.getCatalogSubscribe(platformId) != null) {
  93 + eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
  94 + }
  95 +
86 result = true; 96 result = true;
87 }catch (Exception e) { 97 }catch (Exception e) {
88 logger.error("批量保存流与平台的关系时错误", e); 98 logger.error("批量保存流与平台的关系时错误", e);
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException; @@ -11,6 +11,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
11 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 11 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
12 import com.genersoft.iot.vmp.gb28181.session.SsrcConfig; 12 import com.genersoft.iot.vmp.gb28181.session.SsrcConfig;
13 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; 13 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  14 +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils;
14 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; 15 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
15 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory; 16 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
16 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig; 17 import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
@@ -38,6 +39,7 @@ import org.springframework.transaction.TransactionDefinition; @@ -38,6 +39,7 @@ import org.springframework.transaction.TransactionDefinition;
38 import org.springframework.transaction.TransactionStatus; 39 import org.springframework.transaction.TransactionStatus;
39 import org.springframework.util.ObjectUtils; 40 import org.springframework.util.ObjectUtils;
40 41
  42 +import java.io.File;
41 import java.time.LocalDateTime; 43 import java.time.LocalDateTime;
42 import java.util.*; 44 import java.util.*;
43 45
@@ -64,6 +66,9 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -64,6 +66,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
64 private UserSetting userSetting; 66 private UserSetting userSetting;
65 67
66 @Autowired 68 @Autowired
  69 + private AssistRESTfulUtils assistRESTfulUtils;
  70 +
  71 + @Autowired
67 private ZLMRESTfulUtils zlmresTfulUtils; 72 private ZLMRESTfulUtils zlmresTfulUtils;
68 73
69 @Autowired 74 @Autowired
@@ -409,13 +414,27 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -409,13 +414,27 @@ public class MediaServerServiceImpl implements IMediaServerService {
409 } 414 }
410 RedisUtil.set(key, serverItem); 415 RedisUtil.set(key, serverItem);
411 resetOnlineServerItem(serverItem); 416 resetOnlineServerItem(serverItem);
  417 +
  418 +
412 if (serverItem.isAutoConfig()) { 419 if (serverItem.isAutoConfig()) {
  420 + // 查看assist服务的录像路径配置
  421 + if (serverItem.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
  422 + JSONObject info = assistRESTfulUtils.getInfo(serverItem, null);
  423 + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
  424 + JSONObject dataJson = info.getJSONObject("data");
  425 + if (dataJson != null) {
  426 + String recordPath = dataJson.getString("record");
  427 + userSetting.setRecordPath(recordPath);
  428 + }
  429 + }
  430 + }
413 setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); 431 setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
414 } 432 }
415 final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); 433 final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId();
416 dynamicTask.stop(zlmKeepaliveKey); 434 dynamicTask.stop(zlmKeepaliveKey);
417 dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000); 435 dynamicTask.startDelay(zlmKeepaliveKey, new KeepAliveTimeoutRunnable(serverItem), (Math.getExponent(serverItem.getHookAliveInterval()) + 5) * 1000);
418 publisher.zlmOnlineEventPublish(serverItem.getId()); 436 publisher.zlmOnlineEventPublish(serverItem.getId());
  437 +
419 logger.info("[ZLM] 连接成功 {} - {}:{} ", 438 logger.info("[ZLM] 连接成功 {} - {}:{} ",
420 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); 439 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
421 } 440 }
@@ -549,6 +568,9 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -549,6 +568,9 @@ public class MediaServerServiceImpl implements IMediaServerService {
549 568
550 Map<String, Object> param = new HashMap<>(); 569 Map<String, Object> param = new HashMap<>();
551 param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline 570 param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline
  571 + if (mediaServerItem.getRtspPort() != 0) {
  572 + param.put("ffmpeg.snap", "%s -rtsp_transport tcp -i %s -y -f mjpeg -t 0.001 %s");
  573 + }
552 param.put("hook.enable","1"); 574 param.put("hook.enable","1");
553 param.put("hook.on_flow_report",""); 575 param.put("hook.on_flow_report","");
554 param.put("hook.on_play",String.format("%s/on_play", hookPrex)); 576 param.put("hook.on_play",String.format("%s/on_play", hookPrex));
@@ -583,6 +605,13 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -583,6 +605,13 @@ public class MediaServerServiceImpl implements IMediaServerService {
583 param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-")); 605 param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-"));
584 } 606 }
585 607
  608 + if (userSetting.getRecordPath() != null) {
  609 + File recordPathFile = new File(userSetting.getRecordPath());
  610 + File mp4SavePathFile = recordPathFile.getParentFile().getAbsoluteFile();
  611 + param.put("protocol.mp4_save_path", mp4SavePathFile.getAbsoluteFile());
  612 + param.put("record.appName", recordPathFile.getName());
  613 + }
  614 +
586 JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param); 615 JSONObject responseJSON = zlmresTfulUtils.setServerConfig(mediaServerItem, param);
587 616
588 if (responseJSON != null && responseJSON.getInteger("code") == 0) { 617 if (responseJSON != null && responseJSON.getInteger("code") == 0) {
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java
1 package com.genersoft.iot.vmp.service.impl; 1 package com.genersoft.iot.vmp.service.impl;
2 2
3 -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;  
4 -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;  
5 -import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;  
6 -import com.genersoft.iot.vmp.gb28181.bean.TreeType; 3 +import com.genersoft.iot.vmp.gb28181.bean.*;
7 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 4 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
8 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; 5 import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
9 import com.genersoft.iot.vmp.service.IPlatformChannelService; 6 import com.genersoft.iot.vmp.service.IPlatformChannelService;
@@ -15,7 +12,10 @@ import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; @@ -15,7 +12,10 @@ import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
15 import org.slf4j.Logger; 12 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory; 13 import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.beans.factory.annotation.Autowired;
  15 +import org.springframework.jdbc.datasource.DataSourceTransactionManager;
18 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
  17 +import org.springframework.transaction.TransactionDefinition;
  18 +import org.springframework.transaction.TransactionStatus;
19 import org.springframework.util.ObjectUtils; 19 import org.springframework.util.ObjectUtils;
20 20
21 import java.util.ArrayList; 21 import java.util.ArrayList;
@@ -35,6 +35,16 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @@ -35,6 +35,16 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
35 private PlatformChannelMapper platformChannelMapper; 35 private PlatformChannelMapper platformChannelMapper;
36 36
37 @Autowired 37 @Autowired
  38 + TransactionDefinition transactionDefinition;
  39 +
  40 + @Autowired
  41 + DataSourceTransactionManager dataSourceTransactionManager;
  42 +
  43 + @Autowired
  44 + private SubscribeHolder subscribeHolder;
  45 +
  46 +
  47 + @Autowired
38 private DeviceChannelMapper deviceChannelMapper; 48 private DeviceChannelMapper deviceChannelMapper;
39 49
40 @Autowired 50 @Autowired
@@ -69,17 +79,47 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @@ -69,17 +79,47 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService {
69 } 79 }
70 List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values()); 80 List<ChannelReduce> channelReducesToAdd = new ArrayList<>(deviceAndChannels.values());
71 // 对剩下的数据进行存储 81 // 对剩下的数据进行存储
72 - int result = 0; 82 + int allCount = 0;
  83 + boolean result = false;
  84 + TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
  85 + int limitCount = 300;
73 if (channelReducesToAdd.size() > 0) { 86 if (channelReducesToAdd.size() > 0) {
74 - result = platformChannelMapper.addChannels(platformId, channelReducesToAdd);  
75 - // TODO 后续给平台增加控制开关以控制是否响应目录订阅  
76 - List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId, platform);  
77 - if (deviceChannelList != null) {  
78 - eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD); 87 + if (channelReducesToAdd.size() > limitCount) {
  88 + for (int i = 0; i < channelReducesToAdd.size(); i += limitCount) {
  89 + int toIndex = i + limitCount;
  90 + if (i + limitCount > channelReducesToAdd.size()) {
  91 + toIndex = channelReducesToAdd.size();
  92 + }
  93 + int count = platformChannelMapper.addChannels(platformId, channelReducesToAdd.subList(i, toIndex));
  94 + result = result || count < 0;
  95 + allCount += count;
  96 + logger.info("[关联通道]国标通道 平台:{}, 共需关联通道数:{}, 已关联:{}", platformId, channelReducesToAdd.size(), toIndex);
  97 + }
  98 + }else {
  99 + allCount = platformChannelMapper.addChannels(platformId, channelReducesToAdd);
  100 + result = result || allCount < 0;
  101 + logger.info("[关联通道]国标通道 平台:{}, 关联通道数:{}", platformId, channelReducesToAdd.size());
79 } 102 }
80 - }  
81 103
82 - return result; 104 + if (result) {
  105 + //事务回滚
  106 + dataSourceTransactionManager.rollback(transactionStatus);
  107 + allCount = 0;
  108 + }else {
  109 + logger.info("[关联通道]国标通道 平台:{}, 正在存入数据库", platformId);
  110 + dataSourceTransactionManager.commit(transactionStatus);
  111 +
  112 + }
  113 + SubscribeInfo catalogSubscribe = subscribeHolder.getCatalogSubscribe(platformId);
  114 + if (catalogSubscribe != null) {
  115 + List<DeviceChannel> deviceChannelList = getDeviceChannelListByChannelReduceList(channelReducesToAdd, catalogId, platform);
  116 + if (deviceChannelList != null) {
  117 + eventPublisher.catalogEventPublish(platformId, deviceChannelList, CatalogEvent.ADD);
  118 + }
  119 + }
  120 + logger.info("[关联通道]国标通道 平台:{}, 存入数据库成功", platformId);
  121 + }
  122 + return allCount;
83 } 123 }
84 124
85 private List<DeviceChannel> getDeviceChannelListByChannelReduceList(List<ChannelReduce> channelReduces, String catalogId, ParentPlatform platform) { 125 private List<DeviceChannel> getDeviceChannelListByChannelReduceList(List<ChannelReduce> channelReduces, String catalogId, ParentPlatform platform) {
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
@@ -21,8 +21,8 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; @@ -21,8 +21,8 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
21 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback; 21 import com.genersoft.iot.vmp.service.bean.InviteTimeOutCallback;
22 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 22 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
23 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 23 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
24 -import com.genersoft.iot.vmp.storager.dao.GbStreamMapper;  
25 -import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper; 24 +import com.genersoft.iot.vmp.storager.dao.*;
  25 +import com.genersoft.iot.vmp.utils.DateUtil;
26 import com.github.pagehelper.PageHelper; 26 import com.github.pagehelper.PageHelper;
27 import com.github.pagehelper.PageInfo; 27 import com.github.pagehelper.PageInfo;
28 import org.slf4j.Logger; 28 import org.slf4j.Logger;
@@ -54,6 +54,15 @@ public class PlatformServiceImpl implements IPlatformService { @@ -54,6 +54,15 @@ public class PlatformServiceImpl implements IPlatformService {
54 private ParentPlatformMapper platformMapper; 54 private ParentPlatformMapper platformMapper;
55 55
56 @Autowired 56 @Autowired
  57 + private PlatformCatalogMapper catalogMapper;
  58 +
  59 + @Autowired
  60 + private PlatformChannelMapper platformChannelMapper;
  61 +
  62 + @Autowired
  63 + private PlatformGbStreamMapper platformGbStreamMapper;
  64 +
  65 + @Autowired
57 private IRedisCatchStorage redisCatchStorage; 66 private IRedisCatchStorage redisCatchStorage;
58 67
59 @Autowired 68 @Autowired
@@ -135,36 +144,106 @@ public class PlatformServiceImpl implements IPlatformService { @@ -135,36 +144,106 @@ public class PlatformServiceImpl implements IPlatformService {
135 } 144 }
136 145
137 @Override 146 @Override
138 - public void online(ParentPlatform parentPlatform) {  
139 - logger.info("[国标级联]:{}, 平台上线/更新注册", parentPlatform.getServerGBId()); 147 + public boolean update(ParentPlatform parentPlatform) {
  148 + logger.info("[国标级联]更新平台 {}", parentPlatform.getDeviceGBId());
  149 + parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());
  150 + ParentPlatform parentPlatformOld = platformMapper.getParentPlatById(parentPlatform.getId());
  151 + ParentPlatformCatch parentPlatformCatchOld = redisCatchStorage.queryPlatformCatchInfo(parentPlatformOld.getServerGBId());
  152 + parentPlatform.setUpdateTime(DateUtil.getNow());
  153 + if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {
  154 + // 目录结构发生变化,清空之前的关联关系
  155 + logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());
  156 + catalogMapper.delByPlatformId(parentPlatformOld.getServerGBId());
  157 + platformChannelMapper.delByPlatformId(parentPlatformOld.getServerGBId());
  158 + platformGbStreamMapper.delByPlatformId(parentPlatformOld.getServerGBId());
  159 + }
  160 +
  161 +
  162 + // 停止心跳定时
  163 + final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatformOld.getServerGBId();
  164 + dynamicTask.stop(keepaliveTaskKey);
  165 + // 停止注册定时
  166 + final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatformOld.getServerGBId();
  167 + dynamicTask.stop(registerTaskKey);
  168 + // 注销旧的
  169 + try {
  170 + if (parentPlatformOld.isStatus()) {
  171 + logger.info("保存平台{}时发现救平台在线,发送注销命令", parentPlatform.getDeviceGBId());
  172 + commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> {
  173 + logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId());
  174 + });
  175 + }
  176 +
  177 + } catch (InvalidArgumentException | ParseException | SipException e) {
  178 + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
  179 + }
  180 +
  181 + // 更新数据库
  182 + if (parentPlatform.getCatalogGroup() == 0) {
  183 + parentPlatform.setCatalogGroup(1);
  184 + }
  185 + if (parentPlatform.getAdministrativeDivision() == null) {
  186 + parentPlatform.setAdministrativeDivision(parentPlatform.getAdministrativeDivision());
  187 + }
  188 +
  189 + platformMapper.updateParentPlatform(parentPlatform);
  190 + // 更新redis
  191 + redisCatchStorage.delPlatformCatchInfo(parentPlatformOld.getServerGBId());
  192 + ParentPlatformCatch parentPlatformCatch = new ParentPlatformCatch();
  193 + parentPlatformCatch.setParentPlatform(parentPlatform);
  194 + parentPlatformCatch.setId(parentPlatform.getServerGBId());
  195 + redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
  196 + // 注册
  197 + if (parentPlatform.isEnable()) {
  198 + // 保存时启用就发送注册
  199 + // 注册成功时由程序直接调用了online方法
  200 + try {
  201 + commanderForPlatform.register(parentPlatform, eventResult -> {
  202 + logger.info("[国标级联] {},添加向上级注册失败,请确定上级平台可用时重新保存", parentPlatform.getServerGBId());
  203 + }, null);
  204 + } catch (InvalidArgumentException | ParseException | SipException e) {
  205 + logger.error("[命令发送失败] 国标级联: {}", e.getMessage());
  206 + }
  207 + }
  208 + // 重新开启定时注册, 使用续订消息
  209 + // 重新开始心跳保活
  210 +
  211 +
  212 + return false;
  213 + }
  214 +
  215 +
  216 + @Override
  217 + public void online(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo) {
  218 + logger.info("[国标级联]:{}, 平台上线", parentPlatform.getServerGBId());
140 platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true); 219 platformMapper.updateParentPlatformStatus(parentPlatform.getServerGBId(), true);
141 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); 220 ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId());
142 - if (parentPlatformCatch != null) {  
143 - parentPlatformCatch.getParentPlatform().setStatus(true);  
144 - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);  
145 - }else { 221 + if (parentPlatformCatch == null) {
146 parentPlatformCatch = new ParentPlatformCatch(); 222 parentPlatformCatch = new ParentPlatformCatch();
147 parentPlatformCatch.setParentPlatform(parentPlatform); 223 parentPlatformCatch.setParentPlatform(parentPlatform);
148 parentPlatformCatch.setId(parentPlatform.getServerGBId()); 224 parentPlatformCatch.setId(parentPlatform.getServerGBId());
149 parentPlatform.setStatus(true); 225 parentPlatform.setStatus(true);
150 parentPlatformCatch.setParentPlatform(parentPlatform); 226 parentPlatformCatch.setParentPlatform(parentPlatform);
151 - redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);  
152 } 227 }
153 228
  229 + parentPlatformCatch.getParentPlatform().setStatus(true);
  230 + parentPlatformCatch.setSipTransactionInfo(sipTransactionInfo);
  231 + redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
  232 +
154 final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId(); 233 final String registerTaskKey = REGISTER_KEY_PREFIX + parentPlatform.getServerGBId();
155 if (!dynamicTask.isAlive(registerTaskKey)) { 234 if (!dynamicTask.isAlive(registerTaskKey)) {
  235 + logger.info("[国标级联]:{}, 添加定时注册任务", parentPlatform.getServerGBId());
156 // 添加注册任务 236 // 添加注册任务
157 dynamicTask.startCron(registerTaskKey, 237 dynamicTask.startCron(registerTaskKey,
158 // 注册失败(注册成功时由程序直接调用了online方法) 238 // 注册失败(注册成功时由程序直接调用了online方法)
159 - ()-> {  
160 - registerTask(parentPlatform);  
161 - },  
162 - (parentPlatform.getExpires() - 10) *1000); 239 + ()-> registerTask(parentPlatform, sipTransactionInfo),
  240 + parentPlatform.getExpires() * 1000);
163 } 241 }
164 242
165 243
166 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId(); 244 final String keepaliveTaskKey = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId();
167 if (!dynamicTask.contains(keepaliveTaskKey)) { 245 if (!dynamicTask.contains(keepaliveTaskKey)) {
  246 + logger.info("[国标级联]:{}, 添加定时心跳任务", parentPlatform.getServerGBId());
168 // 添加心跳任务 247 // 添加心跳任务
169 dynamicTask.startCron(keepaliveTaskKey, 248 dynamicTask.startCron(keepaliveTaskKey,
170 ()-> { 249 ()-> {
@@ -205,11 +284,11 @@ public class PlatformServiceImpl implements IPlatformService { @@ -205,11 +284,11 @@ public class PlatformServiceImpl implements IPlatformService {
205 logger.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage()); 284 logger.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage());
206 } 285 }
207 }, 286 },
208 - (parentPlatform.getKeepTimeout() - 10)*1000); 287 + (parentPlatform.getKeepTimeout())*1000);
209 } 288 }
210 } 289 }
211 290
212 - private void registerTask(ParentPlatform parentPlatform){ 291 + private void registerTask(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo){
213 try { 292 try {
214 // 设置超时重发, 后续从底层支持消息重发 293 // 设置超时重发, 后续从底层支持消息重发
215 String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout"; 294 String key = KEEPALIVE_KEY_PREFIX + parentPlatform.getServerGBId() + "_timeout";
@@ -217,10 +296,10 @@ public class PlatformServiceImpl implements IPlatformService { @@ -217,10 +296,10 @@ public class PlatformServiceImpl implements IPlatformService {
217 return; 296 return;
218 } 297 }
219 dynamicTask.startDelay(key, ()->{ 298 dynamicTask.startDelay(key, ()->{
220 - registerTask(parentPlatform); 299 + registerTask(parentPlatform, sipTransactionInfo);
221 }, 1000); 300 }, 1000);
222 - logger.info("[国标级联] 平台:{}注册即将到期,重新注册", parentPlatform.getServerGBId());  
223 - commanderForPlatform.register(parentPlatform, eventResult -> { 301 + logger.info("[国标级联] 平台:{}注册即将到期,开始续订", parentPlatform.getServerGBId());
  302 + commanderForPlatform.register(parentPlatform, sipTransactionInfo, eventResult -> {
224 dynamicTask.stop(key); 303 dynamicTask.stop(key);
225 offline(parentPlatform, false); 304 offline(parentPlatform, false);
226 },eventResult -> { 305 },eventResult -> {
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -438,7 +438,12 @@ public class PlayServiceImpl implements IPlayService { @@ -438,7 +438,12 @@ public class PlayServiceImpl implements IPlayService {
438 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId); 438 onPublishHandlerForPlay(mediaServerItemInuse, response, device.getDeviceId(), channelId);
439 hookEvent.response(mediaServerItemInuse, response); 439 hookEvent.response(mediaServerItemInuse, response);
440 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId); 440 logger.info("[点播成功] deviceId: {}, channelId: {}", device.getDeviceId(), channelId);
441 - String streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.flv", mediaServerItemInuse.getHttpPort(), "rtp", ssrcInfo.getStream()); 441 + String streamUrl;
  442 + if (mediaServerItemInuse.getRtspPort() != 0) {
  443 + streamUrl = String.format("rtsp://127.0.0.1:%s/%s/%s", mediaServerItemInuse.getRtspPort(), "rtp", ssrcInfo.getStream());
  444 + }else {
  445 + streamUrl = String.format("http://127.0.0.1:%s/%s/%s.live.mp4", mediaServerItemInuse.getHttpPort(), "rtp", ssrcInfo.getStream());
  446 + }
442 String path = "snap"; 447 String path = "snap";
443 String fileName = device.getDeviceId() + "_" + channelId + ".jpg"; 448 String fileName = device.getDeviceId() + "_" + channelId + ".jpg";
444 // 请求截图 449 // 请求截图
@@ -806,23 +811,75 @@ public class PlayServiceImpl implements IPlayService { @@ -806,23 +811,75 @@ public class PlayServiceImpl implements IPlayService {
806 hookCallBack.call(downloadResult); 811 hookCallBack.call(downloadResult);
807 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); 812 streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
808 }; 813 };
809 - 814 + InviteStreamCallback hookEvent = (InviteStreamInfo inviteStreamInfo) -> {
  815 + logger.info("收到订阅消息: " + inviteStreamInfo.getCallId());
  816 + dynamicTask.stop(downLoadTimeOutTaskKey);
  817 + StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);
  818 + streamInfo.setStartTime(startTime);
  819 + streamInfo.setEndTime(endTime);
  820 + redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());
  821 + downloadResult.setCode(ErrorCode.SUCCESS.getCode());
  822 + downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());
  823 + downloadResult.setData(streamInfo);
  824 + downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());
  825 + downloadResult.setResponse(inviteStreamInfo.getResponse());
  826 + hookCallBack.call(downloadResult);
  827 + };
810 try { 828 try {
811 cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack, 829 cmder.downloadStreamCmd(mediaServerItem, ssrcInfo, device, channelId, startTime, endTime, downloadSpeed, infoCallBack,
812 - inviteStreamInfo -> {  
813 - logger.info("收到订阅消息: " + inviteStreamInfo.getResponse().toJSONString());  
814 - dynamicTask.stop(downLoadTimeOutTaskKey);  
815 - StreamInfo streamInfo = onPublishHandler(inviteStreamInfo.getMediaServerItem(), inviteStreamInfo.getResponse(), deviceId, channelId);  
816 - streamInfo.setStartTime(startTime);  
817 - streamInfo.setEndTime(endTime);  
818 - redisCatchStorage.startDownload(streamInfo, inviteStreamInfo.getCallId());  
819 - downloadResult.setCode(ErrorCode.SUCCESS.getCode());  
820 - downloadResult.setMsg(ErrorCode.SUCCESS.getMsg());  
821 - downloadResult.setData(streamInfo);  
822 - downloadResult.setMediaServerItem(inviteStreamInfo.getMediaServerItem());  
823 - downloadResult.setResponse(inviteStreamInfo.getResponse());  
824 - hookCallBack.call(downloadResult);  
825 - }, errorEvent); 830 + hookEvent, errorEvent, eventResult ->
  831 + {
  832 + if (eventResult.type == SipSubscribe.EventResultType.response) {
  833 + ResponseEvent responseEvent = (ResponseEvent) eventResult.event;
  834 + String contentString = new String(responseEvent.getResponse().getRawContent());
  835 + // 获取ssrc
  836 + int ssrcIndex = contentString.indexOf("y=");
  837 + // 检查是否有y字段
  838 + if (ssrcIndex >= 0) {
  839 + //ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段 TODO 后续对不规范的非10位ssrc兼容
  840 + String ssrcInResponse = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
  841 + // 查询到ssrc不一致且开启了ssrc校验则需要针对处理
  842 + if (ssrcInfo.getSsrc().equals(ssrcInResponse)) {
  843 + return;
  844 + }
  845 + logger.info("[回放消息] 收到invite 200, 发现下级自定义了ssrc: {}", ssrcInResponse);
  846 + if (!mediaServerItem.isRtpEnable() || device.isSsrcCheck()) {
  847 + logger.info("[回放消息] SSRC修正 {}->{}", ssrcInfo.getSsrc(), ssrcInResponse);
  848 +
  849 + if (!mediaServerItem.getSsrcConfig().checkSsrc(ssrcInResponse)) {
  850 + // ssrc 不可用
  851 + // 释放ssrc
  852 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  853 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  854 + eventResult.msg = "下级自定义了ssrc,但是此ssrc不可用";
  855 + eventResult.statusCode = 400;
  856 + errorEvent.response(eventResult);
  857 + return;
  858 + }
  859 +
  860 + // 单端口模式streamId也有变化,需要重新设置监听
  861 + if (!mediaServerItem.isRtpEnable()) {
  862 + // 添加订阅
  863 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  864 + subscribe.removeSubscribe(hookSubscribe);
  865 + hookSubscribe.getContent().put("stream", String.format("%08x", Integer.parseInt(ssrcInResponse)).toUpperCase());
  866 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, JSONObject response) -> {
  867 + logger.info("[ZLM HOOK] ssrc修正后收到订阅消息: " + response.toJSONString());
  868 + dynamicTask.stop(downLoadTimeOutTaskKey);
  869 + // hook响应
  870 + onPublishHandlerForPlayback(mediaServerItemInUse, response, device.getDeviceId(), channelId, hookCallBack);
  871 + hookEvent.call(new InviteStreamInfo(mediaServerItem, null, eventResult.callId, "rtp", ssrcInfo.getStream()));
  872 + });
  873 + }
  874 + // 关闭rtp server
  875 + mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream());
  876 + // 重新开启ssrc server
  877 + mediaServerService.openRTPServer(mediaServerItem, ssrcInfo.getStream(), ssrcInResponse, device.isSsrcCheck(), true, ssrcInfo.getPort());
  878 + }
  879 + }
  880 + }
  881 +
  882 + });
826 } catch (InvalidArgumentException | SipException | ParseException e) { 883 } catch (InvalidArgumentException | SipException | ParseException e) {
827 logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); 884 logger.error("[命令发送失败] 录像下载: {}", e.getMessage());
828 885
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
@@ -201,7 +201,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { @@ -201,7 +201,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService {
201 dataSourceTransactionManager.commit(transactionStatus); //手动提交 201 dataSourceTransactionManager.commit(transactionStatus); //手动提交
202 result = true; 202 result = true;
203 }catch (Exception e) { 203 }catch (Exception e) {
204 - e.printStackTrace(); 204 + logger.error("未处理的异常 ", e);
205 dataSourceTransactionManager.rollback(transactionStatus); 205 dataSourceTransactionManager.rollback(transactionStatus);
206 } 206 }
207 return result; 207 return result;
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java
1 package com.genersoft.iot.vmp.service.redisMsg; 1 package com.genersoft.iot.vmp.service.redisMsg;
2 2
3 import com.alibaba.fastjson2.JSON; 3 import com.alibaba.fastjson2.JSON;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
4 import com.genersoft.iot.vmp.gb28181.bean.*; 5 import com.genersoft.iot.vmp.gb28181.bean.*;
5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 6 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
6 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -44,13 +45,17 @@ public class RedisAlarmMsgListener implements MessageListener { @@ -44,13 +45,17 @@ public class RedisAlarmMsgListener implements MessageListener {
44 @Autowired 45 @Autowired
45 private ThreadPoolTaskExecutor taskExecutor; 46 private ThreadPoolTaskExecutor taskExecutor;
46 47
  48 + @Autowired
  49 + private UserSetting userSetting;
  50 +
47 @Override 51 @Override
48 public void onMessage(@NotNull Message message, byte[] bytes) { 52 public void onMessage(@NotNull Message message, byte[] bytes) {
  53 + // 消息示例: PUBLISH alarm_receive '{ "gbId": "", "alarmSn": 1, "alarmType": "111", "alarmDescription": "222", }'
49 logger.info("收到来自REDIS的ALARM通知: {}", new String(message.getBody())); 54 logger.info("收到来自REDIS的ALARM通知: {}", new String(message.getBody()));
50 boolean isEmpty = taskQueue.isEmpty(); 55 boolean isEmpty = taskQueue.isEmpty();
51 taskQueue.offer(message); 56 taskQueue.offer(message);
52 if (isEmpty) { 57 if (isEmpty) {
53 - logger.info("[线程池信息]活动线程数:{}, 最大线程数: {}", taskExecutor.getActiveCount(), taskExecutor.getMaxPoolSize()); 58 +// logger.info("[线程池信息]活动线程数:{}, 最大线程数: {}", taskExecutor.getActiveCount(), taskExecutor.getMaxPoolSize());
54 taskExecutor.execute(() -> { 59 taskExecutor.execute(() -> {
55 while (!taskQueue.isEmpty()) { 60 while (!taskQueue.isEmpty()) {
56 Message msg = taskQueue.poll(); 61 Message msg = taskQueue.poll();
@@ -69,22 +74,52 @@ public class RedisAlarmMsgListener implements MessageListener { @@ -69,22 +74,52 @@ public class RedisAlarmMsgListener implements MessageListener {
69 deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn()); 74 deviceAlarm.setAlarmMethod("" + alarmChannelMessage.getAlarmSn());
70 deviceAlarm.setAlarmType("" + alarmChannelMessage.getAlarmType()); 75 deviceAlarm.setAlarmType("" + alarmChannelMessage.getAlarmType());
71 deviceAlarm.setAlarmPriority("1"); 76 deviceAlarm.setAlarmPriority("1");
72 - deviceAlarm.setAlarmTime(DateUtil.getNowForISO8601()); 77 + deviceAlarm.setAlarmTime(DateUtil.getNow());
73 deviceAlarm.setLongitude(0); 78 deviceAlarm.setLongitude(0);
74 deviceAlarm.setLatitude(0); 79 deviceAlarm.setLatitude(0);
75 80
76 if (ObjectUtils.isEmpty(gbId)) { 81 if (ObjectUtils.isEmpty(gbId)) {
77 - // 发送给所有的上级  
78 - List<ParentPlatform> parentPlatforms = storage.queryEnableParentPlatformList(true);  
79 - if (parentPlatforms.size() > 0) {  
80 - for (ParentPlatform parentPlatform : parentPlatforms) { 82 + if (userSetting.getSendToPlatformsWhenIdLost()) {
  83 + // 发送给所有的上级
  84 + List<ParentPlatform> parentPlatforms = storage.queryEnableParentPlatformList(true);
  85 + if (parentPlatforms.size() > 0) {
  86 + for (ParentPlatform parentPlatform : parentPlatforms) {
  87 + try {
  88 + deviceAlarm.setChannelId(parentPlatform.getDeviceGBId());
  89 + commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm);
  90 + } catch (SipException | InvalidArgumentException | ParseException e) {
  91 + logger.error("[命令发送失败] 国标级联 发送报警: {}", e.getMessage());
  92 + }
  93 + }
  94 + }
  95 + }else {
  96 + // 获取开启了消息推送的设备和平台
  97 + List<ParentPlatform> parentPlatforms = storage.queryEnablePlatformListWithAsMessageChannel();
  98 + if (parentPlatforms.size() > 0) {
  99 + for (ParentPlatform parentPlatform : parentPlatforms) {
  100 + try {
  101 + deviceAlarm.setChannelId(parentPlatform.getDeviceGBId());
  102 + commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm);
  103 + } catch (SipException | InvalidArgumentException | ParseException e) {
  104 + logger.error("[命令发送失败] 国标级联 发送报警: {}", e.getMessage());
  105 + }
  106 + }
  107 + }
  108 +
  109 + }
  110 + // 获取开启了消息推送的设备和平台
  111 + List<Device> devices = storage.queryDeviceWithAsMessageChannel();
  112 + if (devices.size() > 0) {
  113 + for (Device device : devices) {
81 try { 114 try {
82 - commanderForPlatform.sendAlarmMessage(parentPlatform, deviceAlarm);  
83 - } catch (SipException | InvalidArgumentException | ParseException e) {  
84 - logger.error("[命令发送失败] 国标级联 发送报警: {}", e.getMessage()); 115 + deviceAlarm.setChannelId(device.getDeviceId());
  116 + commander.sendAlarmMessage(device, deviceAlarm);
  117 + } catch (InvalidArgumentException | SipException | ParseException e) {
  118 + logger.error("[命令发送失败] 发送报警: {}", e.getMessage());
85 } 119 }
86 } 120 }
87 } 121 }
  122 +
88 }else { 123 }else {
89 Device device = storage.queryVideoDevice(gbId); 124 Device device = storage.queryVideoDevice(gbId);
90 ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId); 125 ParentPlatform platform = storage.queryParentPlatByServerGBId(gbId);
@@ -105,6 +140,7 @@ public class RedisAlarmMsgListener implements MessageListener { @@ -105,6 +140,7 @@ public class RedisAlarmMsgListener implements MessageListener {
105 } 140 }
106 } 141 }
107 }catch (Exception e) { 142 }catch (Exception e) {
  143 + logger.error("未处理的异常 ", e);
108 logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 144 logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage());
109 } 145 }
110 } 146 }
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
@@ -202,7 +202,8 @@ public class RedisGbPlayMsgListener implements MessageListener { @@ -202,7 +202,8 @@ public class RedisGbPlayMsgListener implements MessageListener {
202 202
203 } 203 }
204 }catch (Exception e) { 204 }catch (Exception e) {
205 - logger.warn("[RedisGbPlayMsg] 发现未处理的异常, {}",e.getMessage()); 205 + logger.warn("[RedisGbPlayMsg] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  206 + logger.error("[RedisGbPlayMsg] 异常内容: ", e);
206 } 207 }
207 } 208 }
208 }); 209 });
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java
@@ -53,7 +53,8 @@ public class RedisGpsMsgListener implements MessageListener { @@ -53,7 +53,8 @@ public class RedisGpsMsgListener implements MessageListener {
53 // 只是放入redis缓存起来 53 // 只是放入redis缓存起来
54 redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo); 54 redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo);
55 }catch (Exception e) { 55 }catch (Exception e) {
56 - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 56 + logger.warn("[REDIS的ALARM通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  57 + logger.error("[REDIS的ALARM通知] 异常内容: ", e);
57 } 58 }
58 } 59 }
59 }); 60 });
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamResponseListener.java
@@ -58,7 +58,8 @@ public class RedisPushStreamResponseListener implements MessageListener { @@ -58,7 +58,8 @@ public class RedisPushStreamResponseListener implements MessageListener {
58 responseEvents.get(response.getApp() + response.getStream()).run(response); 58 responseEvents.get(response.getApp() + response.getStream()).run(response);
59 } 59 }
60 }catch (Exception e) { 60 }catch (Exception e) {
61 - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 61 + logger.warn("[REDIS消息-请求推流结果] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  62 + logger.error("[REDIS消息-请求推流结果] 异常内容: ", e);
62 } 63 }
63 } 64 }
64 }); 65 });
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java
@@ -95,7 +95,8 @@ public class RedisPushStreamStatusListMsgListener implements MessageListener { @@ -95,7 +95,8 @@ public class RedisPushStreamStatusListMsgListener implements MessageListener {
95 gbStreamService.updateGbIdOrName(streamPushItemForUpdate); 95 gbStreamService.updateGbIdOrName(streamPushItemForUpdate);
96 } 96 }
97 }catch (Exception e) { 97 }catch (Exception e) {
98 - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 98 + logger.warn("[REDIS消息-推流设备列表更新] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  99 + logger.error("[REDIS消息-推流设备列表更新] 异常内容: ", e);
99 } 100 }
100 } 101 }
101 }); 102 });
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java
@@ -79,7 +79,8 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic @@ -79,7 +79,8 @@ public class RedisPushStreamStatusMsgListener implements MessageListener, Applic
79 streamPushService.online(statusChangeFromPushStream.getOnlineStreams()); 79 streamPushService.online(statusChangeFromPushStream.getOnlineStreams());
80 } 80 }
81 }catch (Exception e) { 81 }catch (Exception e) {
82 - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 82 + logger.warn("[REDIS消息-推流设备状态变化] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  83 + logger.error("[REDIS消息-推流设备状态变化] 异常内容: ", e);
83 } 84 }
84 } 85 }
85 }); 86 });
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java
@@ -82,7 +82,8 @@ public class RedisStreamMsgListener implements MessageListener { @@ -82,7 +82,8 @@ public class RedisStreamMsgListener implements MessageListener {
82 zlmMediaListManager.removeMedia(app, stream); 82 zlmMediaListManager.removeMedia(app, stream);
83 } 83 }
84 }catch (Exception e) { 84 }catch (Exception e) {
85 - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, {}",e.getMessage()); 85 + logger.warn("[REDIS消息-流变化] 发现未处理的异常, \r\n{}", JSON.toJSONString(message));
  86 + logger.error("[REDIS消息-流变化] 异常内容: ", e);
86 } 87 }
87 } 88 }
88 }); 89 });
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
5 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 5 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
6 import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo; 6 import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
7 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; 7 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
  8 +import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
8 import com.github.pagehelper.PageInfo; 9 import com.github.pagehelper.PageInfo;
9 10
10 import java.util.List; 11 import java.util.List;
@@ -58,7 +59,7 @@ public interface IVideoManagerStorage { @@ -58,7 +59,7 @@ public interface IVideoManagerStorage {
58 */ 59 */
59 public PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count); 60 public PageInfo<DeviceChannel> queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, Boolean catalogUnderDevice, int page, int count);
60 61
61 - public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds); 62 + public List<DeviceChannelExtend> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, List<String> channelIds, String query, Boolean hasSubChannel, Boolean online, int start, int limit);
62 63
63 64
64 /** 65 /**
@@ -374,4 +375,10 @@ public interface IVideoManagerStorage { @@ -374,4 +375,10 @@ public interface IVideoManagerStorage {
374 void cleanContentForPlatform(String serverGBId); 375 void cleanContentForPlatform(String serverGBId);
375 376
376 List<DeviceChannel> queryChannelWithCatalog(String serverGBId); 377 List<DeviceChannel> queryChannelWithCatalog(String serverGBId);
  378 +
  379 + List<DeviceChannelExtend> queryChannelsByDeviceId(String serial, List<String> channelIds, Boolean online);
  380 +
  381 + List<ParentPlatform> queryEnablePlatformListWithAsMessageChannel();
  382 +
  383 + List<Device> queryDeviceWithAsMessageChannel();
377 } 384 }
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform; 5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform;
6 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo; 6 import com.genersoft.iot.vmp.vmanager.bean.ResourceBaceInfo;
7 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; 7 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
  8 +import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
8 import org.apache.ibatis.annotations.*; 9 import org.apache.ibatis.annotations.*;
9 import org.springframework.stereotype.Repository; 10 import org.springframework.stereotype.Repository;
10 11
@@ -82,7 +83,56 @@ public interface DeviceChannelMapper { @@ -82,7 +83,56 @@ public interface DeviceChannelMapper {
82 "</foreach> </if>" + 83 "</foreach> </if>" +
83 "ORDER BY dc.channelId " + 84 "ORDER BY dc.channelId " +
84 " </script>"}) 85 " </script>"})
85 - List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online,List<String> channelIds); 86 + List<DeviceChannel> queryChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds);
  87 +
  88 + @Select(value = {" <script>" +
  89 + "SELECT " +
  90 + "dc.*, " +
  91 + "de.name as deviceName, " +
  92 + "de.online as deviceOnline " +
  93 + "from " +
  94 + "device_channel dc " +
  95 + "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
  96 + "WHERE 1=1" +
  97 + " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " +
  98 + " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
  99 + " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " +
  100 + " <if test='online == true' > AND dc.status=1</if>" +
  101 + " <if test='online == false' > AND dc.status=0</if>" +
  102 + " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" +
  103 + " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" +
  104 + "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
  105 + "#{item} " +
  106 + "</foreach> </if>" +
  107 + "ORDER BY dc.channelId ASC" +
  108 + " </script>"})
  109 + List<DeviceChannelExtend> queryChannelsWithDeviceInfo(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, List<String> channelIds);
  110 +
  111 +
  112 + @Select(value = {" <script>" +
  113 + "SELECT " +
  114 + "dc.*, " +
  115 + "de.name as deviceName, " +
  116 + "de.online as deviceOnline " +
  117 + "from " +
  118 + "device_channel dc " +
  119 + "LEFT JOIN device de ON dc.deviceId = de.deviceId " +
  120 + "WHERE 1=1" +
  121 + " <if test='deviceId != null'> AND dc.deviceId = #{deviceId} </if> " +
  122 + " <if test='query != null'> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
  123 + " <if test='parentChannelId != null'> AND dc.parentId=#{parentChannelId} </if> " +
  124 + " <if test='online == true' > AND dc.status=1</if>" +
  125 + " <if test='online == false' > AND dc.status=0</if>" +
  126 + " <if test='hasSubChannel == true' > AND dc.subCount > 0 </if>" +
  127 + " <if test='hasSubChannel == false' > AND dc.subCount = 0 </if>" +
  128 + "<if test='channelIds != null'> AND dc.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +
  129 + "#{item} " +
  130 + "</foreach> </if>" +
  131 + "ORDER BY dc.channelId ASC " +
  132 + "Limit #{limit} OFFSET #{start}" +
  133 + " </script>"})
  134 + List<DeviceChannelExtend> queryChannelsByDeviceIdWithStartAndLimit(String deviceId,List<String> channelIds, String parentChannelId, String query,
  135 + Boolean hasSubChannel, Boolean online, int start, int limit);
86 136
87 @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}") 137 @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
88 DeviceChannel queryChannel(String deviceId, String channelId); 138 DeviceChannel queryChannel(String deviceId, String channelId);
@@ -245,28 +295,6 @@ public interface DeviceChannelMapper { @@ -245,28 +295,6 @@ public interface DeviceChannelMapper {
245 int batchUpdate(List<DeviceChannel> updateChannels); 295 int batchUpdate(List<DeviceChannel> updateChannels);
246 296
247 297
248 - @Select(value = {" <script>" +  
249 - "SELECT " +  
250 - "dc1.* " +  
251 - "from " +  
252 - "device_channel dc1 " +  
253 - "WHERE " +  
254 - "dc1.deviceId = #{deviceId} " +  
255 - " <if test='query != null'> AND (dc1.channelId LIKE concat('%',#{query},'%') OR dc1.name LIKE concat('%',#{query},'%') OR dc1.name LIKE concat('%',#{query},'%'))</if> " +  
256 - " <if test='parentChannelId != null'> AND dc1.parentId=#{parentChannelId} </if> " +  
257 - " <if test='online == true' > AND dc1.status=1</if>" +  
258 - " <if test='online == false' > AND dc1.status=0</if>" +  
259 - " <if test='hasSubChannel == true' > AND dc1.subCount >0</if>" +  
260 - " <if test='hasSubChannel == false' > AND dc1.subCount=0</if>" +  
261 - "<if test='channelIds != null'> AND dc1.channelId in <foreach item='item' index='index' collection='channelIds' open='(' separator=',' close=')'>" +  
262 - "#{item} " +  
263 - "</foreach> </if>" +  
264 - "ORDER BY dc1.channelId ASC " +  
265 - "Limit #{limit} OFFSET #{start}" +  
266 - " </script>"})  
267 - List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String parentChannelId, String query,  
268 - Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds);  
269 -  
270 @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1") 298 @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND status=1")
271 List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId); 299 List<DeviceChannel> queryOnlineChannelsByDeviceId(String deviceId);
272 300
@@ -316,10 +344,10 @@ public interface DeviceChannelMapper { @@ -316,10 +344,10 @@ public interface DeviceChannelMapper {
316 "select * " + 344 "select * " +
317 "from device_channel " + 345 "from device_channel " +
318 "where deviceId=#{deviceId}" + 346 "where deviceId=#{deviceId}" +
319 - " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, #{parentId.length()}) = #{parentId} and length(channelId)=#{length} </if>" + 347 + " <if test='parentId != null and length != null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} and length(channelId)=#{length} </if>" +
320 " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=#{length} </if>" + 348 " <if test='parentId == null and length != null' > and parentId = #{parentId} or length(channelId)=#{length} </if>" +
321 " <if test='parentId == null and length == null' > and parentId = #{parentId} </if>" + 349 " <if test='parentId == null and length == null' > and parentId = #{parentId} </if>" +
322 - " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, #{parentId.length()}) = #{parentId} </if>" + 350 + " <if test='parentId != null and length == null' > and parentId = #{parentId} or left(channelId, LENGTH(#{parentId})) = #{parentId} </if>" +
323 " </script>"}) 351 " </script>"})
324 List<DeviceChannel> getChannelsWithCivilCodeAndLength(String deviceId, String parentId, Integer length); 352 List<DeviceChannel> getChannelsWithCivilCodeAndLength(String deviceId, String parentId, Integer length);
325 353
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
@@ -39,9 +39,12 @@ public interface DeviceMapper { @@ -39,9 +39,12 @@ public interface DeviceMapper {
39 "mobilePositionSubmissionInterval," + 39 "mobilePositionSubmissionInterval," +
40 "subscribeCycleForAlarm," + 40 "subscribeCycleForAlarm," +
41 "ssrcCheck," + 41 "ssrcCheck," +
  42 + "asMessageChannel," +
42 "geoCoordSys," + 43 "geoCoordSys," +
43 "treeType," + 44 "treeType," +
44 - "online" + 45 + "online," +
  46 + "mediaServerId," +
  47 + "(SELECT count(0) FROM device_channel WHERE deviceId=device.deviceId) as channelCount "+
45 " FROM device WHERE deviceId = #{deviceId}") 48 " FROM device WHERE deviceId = #{deviceId}")
46 Device getDeviceByDeviceId(String deviceId); 49 Device getDeviceByDeviceId(String deviceId);
47 50
@@ -70,6 +73,7 @@ public interface DeviceMapper { @@ -70,6 +73,7 @@ public interface DeviceMapper {
70 "mobilePositionSubmissionInterval," + 73 "mobilePositionSubmissionInterval," +
71 "subscribeCycleForAlarm," + 74 "subscribeCycleForAlarm," +
72 "ssrcCheck," + 75 "ssrcCheck," +
  76 + "asMessageChannel," +
73 "geoCoordSys," + 77 "geoCoordSys," +
74 "treeType," + 78 "treeType," +
75 "online" + 79 "online" +
@@ -98,6 +102,7 @@ public interface DeviceMapper { @@ -98,6 +102,7 @@ public interface DeviceMapper {
98 "#{mobilePositionSubmissionInterval}," + 102 "#{mobilePositionSubmissionInterval}," +
99 "#{subscribeCycleForAlarm}," + 103 "#{subscribeCycleForAlarm}," +
100 "#{ssrcCheck}," + 104 "#{ssrcCheck}," +
  105 + "#{asMessageChannel}," +
101 "#{geoCoordSys}," + 106 "#{geoCoordSys}," +
102 "#{treeType}," + 107 "#{treeType}," +
103 "#{online}" + 108 "#{online}" +
@@ -152,9 +157,11 @@ public interface DeviceMapper { @@ -152,9 +157,11 @@ public interface DeviceMapper {
152 "mobilePositionSubmissionInterval," + 157 "mobilePositionSubmissionInterval," +
153 "subscribeCycleForAlarm," + 158 "subscribeCycleForAlarm," +
154 "ssrcCheck," + 159 "ssrcCheck," +
  160 + "asMessageChannel," +
155 "geoCoordSys," + 161 "geoCoordSys," +
156 "treeType," + 162 "treeType," +
157 "online," + 163 "online," +
  164 + "mediaServerId," +
158 "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de" + 165 "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de" +
159 "<if test=\"online != null\"> where online=${online}</if>"+ 166 "<if test=\"online != null\"> where online=${online}</if>"+
160 " </script>" 167 " </script>"
@@ -164,9 +171,6 @@ public interface DeviceMapper { @@ -164,9 +171,6 @@ public interface DeviceMapper {
164 @Delete("DELETE FROM device WHERE deviceId=#{deviceId}") 171 @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
165 int del(String deviceId); 172 int del(String deviceId);
166 173
167 - @Update("UPDATE device SET online=0")  
168 - int outlineForAll();  
169 -  
170 @Select("SELECT " + 174 @Select("SELECT " +
171 "deviceId, " + 175 "deviceId, " +
172 "coalesce(custom_name, name) as name, " + 176 "coalesce(custom_name, name) as name, " +
@@ -192,6 +196,7 @@ public interface DeviceMapper { @@ -192,6 +196,7 @@ public interface DeviceMapper {
192 "mobilePositionSubmissionInterval," + 196 "mobilePositionSubmissionInterval," +
193 "subscribeCycleForAlarm," + 197 "subscribeCycleForAlarm," +
194 "ssrcCheck," + 198 "ssrcCheck," +
  199 + "asMessageChannel," +
195 "geoCoordSys," + 200 "geoCoordSys," +
196 "treeType," + 201 "treeType," +
197 "online " + 202 "online " +
@@ -222,6 +227,7 @@ public interface DeviceMapper { @@ -222,6 +227,7 @@ public interface DeviceMapper {
222 "mobilePositionSubmissionInterval," + 227 "mobilePositionSubmissionInterval," +
223 "subscribeCycleForAlarm," + 228 "subscribeCycleForAlarm," +
224 "ssrcCheck," + 229 "ssrcCheck," +
  230 + "asMessageChannel," +
225 "geoCoordSys," + 231 "geoCoordSys," +
226 "treeType," + 232 "treeType," +
227 "online" + 233 "online" +
@@ -243,12 +249,13 @@ public interface DeviceMapper { @@ -243,12 +249,13 @@ public interface DeviceMapper {
243 "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=#{mobilePositionSubmissionInterval}</if>" + 249 "<if test=\"mobilePositionSubmissionInterval != null\">, mobilePositionSubmissionInterval=#{mobilePositionSubmissionInterval}</if>" +
244 "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=#{subscribeCycleForAlarm}</if>" + 250 "<if test=\"subscribeCycleForAlarm != null\">, subscribeCycleForAlarm=#{subscribeCycleForAlarm}</if>" +
245 "<if test=\"ssrcCheck != null\">, ssrcCheck=#{ssrcCheck}</if>" + 251 "<if test=\"ssrcCheck != null\">, ssrcCheck=#{ssrcCheck}</if>" +
  252 + "<if test=\"asMessageChannel != null\">, asMessageChannel=#{asMessageChannel}</if>" +
246 "<if test=\"geoCoordSys != null\">, geoCoordSys=#{geoCoordSys}</if>" + 253 "<if test=\"geoCoordSys != null\">, geoCoordSys=#{geoCoordSys}</if>" +
247 "<if test=\"treeType != null\">, treeType=#{treeType}</if>" + 254 "<if test=\"treeType != null\">, treeType=#{treeType}</if>" +
248 "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" + 255 "<if test=\"mediaServerId != null\">, mediaServerId=#{mediaServerId}</if>" +
249 "WHERE deviceId=#{deviceId}"+ 256 "WHERE deviceId=#{deviceId}"+
250 " </script>"}) 257 " </script>"})
251 - int updateCustom(Device device); 258 + void updateCustom(Device device);
252 259
253 @Insert("INSERT INTO device (" + 260 @Insert("INSERT INTO device (" +
254 "deviceId, " + 261 "deviceId, " +
@@ -259,9 +266,11 @@ public interface DeviceMapper { @@ -259,9 +266,11 @@ public interface DeviceMapper {
259 "updateTime," + 266 "updateTime," +
260 "charset," + 267 "charset," +
261 "ssrcCheck," + 268 "ssrcCheck," +
  269 + "asMessageChannel," +
262 "geoCoordSys," + 270 "geoCoordSys," +
263 "treeType," + 271 "treeType," +
264 - "online" + 272 + "online," +
  273 + "mediaServerId" +
265 ") VALUES (" + 274 ") VALUES (" +
266 "#{deviceId}," + 275 "#{deviceId}," +
267 "#{name}," + 276 "#{name}," +
@@ -271,9 +280,11 @@ public interface DeviceMapper { @@ -271,9 +280,11 @@ public interface DeviceMapper {
271 "#{updateTime}," + 280 "#{updateTime}," +
272 "#{charset}," + 281 "#{charset}," +
273 "#{ssrcCheck}," + 282 "#{ssrcCheck}," +
  283 + "#{asMessageChannel}," +
274 "#{geoCoordSys}," + 284 "#{geoCoordSys}," +
275 "#{treeType}," + 285 "#{treeType}," +
276 - "#{online}" + 286 + "#{online}," +
  287 + "#{mediaServerId}" +
277 ")") 288 ")")
278 void addCustomDevice(Device device); 289 void addCustomDevice(Device device);
279 290
@@ -282,4 +293,7 @@ public interface DeviceMapper { @@ -282,4 +293,7 @@ public interface DeviceMapper {
282 293
283 @Select("select * from device") 294 @Select("select * from device")
284 List<Device> getAll(); 295 List<Device> getAll();
  296 +
  297 + @Select("select * from device where asMessageChannel = 1")
  298 + List<Device> queryDeviceWithAsMessageChannel();
285 } 299 }
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
@@ -15,10 +15,10 @@ import java.util.List; @@ -15,10 +15,10 @@ import java.util.List;
15 public interface ParentPlatformMapper { 15 public interface ParentPlatformMapper {
16 16
17 @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " + 17 @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " +
18 - " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " + 18 + " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, asMessageChannel, " +
19 " status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " + 19 " status, startOfflinePush, catalogId, administrativeDivision, catalogGroup, createTime, updateTime, treeType) " +
20 " VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " + 20 " VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIP}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " +
21 - " #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, " + 21 + " #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{asMessageChannel}, " +
22 " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})") 22 " #{status}, #{startOfflinePush}, #{catalogId}, #{administrativeDivision}, #{catalogGroup}, #{createTime}, #{updateTime}, #{treeType})")
23 int addParentPlatform(ParentPlatform parentPlatform); 23 int addParentPlatform(ParentPlatform parentPlatform);
24 24
@@ -40,6 +40,7 @@ public interface ParentPlatformMapper { @@ -40,6 +40,7 @@ public interface ParentPlatformMapper {
40 "characterSet=#{characterSet}, " + 40 "characterSet=#{characterSet}, " +
41 "ptz=#{ptz}, " + 41 "ptz=#{ptz}, " +
42 "rtcp=#{rtcp}, " + 42 "rtcp=#{rtcp}, " +
  43 + "asMessageChannel=#{asMessageChannel}, " +
43 "status=#{status}, " + 44 "status=#{status}, " +
44 "startOfflinePush=#{startOfflinePush}, " + 45 "startOfflinePush=#{startOfflinePush}, " +
45 "catalogGroup=#{catalogGroup}, " + 46 "catalogGroup=#{catalogGroup}, " +
@@ -68,9 +69,12 @@ public interface ParentPlatformMapper { @@ -68,9 +69,12 @@ public interface ParentPlatformMapper {
68 "FROM parent_platform pp ") 69 "FROM parent_platform pp ")
69 List<ParentPlatform> getParentPlatformList(); 70 List<ParentPlatform> getParentPlatformList();
70 71
71 - @Select("SELECT * FROM parent_platform WHERE enable=#{enable}") 72 + @Select("SELECT * FROM parent_platform WHERE enable=#{enable} ")
72 List<ParentPlatform> getEnableParentPlatformList(boolean enable); 73 List<ParentPlatform> getEnableParentPlatformList(boolean enable);
73 74
  75 + @Select("SELECT * FROM parent_platform WHERE enable=1 and asMessageChannel = 1")
  76 + List<ParentPlatform> queryEnablePlatformListWithAsMessageChannel();
  77 +
74 @Select("SELECT * FROM parent_platform WHERE serverGBId=#{platformGbId}") 78 @Select("SELECT * FROM parent_platform WHERE serverGBId=#{platformGbId}")
75 ParentPlatform getParentPlatByServerGBId(String platformGbId); 79 ParentPlatform getParentPlatByServerGBId(String platformGbId);
76 80
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
@@ -177,12 +177,14 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -177,12 +177,14 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
177 @Override 177 @Override
178 public boolean startDownload(StreamInfo stream, String callId) { 178 public boolean startDownload(StreamInfo stream, String callId) {
179 boolean result; 179 boolean result;
  180 + String key=String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,
  181 + userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId);
180 if (stream.getProgress() == 1) { 182 if (stream.getProgress() == 1) {
181 - result = RedisUtil.set(String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
182 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream); 183 + logger.debug("添加下载缓存==已完成下载=》{}",key);
  184 + result = RedisUtil.set(key, stream);
183 }else { 185 }else {
184 - result = RedisUtil.set(String.format("%S_%s_%s_%s_%s_%s_%s", VideoManagerConstants.DOWNLOAD_PREFIX,  
185 - userSetting.getServerId(), stream.getMediaServerId(), stream.getDeviceID(), stream.getChannelId(), stream.getStream(), callId), stream, 60*60); 186 + logger.debug("添加下载缓存==未完成下载=》{}",key);
  187 + result = RedisUtil.set(key, stream, 60*60);
186 } 188 }
187 return result; 189 return result;
188 } 190 }
@@ -617,7 +619,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -617,7 +619,7 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
617 stream, 619 stream,
618 callId 620 callId
619 ); 621 );
620 - List<Object> streamInfoScan = RedisUtil.scan(key); 622 + List<Object> streamInfoScan = RedisUtil.scan2(key);
621 if (streamInfoScan.size() > 0) { 623 if (streamInfoScan.size() > 0) {
622 return (StreamInfo) RedisUtil.get((String) streamInfoScan.get(0)); 624 return (StreamInfo) RedisUtil.get((String) streamInfoScan.get(0));
623 }else { 625 }else {
@@ -855,7 +857,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @@ -855,7 +857,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
855 857
856 @Override 858 @Override
857 public void sendAlarmMsg(AlarmChannelMessage msg) { 859 public void sendAlarmMsg(AlarmChannelMessage msg) {
858 - String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM_RECEIVE; 860 + // 此消息用于对接第三方服务下级来的消息内容
  861 + String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_ALARM;
859 logger.info("[redis发送通知] 报警{}: {}", key, JSON.toJSON(msg)); 862 logger.info("[redis发送通知] 报警{}: {}", key, JSON.toJSON(msg));
860 RedisUtil.convertAndSend(key, (JSONObject)JSON.toJSON(msg)); 863 RedisUtil.convertAndSend(key, (JSONObject)JSON.toJSON(msg));
861 } 864 }
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.storager.dao.*; @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.storager.dao.*;
13 import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo; 13 import com.genersoft.iot.vmp.storager.dao.dto.ChannelSourceInfo;
14 import com.genersoft.iot.vmp.utils.DateUtil; 14 import com.genersoft.iot.vmp.utils.DateUtil;
15 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; 15 import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
  16 +import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend;
16 import com.github.pagehelper.PageHelper; 17 import com.github.pagehelper.PageHelper;
17 import com.github.pagehelper.PageInfo; 18 import com.github.pagehelper.PageInfo;
18 import org.slf4j.Logger; 19 import org.slf4j.Logger;
@@ -189,7 +190,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -189,7 +190,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
189 dataSourceTransactionManager.commit(transactionStatus); //手动提交 190 dataSourceTransactionManager.commit(transactionStatus); //手动提交
190 return true; 191 return true;
191 }catch (Exception e) { 192 }catch (Exception e) {
192 - e.printStackTrace(); 193 + logger.error("未处理的异常 ", e);
193 dataSourceTransactionManager.rollback(transactionStatus); 194 dataSourceTransactionManager.rollback(transactionStatus);
194 return false; 195 return false;
195 } 196 }
@@ -305,7 +306,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -305,7 +306,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
305 } 306 }
306 return true; 307 return true;
307 }catch (Exception e) { 308 }catch (Exception e) {
308 - e.printStackTrace(); 309 + logger.error("未处理的异常 ", e);
309 dataSourceTransactionManager.rollback(transactionStatus); 310 dataSourceTransactionManager.rollback(transactionStatus);
310 return false; 311 return false;
311 } 312 }
@@ -359,8 +360,8 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -359,8 +360,8 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
359 } 360 }
360 361
361 @Override 362 @Override
362 - public List<DeviceChannel> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, String query, Boolean hasSubChannel, Boolean online, int start, int limit,List<String> channelIds) {  
363 - return deviceChannelMapper.queryChannelsByDeviceIdWithStartAndLimit(deviceId, null, query, hasSubChannel, online, start, limit,channelIds); 363 + public List<DeviceChannelExtend> queryChannelsByDeviceIdWithStartAndLimit(String deviceId, List<String> channelIds, String query, Boolean hasSubChannel, Boolean online, int start, int limit) {
  364 + return deviceChannelMapper.queryChannelsByDeviceIdWithStartAndLimit(deviceId, channelIds, null, query, hasSubChannel, online, start, limit);
364 } 365 }
365 366
366 367
@@ -370,6 +371,11 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -370,6 +371,11 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
370 } 371 }
371 372
372 @Override 373 @Override
  374 + public List<DeviceChannelExtend> queryChannelsByDeviceId(String deviceId, List<String> channelIds, Boolean online) {
  375 + return deviceChannelMapper.queryChannelsWithDeviceInfo(deviceId, null,null, null, online,channelIds);
  376 + }
  377 +
  378 + @Override
373 public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, int page, int count) { 379 public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
374 PageHelper.startPage(page, count); 380 PageHelper.startPage(page, count);
375 List<DeviceChannel> all = deviceChannelMapper.queryChannels(deviceId, parentChannelId, query, hasSubChannel, online,null); 381 List<DeviceChannel> all = deviceChannelMapper.queryChannels(deviceId, parentChannelId, query, hasSubChannel, online,null);
@@ -512,6 +518,16 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -512,6 +518,16 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
512 } 518 }
513 519
514 @Override 520 @Override
  521 + public List<ParentPlatform> queryEnablePlatformListWithAsMessageChannel() {
  522 + return platformMapper.queryEnablePlatformListWithAsMessageChannel();
  523 + }
  524 +
  525 + @Override
  526 + public List<Device> queryDeviceWithAsMessageChannel() {
  527 + return deviceMapper.queryDeviceWithAsMessageChannel();
  528 + }
  529 +
  530 + @Override
515 public void outlineForAllParentPlatform() { 531 public void outlineForAllParentPlatform() {
516 platformMapper.outlineForAllParentPlatform(); 532 platformMapper.outlineForAllParentPlatform();
517 } 533 }
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
@@ -45,7 +45,6 @@ public class DateUtil { @@ -45,7 +45,6 @@ public class DateUtil {
45 45
46 public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) { 46 public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) {
47 return formatter.format(formatterCompatibleISO8601.parse(formatTime)); 47 return formatter.format(formatterCompatibleISO8601.parse(formatTime));
48 -  
49 } 48 }
50 49
51 /** 50 /**
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java
@@ -881,7 +881,13 @@ public class RedisUtil { @@ -881,7 +881,13 @@ public class RedisUtil {
881 881
882 return new ArrayList<>(resultKeys); 882 return new ArrayList<>(resultKeys);
883 } 883 }
884 - 884 + public static List<Object> scan2(String query) {
  885 + if (redisTemplate == null) {
  886 + redisTemplate = SpringBeanFactory.getBean("redisTemplate");
  887 + }
  888 + Set<String> keys = redisTemplate.keys(query);
  889 + return new ArrayList<>(keys);
  890 + }
885 // ============================== 消息发送与订阅 ============================== 891 // ============================== 消息发送与订阅 ==============================
886 public static void convertAndSend(String channel, JSONObject msg) { 892 public static void convertAndSend(String channel, JSONObject msg) {
887 if (redisTemplate == null) { 893 if (redisTemplate == null) {
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -28,6 +28,10 @@ public class WVPResult&lt;T&gt; implements Cloneable{ @@ -28,6 +28,10 @@ public class WVPResult&lt;T&gt; implements Cloneable{
28 return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t); 28 return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t);
29 } 29 }
30 30
  31 + public static WVPResult success() {
  32 + return new WVPResult<>(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), null);
  33 + }
  34 +
31 public static <T> WVPResult<T> success(T t) { 35 public static <T> WVPResult<T> success(T t) {
32 return success(t, ErrorCode.SUCCESS.getMsg()); 36 return success(t, ErrorCode.SUCCESS.getMsg());
33 } 37 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
@@ -30,7 +30,7 @@ import java.util.UUID; @@ -30,7 +30,7 @@ import java.util.UUID;
30 * 位置信息管理 30 * 位置信息管理
31 */ 31 */
32 @Tag(name = "位置信息管理") 32 @Tag(name = "位置信息管理")
33 -@CrossOrigin 33 +
34 @RestController 34 @RestController
35 @RequestMapping("/api/position") 35 @RequestMapping("/api/position")
36 public class MobilePositionController { 36 public class MobilePositionController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java
@@ -17,7 +17,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; @@ -17,7 +17,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
17 * @data: 2021-01-20 17 * @data: 2021-01-20
18 */ 18 */
19 @Tag(name = "SSE推送") 19 @Tag(name = "SSE推送")
20 -@CrossOrigin 20 +
21 @Controller 21 @Controller
22 @RequestMapping("/api") 22 @RequestMapping("/api")
23 public class SseController { 23 public class SseController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
@@ -6,35 +6,28 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; @@ -6,35 +6,28 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 6 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 7 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
9 -import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookListener;  
10 import com.genersoft.iot.vmp.service.IDeviceAlarmService; 9 import com.genersoft.iot.vmp.service.IDeviceAlarmService;
11 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 10 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
12 import com.genersoft.iot.vmp.utils.DateUtil; 11 import com.genersoft.iot.vmp.utils.DateUtil;
13 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 12 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
14 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
15 import com.github.pagehelper.PageInfo; 13 import com.github.pagehelper.PageInfo;
16 import io.swagger.v3.oas.annotations.Operation; 14 import io.swagger.v3.oas.annotations.Operation;
17 import io.swagger.v3.oas.annotations.Parameter; 15 import io.swagger.v3.oas.annotations.Parameter;
18 -import io.swagger.v3.oas.annotations.responses.ApiResponse;  
19 import io.swagger.v3.oas.annotations.tags.Tag; 16 import io.swagger.v3.oas.annotations.tags.Tag;
20 import org.slf4j.Logger; 17 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory; 18 import org.slf4j.LoggerFactory;
22 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
23 -import org.springframework.http.HttpStatus;  
24 -import org.springframework.http.ResponseEntity;  
25 import org.springframework.util.ObjectUtils; 20 import org.springframework.util.ObjectUtils;
26 -import org.springframework.util.StringUtils;  
27 import org.springframework.web.bind.annotation.*; 21 import org.springframework.web.bind.annotation.*;
28 22
29 import javax.sip.InvalidArgumentException; 23 import javax.sip.InvalidArgumentException;
30 import javax.sip.SipException; 24 import javax.sip.SipException;
31 import java.text.ParseException; 25 import java.text.ParseException;
32 -import java.time.LocalDateTime;  
33 import java.util.Arrays; 26 import java.util.Arrays;
34 import java.util.List; 27 import java.util.List;
35 28
36 @Tag(name = "报警信息管理") 29 @Tag(name = "报警信息管理")
37 -@CrossOrigin 30 +
38 @RestController 31 @RestController
39 @RequestMapping("/api/alarm") 32 @RequestMapping("/api/alarm")
40 public class AlarmController { 33 public class AlarmController {
@@ -78,11 +71,11 @@ public class AlarmController { @@ -78,11 +71,11 @@ public class AlarmController {
78 if (ObjectUtils.isEmpty(deviceIds)) { 71 if (ObjectUtils.isEmpty(deviceIds)) {
79 deviceIds = null; 72 deviceIds = null;
80 } 73 }
  74 +
81 if (ObjectUtils.isEmpty(time)) { 75 if (ObjectUtils.isEmpty(time)) {
82 time = null; 76 time = null;
83 - }  
84 - if (!DateUtil.verification(time, DateUtil.formatter) ){  
85 - return null; 77 + }else if (!DateUtil.verification(time, DateUtil.formatter) ){
  78 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "time格式为" + DateUtil.PATTERN);
86 } 79 }
87 List<String> deviceIdList = null; 80 List<String> deviceIdList = null;
88 if (deviceIds != null) { 81 if (deviceIds != null) {
@@ -110,7 +103,7 @@ public class AlarmController { @@ -110,7 +103,7 @@ public class AlarmController {
110 deviceAlarm.setAlarmDescription("test"); 103 deviceAlarm.setAlarmDescription("test");
111 deviceAlarm.setAlarmMethod("1"); 104 deviceAlarm.setAlarmMethod("1");
112 deviceAlarm.setAlarmPriority("1"); 105 deviceAlarm.setAlarmPriority("1");
113 - deviceAlarm.setAlarmTime(DateUtil.formatterISO8601.format(LocalDateTime.now())); 106 + deviceAlarm.setAlarmTime(DateUtil.getNow());
114 deviceAlarm.setAlarmType("1"); 107 deviceAlarm.setAlarmType("1");
115 deviceAlarm.setLongitude(115.33333); 108 deviceAlarm.setLongitude(115.33333);
116 deviceAlarm.setLatitude(39.33333); 109 deviceAlarm.setLatitude(39.33333);
@@ -177,16 +170,17 @@ public class AlarmController { @@ -177,16 +170,17 @@ public class AlarmController {
177 if (ObjectUtils.isEmpty(alarmType)) { 170 if (ObjectUtils.isEmpty(alarmType)) {
178 alarmType = null; 171 alarmType = null;
179 } 172 }
  173 +
180 if (ObjectUtils.isEmpty(startTime)) { 174 if (ObjectUtils.isEmpty(startTime)) {
181 startTime = null; 175 startTime = null;
  176 + }else if (!DateUtil.verification(startTime, DateUtil.formatter) ){
  177 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "startTime格式为" + DateUtil.PATTERN);
182 } 178 }
  179 +
183 if (ObjectUtils.isEmpty(endTime)) { 180 if (ObjectUtils.isEmpty(endTime)) {
184 endTime = null; 181 endTime = null;
185 - }  
186 -  
187 -  
188 - if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){  
189 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间或结束时间格式有误"); 182 + }else if (!DateUtil.verification(endTime, DateUtil.formatter) ){
  183 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "endTime格式为" + DateUtil.PATTERN);
190 } 184 }
191 185
192 return deviceAlarmService.getAllAlarm(page, count, deviceId, alarmPriority, alarmMethod, 186 return deviceAlarmService.getAllAlarm(page, count, deviceId, alarmPriority, alarmMethod,
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
@@ -14,7 +14,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -14,7 +14,6 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
14 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 15 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
17 -  
18 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 17 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
19 import io.swagger.v3.oas.annotations.Operation; 18 import io.swagger.v3.oas.annotations.Operation;
20 import io.swagger.v3.oas.annotations.Parameter; 19 import io.swagger.v3.oas.annotations.Parameter;
@@ -22,9 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; @@ -22,9 +21,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
22 import org.slf4j.Logger; 21 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory; 22 import org.slf4j.LoggerFactory;
24 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
25 -import org.springframework.http.ResponseEntity;  
26 import org.springframework.util.ObjectUtils; 24 import org.springframework.util.ObjectUtils;
27 -import org.springframework.util.StringUtils;  
28 import org.springframework.web.bind.annotation.*; 25 import org.springframework.web.bind.annotation.*;
29 import org.springframework.web.context.request.async.DeferredResult; 26 import org.springframework.web.context.request.async.DeferredResult;
30 27
@@ -34,7 +31,6 @@ import java.text.ParseException; @@ -34,7 +31,6 @@ import java.text.ParseException;
34 import java.util.UUID; 31 import java.util.UUID;
35 32
36 @Tag(name = "国标设备配置") 33 @Tag(name = "国标设备配置")
37 -@CrossOrigin  
38 @RestController 34 @RestController
39 @RequestMapping("/api/device/config") 35 @RequestMapping("/api/device/config")
40 public class DeviceConfig { 36 public class DeviceConfig {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
@@ -32,7 +32,7 @@ import java.text.ParseException; @@ -32,7 +32,7 @@ import java.text.ParseException;
32 import java.util.UUID; 32 import java.util.UUID;
33 33
34 @Tag(name = "国标设备控制") 34 @Tag(name = "国标设备控制")
35 -@CrossOrigin 35 +
36 @RestController 36 @RestController
37 @RequestMapping("/api/device/control") 37 @RequestMapping("/api/device/control")
38 public class DeviceControl { 38 public class DeviceControl {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation; @@ -24,6 +24,7 @@ import io.swagger.v3.oas.annotations.Operation;
24 import io.swagger.v3.oas.annotations.Parameter; 24 import io.swagger.v3.oas.annotations.Parameter;
25 import io.swagger.v3.oas.annotations.tags.Tag; 25 import io.swagger.v3.oas.annotations.tags.Tag;
26 import org.apache.commons.compress.utils.IOUtils; 26 import org.apache.commons.compress.utils.IOUtils;
  27 +import org.apache.ibatis.annotations.Options;
27 import org.slf4j.Logger; 28 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory; 29 import org.slf4j.LoggerFactory;
29 import org.springframework.beans.factory.annotation.Autowired; 30 import org.springframework.beans.factory.annotation.Autowired;
@@ -46,7 +47,7 @@ import java.util.*; @@ -46,7 +47,7 @@ import java.util.*;
46 47
47 @Tag(name = "国标设备查询", description = "国标设备查询") 48 @Tag(name = "国标设备查询", description = "国标设备查询")
48 @SuppressWarnings("rawtypes") 49 @SuppressWarnings("rawtypes")
49 -@CrossOrigin 50 +
50 @RestController 51 @RestController
51 @RequestMapping("/api/device/query") 52 @RequestMapping("/api/device/query")
52 public class DeviceQuery { 53 public class DeviceQuery {
@@ -97,8 +98,10 @@ public class DeviceQuery { @@ -97,8 +98,10 @@ public class DeviceQuery {
97 @Parameter(name = "page", description = "当前页", required = true) 98 @Parameter(name = "page", description = "当前页", required = true)
98 @Parameter(name = "count", description = "每页查询数量", required = true) 99 @Parameter(name = "count", description = "每页查询数量", required = true)
99 @GetMapping("/devices") 100 @GetMapping("/devices")
  101 + @Options()
100 public PageInfo<Device> devices(int page, int count){ 102 public PageInfo<Device> devices(int page, int count){
101 - 103 +// if (page == null) page = 0;
  104 +// if (count == null) count = 20;
102 return storager.queryVideoDeviceList(page, count,null); 105 return storager.queryVideoDeviceList(page, count,null);
103 } 106 }
104 107
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
@@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*; @@ -17,7 +17,7 @@ import org.springframework.web.bind.annotation.*;
17 import java.util.List; 17 import java.util.List;
18 18
19 @Tag(name = "视频流关联到级联平台") 19 @Tag(name = "视频流关联到级联平台")
20 -@CrossOrigin 20 +
21 @RestController 21 @RestController
22 @RequestMapping("/api/gbStream") 22 @RequestMapping("/api/gbStream")
23 public class GbStreamController { 23 public class GbStreamController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
@@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletRequest; @@ -24,7 +24,7 @@ import javax.servlet.http.HttpServletRequest;
24 24
25 @Tag(name = "媒体流相关") 25 @Tag(name = "媒体流相关")
26 @Controller 26 @Controller
27 -@CrossOrigin 27 +
28 @RequestMapping(value = "/api/media") 28 @RequestMapping(value = "/api/media")
29 public class MediaController { 29 public class MediaController {
30 30
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
@@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask; @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.DynamicTask;
7 import com.genersoft.iot.vmp.conf.UserSetting; 7 import com.genersoft.iot.vmp.conf.UserSetting;
8 import com.genersoft.iot.vmp.conf.exception.ControllerException; 8 import com.genersoft.iot.vmp.conf.exception.ControllerException;
9 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; 9 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  10 +import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
10 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; 11 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
11 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; 12 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
12 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 13 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
@@ -37,7 +38,7 @@ import java.util.List; @@ -37,7 +38,7 @@ import java.util.List;
37 * 级联平台管理 38 * 级联平台管理
38 */ 39 */
39 @Tag(name = "级联平台管理") 40 @Tag(name = "级联平台管理")
40 -@CrossOrigin 41 +
41 @RestController 42 @RestController
42 @RequestMapping("/api/platform") 43 @RequestMapping("/api/platform")
43 public class PlatformController { 44 public class PlatformController {
@@ -205,58 +206,8 @@ public class PlatformController { @@ -205,58 +206,8 @@ public class PlatformController {
205 ) { 206 ) {
206 throw new ControllerException(ErrorCode.ERROR400); 207 throw new ControllerException(ErrorCode.ERROR400);
207 } 208 }
208 - parentPlatform.setCharacterSet(parentPlatform.getCharacterSet().toUpperCase());  
209 - ParentPlatform parentPlatformOld = storager.queryParentPlatByServerGBId(parentPlatform.getServerGBId());  
210 - parentPlatform.setUpdateTime(DateUtil.getNow());  
211 - if (!parentPlatformOld.getTreeType().equals(parentPlatform.getTreeType())) {  
212 - // 目录结构发生变化,清空之前的关联关系  
213 - logger.info("保存平台{}时发现目录结构变化,清空关联关系", parentPlatform.getDeviceGBId());  
214 - storager.cleanContentForPlatform(parentPlatform.getServerGBId());  
215 -  
216 - }  
217 - boolean updateResult = storager.updateParentPlatform(parentPlatform);  
218 -  
219 - if (updateResult) {  
220 - // 保存时启用就发送注册  
221 - if (parentPlatform.isEnable()) {  
222 - if (parentPlatformOld != null && parentPlatformOld.isStatus()) {  
223 - try {  
224 - commanderForPlatform.unregister(parentPlatformOld, null, null);  
225 - } catch (InvalidArgumentException | ParseException | SipException e) {  
226 - logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());  
227 - }  
228 - try {  
229 - Thread.sleep(500);  
230 - } catch (InterruptedException e) {  
231 - logger.error("[线程休眠失败] : {}", e.getMessage());  
232 - }  
233 - // 只要保存就发送注册  
234 - try {  
235 - commanderForPlatform.register(parentPlatform, null, null);  
236 - } catch (InvalidArgumentException | ParseException | SipException e) {  
237 - logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage());  
238 - }  
239 -  
240 - } else {  
241 - // 只要保存就发送注册  
242 - try {  
243 - commanderForPlatform.register(parentPlatform, null, null);  
244 - } catch (InvalidArgumentException | ParseException | SipException e) {  
245 - logger.error("[命令发送失败] 国标级联 注册: {}", e.getMessage());  
246 - }  
247 - }  
248 - } else if (parentPlatformOld != null && parentPlatformOld.isEnable() && !parentPlatform.isEnable()) { // 关闭启用时注销  
249 - try {  
250 - commanderForPlatform.unregister(parentPlatformOld, null, null);  
251 - } catch (InvalidArgumentException | ParseException | SipException e) {  
252 - logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());  
253 - }  
254 - // 停止订阅相关的定时任务  
255 - subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId());  
256 - }  
257 - } else {  
258 - throw new ControllerException(ErrorCode.ERROR100.getCode(),"写入数据库失败");  
259 - } 209 +
  210 + platformService.update(parentPlatform);
260 } 211 }
261 212
262 /** 213 /**
@@ -279,12 +230,16 @@ public class PlatformController { @@ -279,12 +230,16 @@ public class PlatformController {
279 throw new ControllerException(ErrorCode.ERROR400); 230 throw new ControllerException(ErrorCode.ERROR400);
280 } 231 }
281 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId); 232 ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(serverGBId);
  233 + ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(serverGBId);
282 if (parentPlatform == null) { 234 if (parentPlatform == null) {
283 throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在"); 235 throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在");
284 } 236 }
  237 + if (parentPlatformCatch == null) {
  238 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台不存在");
  239 + }
285 // 发送离线消息,无论是否成功都删除缓存 240 // 发送离线消息,无论是否成功都删除缓存
286 try { 241 try {
287 - commanderForPlatform.unregister(parentPlatform, (event -> { 242 + commanderForPlatform.unregister(parentPlatform, parentPlatformCatch.getSipTransactionInfo(), (event -> {
288 // 清空redis缓存 243 // 清空redis缓存
289 redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId()); 244 redisCatchStorage.delPlatformCatchInfo(parentPlatform.getServerGBId());
290 redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId()); 245 redisCatchStorage.delPlatformKeepalive(parentPlatform.getServerGBId());
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
@@ -41,7 +41,7 @@ import java.util.UUID; @@ -41,7 +41,7 @@ import java.util.UUID;
41 * @author lin 41 * @author lin
42 */ 42 */
43 @Tag(name = "国标设备点播") 43 @Tag(name = "国标设备点播")
44 -@CrossOrigin 44 +
45 @RestController 45 @RestController
46 @RequestMapping("/api/play") 46 @RequestMapping("/api/play")
47 public class PlayController { 47 public class PlayController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
@@ -40,7 +40,7 @@ import java.util.UUID; @@ -40,7 +40,7 @@ import java.util.UUID;
40 * @author lin 40 * @author lin
41 */ 41 */
42 @Tag(name = "视频回放") 42 @Tag(name = "视频回放")
43 -@CrossOrigin 43 +
44 @RestController 44 @RestController
45 @RequestMapping("/api/playback") 45 @RequestMapping("/api/playback")
46 public class PlaybackController { 46 public class PlaybackController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
1 package com.genersoft.iot.vmp.vmanager.gb28181.ptz; 1 package com.genersoft.iot.vmp.vmanager.gb28181.ptz;
2 2
3 - 3 +
4 import com.genersoft.iot.vmp.conf.exception.ControllerException; 4 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  8 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  9 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
5 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 10 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
6 import io.swagger.v3.oas.annotations.Operation; 11 import io.swagger.v3.oas.annotations.Operation;
7 import io.swagger.v3.oas.annotations.Parameter; 12 import io.swagger.v3.oas.annotations.Parameter;
@@ -10,23 +15,16 @@ import org.slf4j.Logger; @@ -10,23 +15,16 @@ import org.slf4j.Logger;
10 import org.slf4j.LoggerFactory; 15 import org.slf4j.LoggerFactory;
11 import org.springframework.beans.factory.annotation.Autowired; 16 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.util.ObjectUtils; 17 import org.springframework.util.ObjectUtils;
13 -import org.springframework.util.StringUtils;  
14 import org.springframework.web.bind.annotation.*; 18 import org.springframework.web.bind.annotation.*;
15 import org.springframework.web.context.request.async.DeferredResult; 19 import org.springframework.web.context.request.async.DeferredResult;
16 20
17 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
18 -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;  
19 -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;  
20 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;  
21 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
22 -  
23 import javax.sip.InvalidArgumentException; 21 import javax.sip.InvalidArgumentException;
24 import javax.sip.SipException; 22 import javax.sip.SipException;
25 import java.text.ParseException; 23 import java.text.ParseException;
26 import java.util.UUID; 24 import java.util.UUID;
27 25
28 @Tag(name = "云台控制") 26 @Tag(name = "云台控制")
29 -@CrossOrigin 27 +
30 @RestController 28 @RestController
31 @RequestMapping("/api/ptz") 29 @RequestMapping("/api/ptz")
32 public class PtzController { 30 public class PtzController {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
@@ -3,40 +3,37 @@ package com.genersoft.iot.vmp.vmanager.gb28181.record; @@ -3,40 +3,37 @@ package com.genersoft.iot.vmp.vmanager.gb28181.record;
3 import com.genersoft.iot.vmp.common.StreamInfo; 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 import com.genersoft.iot.vmp.conf.exception.ControllerException; 4 import com.genersoft.iot.vmp.conf.exception.ControllerException;
5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; 5 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
  8 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
6 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  10 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
7 import com.genersoft.iot.vmp.service.IDeviceService; 11 import com.genersoft.iot.vmp.service.IDeviceService;
8 import com.genersoft.iot.vmp.service.IPlayService; 12 import com.genersoft.iot.vmp.service.IPlayService;
  13 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
9 import com.genersoft.iot.vmp.utils.DateUtil; 14 import com.genersoft.iot.vmp.utils.DateUtil;
10 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 15 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
11 import com.genersoft.iot.vmp.vmanager.bean.StreamContent; 16 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
12 import com.genersoft.iot.vmp.vmanager.bean.WVPResult; 17 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
13 -  
14 import io.swagger.v3.oas.annotations.Operation; 18 import io.swagger.v3.oas.annotations.Operation;
15 import io.swagger.v3.oas.annotations.Parameter; 19 import io.swagger.v3.oas.annotations.Parameter;
16 import io.swagger.v3.oas.annotations.tags.Tag; 20 import io.swagger.v3.oas.annotations.tags.Tag;
17 import org.slf4j.Logger; 21 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory; 22 import org.slf4j.LoggerFactory;
19 import org.springframework.beans.factory.annotation.Autowired; 23 import org.springframework.beans.factory.annotation.Autowired;
20 -import org.springframework.web.bind.annotation.CrossOrigin;  
21 import org.springframework.web.bind.annotation.GetMapping; 24 import org.springframework.web.bind.annotation.GetMapping;
22 import org.springframework.web.bind.annotation.PathVariable; 25 import org.springframework.web.bind.annotation.PathVariable;
23 import org.springframework.web.bind.annotation.RequestMapping; 26 import org.springframework.web.bind.annotation.RequestMapping;
24 import org.springframework.web.bind.annotation.RestController; 27 import org.springframework.web.bind.annotation.RestController;
25 import org.springframework.web.context.request.async.DeferredResult; 28 import org.springframework.web.context.request.async.DeferredResult;
26 29
27 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
28 -import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;  
29 -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;  
30 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;  
31 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
32 -  
33 import javax.sip.InvalidArgumentException; 30 import javax.sip.InvalidArgumentException;
34 import javax.sip.SipException; 31 import javax.sip.SipException;
35 import java.text.ParseException; 32 import java.text.ParseException;
36 import java.util.UUID; 33 import java.util.UUID;
37 34
38 @Tag(name = "国标录像") 35 @Tag(name = "国标录像")
39 -@CrossOrigin 36 +
40 @RestController 37 @RestController
41 @RequestMapping("/api/gb_record") 38 @RequestMapping("/api/gb_record")
42 public class GBRecordController { 39 public class GBRecordController {
@@ -74,10 +71,10 @@ public class GBRecordController { @@ -74,10 +71,10 @@ public class GBRecordController {
74 } 71 }
75 DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>(); 72 DeferredResult<WVPResult<RecordInfo>> result = new DeferredResult<>();
76 if (!DateUtil.verification(startTime, DateUtil.formatter)){ 73 if (!DateUtil.verification(startTime, DateUtil.formatter)){
77 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime error, format is " + DateUtil.PATTERN); 74 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN);
78 } 75 }
79 if (!DateUtil.verification(endTime, DateUtil.formatter)){ 76 if (!DateUtil.verification(endTime, DateUtil.formatter)){
80 - throw new ControllerException(ErrorCode.ERROR100.getCode(), "endTime error, format is " + DateUtil.PATTERN); 77 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "endTime格式为" + DateUtil.PATTERN);
81 } 78 }
82 79
83 Device device = storager.queryVideoDevice(deviceId); 80 Device device = storager.queryVideoDevice(deviceId);
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java
@@ -6,25 +6,18 @@ import com.genersoft.iot.vmp.service.ILogService; @@ -6,25 +6,18 @@ import com.genersoft.iot.vmp.service.ILogService;
6 import com.genersoft.iot.vmp.storager.dao.dto.LogDto; 6 import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
7 import com.genersoft.iot.vmp.utils.DateUtil; 7 import com.genersoft.iot.vmp.utils.DateUtil;
8 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 8 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
9 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
10 import com.github.pagehelper.PageInfo; 9 import com.github.pagehelper.PageInfo;
11 -  
12 import io.swagger.v3.oas.annotations.Operation; 10 import io.swagger.v3.oas.annotations.Operation;
13 import io.swagger.v3.oas.annotations.Parameter; 11 import io.swagger.v3.oas.annotations.Parameter;
14 import io.swagger.v3.oas.annotations.tags.Tag; 12 import io.swagger.v3.oas.annotations.tags.Tag;
15 import org.slf4j.Logger; 13 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory; 14 import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.annotation.Autowired; 15 import org.springframework.beans.factory.annotation.Autowired;
18 -import org.springframework.http.HttpStatus;  
19 -import org.springframework.http.ResponseEntity;  
20 import org.springframework.util.ObjectUtils; 16 import org.springframework.util.ObjectUtils;
21 -import org.springframework.util.StringUtils;  
22 import org.springframework.web.bind.annotation.*; 17 import org.springframework.web.bind.annotation.*;
23 18
24 -import java.text.ParseException;  
25 -  
26 @Tag(name = "日志管理") 19 @Tag(name = "日志管理")
27 -@CrossOrigin 20 +
28 @RestController 21 @RestController
29 @RequestMapping("/api/log") 22 @RequestMapping("/api/log")
30 public class LogController { 23 public class LogController {
@@ -67,18 +60,21 @@ public class LogController { @@ -67,18 +60,21 @@ public class LogController {
67 if (ObjectUtils.isEmpty(query)) { 60 if (ObjectUtils.isEmpty(query)) {
68 query = null; 61 query = null;
69 } 62 }
  63 +
  64 + if (!userSetting.getLogInDatebase()) {
  65 + logger.warn("自动记录日志功能已关闭,查询结果可能不完整。");
  66 + }
  67 +
70 if (ObjectUtils.isEmpty(startTime)) { 68 if (ObjectUtils.isEmpty(startTime)) {
71 startTime = null; 69 startTime = null;
  70 + }else if (!DateUtil.verification(startTime, DateUtil.formatter) ){
  71 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "startTime格式为" + DateUtil.PATTERN);
72 } 72 }
  73 +
73 if (ObjectUtils.isEmpty(endTime)) { 74 if (ObjectUtils.isEmpty(endTime)) {
74 endTime = null; 75 endTime = null;
75 - }  
76 - if (!userSetting.getLogInDatebase()) {  
77 - logger.warn("自动记录日志功能已关闭,查询结果可能不完整。");  
78 - }  
79 -  
80 - if (!DateUtil.verification(startTime, DateUtil.formatter) || !DateUtil.verification(endTime, DateUtil.formatter)){  
81 - throw new ControllerException(ErrorCode.ERROR400); 76 + }else if (!DateUtil.verification(endTime, DateUtil.formatter) ){
  77 + throw new ControllerException(ErrorCode.ERROR400.getCode(), "endTime格式为" + DateUtil.PATTERN);
82 } 78 }
83 79
84 return logService.getAll(page, count, query, type, startTime, endTime); 80 return logService.getAll(page, count, query, type, startTime, endTime);