Commit 22e1d92a9d8ae6aa257889f882722b8e48648abc

Authored by mk1990
Committed by GitHub
2 parents eef78c78 0dc1807f

Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0

Showing 26 changed files with 543 additions and 246 deletions
bootstrap.sh 0 → 100755
  1 +#!/bin/bash
  2 +
  3 +######################################################
  4 +# Copyright 2019 Pham Ngoc Hoai
  5 +#
  6 +# Licensed under the Apache License, Version 2.0 (the "License");
  7 +# you may not use this file except in compliance with the License.
  8 +# You may obtain a copy of the License at
  9 +#
  10 +# http://www.apache.org/licenses/LICENSE-2.0
  11 +#
  12 +# Unless required by applicable law or agreed to in writing, software
  13 +# distributed under the License is distributed on an "AS IS" BASIS,
  14 +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15 +# See the License for the specific language governing permissions and
  16 +# limitations under the License.
  17 +#
  18 +# Repo: https://github.com/tyrion9/spring-boot-startup-script
  19 +#
  20 +######### PARAM ######################################
  21 +
  22 +JAVA_OPT=-Xmx1024m
  23 +JARFILE=`ls -1r *.jar 2>/dev/null | head -n 1`
  24 +PID_FILE=pid.file
  25 +RUNNING=N
  26 +PWD=`pwd`
  27 +
  28 +######### DO NOT MODIFY ########
  29 +
  30 +if [ -f $PID_FILE ]; then
  31 + PID=`cat $PID_FILE`
  32 + if [ ! -z "$PID" ] && kill -0 $PID 2>/dev/null; then
  33 + RUNNING=Y
  34 + fi
  35 +fi
  36 +
  37 +start()
  38 +{
  39 + if [ $RUNNING == "Y" ]; then
  40 + echo "Application already started"
  41 + else
  42 + if [ -z "$JARFILE" ]
  43 + then
  44 + echo "ERROR: jar file not found"
  45 + else
  46 + nohup java $JAVA_OPT -Djava.security.egd=file:/dev/./urandom -jar $PWD/$JARFILE > nohup.out 2>&1 &
  47 + echo $! > $PID_FILE
  48 + echo "Application $JARFILE starting..."
  49 + tail -f nohup.out
  50 + fi
  51 + fi
  52 +}
  53 +
  54 +stop()
  55 +{
  56 + if [ $RUNNING == "Y" ]; then
  57 + kill -9 $PID
  58 + rm -f $PID_FILE
  59 + echo "Application stopped"
  60 + else
  61 + echo "Application not running"
  62 + fi
  63 +}
  64 +
  65 +restart()
  66 +{
  67 + stop
  68 + start
  69 +}
  70 +
  71 +case "$1" in
  72 +
  73 + 'start')
  74 + start
  75 + ;;
  76 +
  77 + 'stop')
  78 + stop
  79 + ;;
  80 +
  81 + 'restart')
  82 + restart
  83 + ;;
  84 +
  85 + *)
  86 + echo "Usage: $0 { start | stop | restart }"
  87 + exit 1
  88 + ;;
  89 +esac
  90 +exit 0
  91 +
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
1 package com.genersoft.iot.vmp.conf; 1 package com.genersoft.iot.vmp.conf;
2 2
3 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; 3 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
  4 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
4 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.context.annotation.Bean; 8 import org.springframework.context.annotation.Bean;
6 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 9 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@@ -18,6 +21,8 @@ import java.util.concurrent.ScheduledFuture; @@ -18,6 +21,8 @@ import java.util.concurrent.ScheduledFuture;
18 @Component 21 @Component
19 public class DynamicTask { 22 public class DynamicTask {
20 23
  24 + private Logger logger = LoggerFactory.getLogger(DynamicTask.class);
  25 +
21 @Autowired 26 @Autowired
22 private ThreadPoolTaskScheduler threadPoolTaskScheduler; 27 private ThreadPoolTaskScheduler threadPoolTaskScheduler;
23 28
@@ -26,7 +31,12 @@ public class DynamicTask { @@ -26,7 +31,12 @@ public class DynamicTask {
26 31
27 @Bean 32 @Bean
28 public ThreadPoolTaskScheduler threadPoolTaskScheduler() { 33 public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
29 - return new ThreadPoolTaskScheduler(); 34 + ThreadPoolTaskScheduler schedulerPool = new ThreadPoolTaskScheduler();
  35 + schedulerPool.setPoolSize(300);
  36 + schedulerPool.setWaitForTasksToCompleteOnShutdown(true);
  37 + schedulerPool.setAwaitTerminationSeconds(10);
  38 + return schedulerPool;
  39 +
30 } 40 }
31 41
32 /** 42 /**
@@ -37,11 +47,24 @@ public class DynamicTask { @@ -37,11 +47,24 @@ public class DynamicTask {
37 * @return 47 * @return
38 */ 48 */
39 public void startCron(String key, Runnable task, int cycleForCatalog) { 49 public void startCron(String key, Runnable task, int cycleForCatalog) {
40 - stop(key); 50 + ScheduledFuture future = futureMap.get(key);
  51 + if (future != null) {
  52 + if (future.isCancelled()) {
  53 + logger.info("任务【{}】已存在但是关闭状态!!!", key);
  54 + } else {
  55 + logger.info("任务【{}】已存在且已启动!!!", key);
  56 + return;
  57 + }
  58 + }
41 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 59 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔
42 - ScheduledFuture future = threadPoolTaskScheduler.scheduleWithFixedDelay(task, cycleForCatalog * 1000L);  
43 - futureMap.put(key, future);  
44 - runnableMap.put(key, task); 60 + future = threadPoolTaskScheduler.scheduleAtFixedRate(task, cycleForCatalog * 1000L);
  61 + if (future != null){
  62 + futureMap.put(key, future);
  63 + runnableMap.put(key, task);
  64 + logger.info("任务【{}】启动成功!!!", key);
  65 + }else {
  66 + logger.info("任务【{}】启动失败!!!", key);
  67 + }
45 } 68 }
46 69
47 /** 70 /**
@@ -54,9 +77,25 @@ public class DynamicTask { @@ -54,9 +77,25 @@ public class DynamicTask {
54 public void startDelay(String key, Runnable task, int delay) { 77 public void startDelay(String key, Runnable task, int delay) {
55 stop(key); 78 stop(key);
56 Date starTime = new Date(System.currentTimeMillis() + delay); 79 Date starTime = new Date(System.currentTimeMillis() + delay);
  80 +
  81 + ScheduledFuture future = futureMap.get(key);
  82 + if (future != null) {
  83 + if (future.isCancelled()) {
  84 + logger.info("任务【{}】已存在但是关闭状态!!!", key);
  85 + } else {
  86 + logger.info("任务【{}】已存在且已启动!!!", key);
  87 + return;
  88 + }
  89 + }
57 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 90 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔
58 - ScheduledFuture future = threadPoolTaskScheduler.schedule(task, starTime);  
59 - futureMap.put(key, future); 91 + future = threadPoolTaskScheduler.schedule(task, starTime);
  92 + if (future != null){
  93 + futureMap.put(key, future);
  94 + runnableMap.put(key, task);
  95 + logger.info("任务【{}】启动成功!!!", key);
  96 + }else {
  97 + logger.info("任务【{}】启动失败!!!", key);
  98 + }
60 } 99 }
61 100
62 public void stop(String key) { 101 public void stop(String key) {
@@ -78,4 +117,7 @@ public class DynamicTask { @@ -78,4 +117,7 @@ public class DynamicTask {
78 return futureMap.keySet(); 117 return futureMap.keySet();
79 } 118 }
80 119
  120 + public Runnable get(String key) {
  121 + return runnableMap.get(key);
  122 + }
81 } 123 }
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -48,6 +48,7 @@ public class SipLayer{ @@ -48,6 +48,7 @@ public class SipLayer{
48 properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP"); 48 properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
49 properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getMonitorIp()); 49 properties.setProperty("javax.sip.IP_ADDRESS", sipConfig.getMonitorIp());
50 properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true"); 50 properties.setProperty("gov.nist.javax.sip.LOG_MESSAGE_CONTENT", "true");
  51 + properties.setProperty("gov.nist.javax.sip.DELIVER_UNSOLICITED_NOTIFY", "true"); // 接收所有notify请求,即使没有订阅
51 /** 52 /**
52 * sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE = 53 * sip_server_log.log 和 sip_debug_log.log public static final int TRACE_NONE =
53 * 0; public static final int TRACE_MESSAGES = 16; public static final int 54 * 0; public static final int TRACE_MESSAGES = 16; public static final int
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
@@ -4,6 +4,7 @@ import java.util.Date; @@ -4,6 +4,7 @@ import java.util.Date;
4 import java.util.List; 4 import java.util.List;
5 5
6 public class CatalogData { 6 public class CatalogData {
  7 + private int sn; // 命令序列号
7 private int total; 8 private int total;
8 private List<DeviceChannel> channelList; 9 private List<DeviceChannel> channelList;
9 private Date lastTime; 10 private Date lastTime;
@@ -15,6 +16,15 @@ public class CatalogData { @@ -15,6 +16,15 @@ public class CatalogData {
15 } 16 }
16 private CatalogDataStatus status; 17 private CatalogDataStatus status;
17 18
  19 +
  20 + public int getSn() {
  21 + return sn;
  22 + }
  23 +
  24 + public void setSn(int sn) {
  25 + this.sn = sn;
  26 + }
  27 +
18 public int getTotal() { 28 public int getTotal() {
19 return total; 29 return total;
20 } 30 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
  3 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  4 +import com.genersoft.iot.vmp.conf.DynamicTask;
  5 +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
  6 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
  7 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  8 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  9 +import org.springframework.beans.factory.annotation.Autowired;
3 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
4 11
5 import java.util.ArrayList; 12 import java.util.ArrayList;
@@ -9,12 +16,32 @@ import java.util.concurrent.ConcurrentHashMap; @@ -9,12 +16,32 @@ import java.util.concurrent.ConcurrentHashMap;
9 @Component 16 @Component
10 public class SubscribeHolder { 17 public class SubscribeHolder {
11 18
  19 + @Autowired
  20 + private DynamicTask dynamicTask;
  21 +
  22 + @Autowired
  23 + private IRedisCatchStorage redisCatchStorage;
  24 +
  25 + @Autowired
  26 + private ISIPCommanderForPlatform sipCommanderForPlatform;
  27 +
  28 + @Autowired
  29 + private IVideoManagerStorage storager;
  30 +
  31 + private final String taskOverduePrefix = "subscribe_overdue_";
  32 +
12 private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>(); 33 private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>();
13 private static ConcurrentHashMap<String, SubscribeInfo> mobilePositionMap = new ConcurrentHashMap<>(); 34 private static ConcurrentHashMap<String, SubscribeInfo> mobilePositionMap = new ConcurrentHashMap<>();
14 35
15 36
16 public void putCatalogSubscribe(String platformId, SubscribeInfo subscribeInfo) { 37 public void putCatalogSubscribe(String platformId, SubscribeInfo subscribeInfo) {
17 catalogMap.put(platformId, subscribeInfo); 38 catalogMap.put(platformId, subscribeInfo);
  39 + // 添加订阅到期
  40 + String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId;
  41 + dynamicTask.stop(taskOverdueKey);
  42 + // 添加任务处理订阅过期
  43 + dynamicTask.startDelay(taskOverdueKey, () -> removeCatalogSubscribe(subscribeInfo.getId()),
  44 + subscribeInfo.getExpires() * 1000);
18 } 45 }
19 46
20 public SubscribeInfo getCatalogSubscribe(String platformId) { 47 public SubscribeInfo getCatalogSubscribe(String platformId) {
@@ -23,10 +50,24 @@ public class SubscribeHolder { @@ -23,10 +50,24 @@ public class SubscribeHolder {
23 50
24 public void removeCatalogSubscribe(String platformId) { 51 public void removeCatalogSubscribe(String platformId) {
25 catalogMap.remove(platformId); 52 catalogMap.remove(platformId);
  53 + String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId;
  54 + // 添加任务处理订阅过期
  55 + dynamicTask.stop(taskOverdueKey);
26 } 56 }
27 57
28 public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) { 58 public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) {
29 mobilePositionMap.put(platformId, subscribeInfo); 59 mobilePositionMap.put(platformId, subscribeInfo);
  60 + String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
  61 + // 添加任务处理GPS定时推送
  62 + dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, subscribeInfo.getSn(), key, this), subscribeInfo.getGpsInterval());
  63 + String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId;
  64 + dynamicTask.stop(taskOverdueKey);
  65 + // 添加任务处理订阅过期
  66 + dynamicTask.startDelay(taskOverdueKey, () -> {
  67 + System.out.println("订阅过期");
  68 + removeMobilePositionSubscribe(subscribeInfo.getId());
  69 + },
  70 + subscribeInfo.getExpires() * 1000);
30 } 71 }
31 72
32 public SubscribeInfo getMobilePositionSubscribe(String platformId) { 73 public SubscribeInfo getMobilePositionSubscribe(String platformId) {
@@ -35,6 +76,12 @@ public class SubscribeHolder { @@ -35,6 +76,12 @@ public class SubscribeHolder {
35 76
36 public void removeMobilePositionSubscribe(String platformId) { 77 public void removeMobilePositionSubscribe(String platformId) {
37 mobilePositionMap.remove(platformId); 78 mobilePositionMap.remove(platformId);
  79 + String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
  80 + // 结束任务处理GPS定时推送
  81 + dynamicTask.stop(key);
  82 + String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId;
  83 + // 添加任务处理订阅过期
  84 + dynamicTask.stop(taskOverdueKey);
38 } 85 }
39 86
40 public List<String> getAllCatalogSubscribePlatform() { 87 public List<String> getAllCatalogSubscribePlatform() {
@@ -48,7 +95,7 @@ public class SubscribeHolder { @@ -48,7 +95,7 @@ public class SubscribeHolder {
48 } 95 }
49 96
50 public void removeAllSubscribe(String platformId) { 97 public void removeAllSubscribe(String platformId) {
51 - mobilePositionMap.remove(platformId);  
52 - catalogMap.remove(platformId); 98 + removeMobilePositionSubscribe(platformId);
  99 + removeCatalogSubscribe(platformId);
53 } 100 }
54 } 101 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java
@@ -33,6 +33,14 @@ public class SubscribeInfo { @@ -33,6 +33,14 @@ public class SubscribeInfo {
33 private ServerTransaction transaction; 33 private ServerTransaction transaction;
34 private Dialog dialog; 34 private Dialog dialog;
35 35
  36 + /**
  37 + * 以下为可选字段
  38 + * @return
  39 + */
  40 + private String sn;
  41 + private int gpsInterval;
  42 +
  43 +
36 public String getId() { 44 public String getId() {
37 return id; 45 return id;
38 } 46 }
@@ -88,4 +96,20 @@ public class SubscribeInfo { @@ -88,4 +96,20 @@ public class SubscribeInfo {
88 public void setDialog(Dialog dialog) { 96 public void setDialog(Dialog dialog) {
89 this.dialog = dialog; 97 this.dialog = dialog;
90 } 98 }
  99 +
  100 + public String getSn() {
  101 + return sn;
  102 + }
  103 +
  104 + public void setSn(String sn) {
  105 + this.sn = sn;
  106 + }
  107 +
  108 + public int getGpsInterval() {
  109 + return gpsInterval;
  110 + }
  111 +
  112 + public void setGpsInterval(int gpsInterval) {
  113 + this.gpsInterval = gpsInterval;
  114 + }
91 } 115 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
@@ -54,6 +54,7 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; { @@ -54,6 +54,7 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; {
54 @Autowired 54 @Autowired
55 private SIPCommander cmder; 55 private SIPCommander cmder;
56 56
  57 +
57 private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 58 private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
58 59
59 @Override 60 @Override
@@ -76,7 +77,7 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; { @@ -76,7 +77,7 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; {
76 if (deviceInStore == null) { //第一次上线 77 if (deviceInStore == null) { //第一次上线
77 logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId()); 78 logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId());
78 cmder.deviceInfoQuery(device); 79 cmder.deviceInfoQuery(device);
79 - cmder.catalogQuery(device, null); 80 + deviceService.sync(device);
80 } 81 }
81 break; 82 break;
82 // 设备主动发送心跳触发的在线事件 83 // 设备主动发送心跳触发的在线事件
@@ -99,7 +100,10 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; { @@ -99,7 +100,10 @@ public class OnlineEventListener implements ApplicationListener&lt;OnlineEvent&gt; {
99 storager.updateDevice(device); 100 storager.updateDevice(device);
100 // 上线添加订阅 101 // 上线添加订阅
101 if (device.getSubscribeCycleForCatalog() > 0) { 102 if (device.getSubscribeCycleForCatalog() > 0) {
  103 + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
102 deviceService.addCatalogSubscribe(device); 104 deviceService.addCatalogSubscribe(device);
  105 + }
  106 + if (device.getSubscribeCycleForMobilePosition() > 0) {
103 deviceService.addMobilePositionSubscribe(device); 107 deviceService.addMobilePositionSubscribe(device);
104 } 108 }
105 } 109 }
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.gb28181.event.subscribe;  
2 -  
3 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
4 -import com.genersoft.iot.vmp.conf.DynamicTask;  
5 -import com.genersoft.iot.vmp.conf.RedisKeyExpirationEventMessageListener;  
6 -import com.genersoft.iot.vmp.conf.UserSetting;  
7 -import org.slf4j.Logger;  
8 -import org.slf4j.LoggerFactory;  
9 -import org.springframework.beans.factory.annotation.Autowired;  
10 -import org.springframework.data.redis.connection.Message;  
11 -import org.springframework.data.redis.listener.RedisMessageListenerContainer;  
12 -import org.springframework.stereotype.Component;  
13 -  
14 -/**  
15 - * 平台订阅到期事件  
16 - */  
17 -@Component  
18 -public class SubscribeListenerForPlatform extends RedisKeyExpirationEventMessageListener {  
19 -  
20 - private Logger logger = LoggerFactory.getLogger(SubscribeListenerForPlatform.class);  
21 -  
22 - @Autowired  
23 - private UserSetting userSetting;  
24 -  
25 - @Autowired  
26 - private DynamicTask dynamicTask;  
27 -  
28 - public SubscribeListenerForPlatform(RedisMessageListenerContainer listenerContainer, UserSetting userSetting) {  
29 - super(listenerContainer, userSetting);  
30 - }  
31 -  
32 -  
33 - /**  
34 - * 监听失效的key  
35 - * @param message  
36 - * @param pattern  
37 - */  
38 - @Override  
39 - public void onMessage(Message message, byte[] pattern) {  
40 - // 获取失效的key  
41 - String expiredKey = message.toString();  
42 - logger.debug(expiredKey);  
43 - // 订阅到期  
44 - String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_";  
45 - if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) {  
46 - // 取消定时任务  
47 - dynamicTask.stop(expiredKey);  
48 - }  
49 - }  
50 -}  
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
@@ -61,8 +61,6 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; { @@ -61,8 +61,6 @@ public class CatalogEventLister implements ApplicationListener&lt;CatalogEvent&gt; {
61 if (event.getPlatformId() != null) { 61 if (event.getPlatformId() != null) {
62 parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId()); 62 parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId());
63 if (parentPlatform != null && !parentPlatform.isStatus())return; 63 if (parentPlatform != null && !parentPlatform.isStatus())return;
64 - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_Catalog_" + event.getPlatformId();  
65 -// subscribe = redisCatchStorage.getSubscribe(key);  
66 subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); 64 subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId());
67 65
68 if (subscribe == null) { 66 if (subscribe == null) {
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
@@ -26,28 +26,35 @@ public class CatalogDataCatch { @@ -26,28 +26,35 @@ public class CatalogDataCatch {
26 @Autowired 26 @Autowired
27 private IVideoManagerStorage storager; 27 private IVideoManagerStorage storager;
28 28
29 - public void addReady(String key) {  
30 - CatalogData catalogData = data.get(key); 29 + public void addReady(Device device, int sn ) {
  30 + CatalogData catalogData = data.get(device.getDeviceId());
31 if (catalogData == null || catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) { 31 if (catalogData == null || catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) {
32 catalogData = new CatalogData(); 32 catalogData = new CatalogData();
33 catalogData.setChannelList(new ArrayList<>()); 33 catalogData.setChannelList(new ArrayList<>());
  34 + catalogData.setDevice(device);
  35 + catalogData.setSn(sn);
34 catalogData.setStatus(CatalogData.CatalogDataStatus.ready); 36 catalogData.setStatus(CatalogData.CatalogDataStatus.ready);
35 catalogData.setLastTime(new Date(System.currentTimeMillis())); 37 catalogData.setLastTime(new Date(System.currentTimeMillis()));
36 - data.put(key, catalogData); 38 + data.put(device.getDeviceId(), catalogData);
37 } 39 }
38 } 40 }
39 41
40 - public void put(String key, int total, Device device, List<DeviceChannel> deviceChannelList) {  
41 - CatalogData catalogData = data.get(key); 42 + public void put(String deviceId, int sn, int total, Device device, List<DeviceChannel> deviceChannelList) {
  43 + CatalogData catalogData = data.get(deviceId);
42 if (catalogData == null) { 44 if (catalogData == null) {
43 catalogData = new CatalogData(); 45 catalogData = new CatalogData();
  46 + catalogData.setSn(sn);
44 catalogData.setTotal(total); 47 catalogData.setTotal(total);
45 catalogData.setDevice(device); 48 catalogData.setDevice(device);
46 catalogData.setChannelList(new ArrayList<>()); 49 catalogData.setChannelList(new ArrayList<>());
47 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); 50 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
48 catalogData.setLastTime(new Date(System.currentTimeMillis())); 51 catalogData.setLastTime(new Date(System.currentTimeMillis()));
49 - data.put(key, catalogData); 52 + data.put(deviceId, catalogData);
50 }else { 53 }else {
  54 + // 同一个设备的通道同步请求只考虑一个,其他的直接忽略
  55 + if (catalogData.getSn() != sn) {
  56 + return;
  57 + }
51 catalogData.setTotal(total); 58 catalogData.setTotal(total);
52 catalogData.setDevice(device); 59 catalogData.setDevice(device);
53 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); 60 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
@@ -56,20 +63,20 @@ public class CatalogDataCatch { @@ -56,20 +63,20 @@ public class CatalogDataCatch {
56 } 63 }
57 } 64 }
58 65
59 - public List<DeviceChannel> get(String key) {  
60 - CatalogData catalogData = data.get(key); 66 + public List<DeviceChannel> get(String deviceId) {
  67 + CatalogData catalogData = data.get(deviceId);
61 if (catalogData == null) return null; 68 if (catalogData == null) return null;
62 return catalogData.getChannelList(); 69 return catalogData.getChannelList();
63 } 70 }
64 71
65 - public int getTotal(String key) {  
66 - CatalogData catalogData = data.get(key); 72 + public int getTotal(String deviceId) {
  73 + CatalogData catalogData = data.get(deviceId);
67 if (catalogData == null) return 0; 74 if (catalogData == null) return 0;
68 return catalogData.getTotal(); 75 return catalogData.getTotal();
69 } 76 }
70 77
71 - public SyncStatus getSyncStatus(String key) {  
72 - CatalogData catalogData = data.get(key); 78 + public SyncStatus getSyncStatus(String deviceId) {
  79 + CatalogData catalogData = data.get(deviceId);
73 if (catalogData == null) return null; 80 if (catalogData == null) return null;
74 SyncStatus syncStatus = new SyncStatus(); 81 SyncStatus syncStatus = new SyncStatus();
75 syncStatus.setCurrent(catalogData.getChannelList().size()); 82 syncStatus.setCurrent(catalogData.getChannelList().size());
@@ -78,10 +85,6 @@ public class CatalogDataCatch { @@ -78,10 +85,6 @@ public class CatalogDataCatch {
78 return syncStatus; 85 return syncStatus;
79 } 86 }
80 87
81 - public void del(String key) {  
82 - data.remove(key);  
83 - }  
84 -  
85 @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时 88 @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时
86 private void timerTask(){ 89 private void timerTask(){
87 Set<String> keys = data.keySet(); 90 Set<String> keys = data.keySet();
@@ -92,23 +95,30 @@ public class CatalogDataCatch { @@ -92,23 +95,30 @@ public class CatalogDataCatch {
92 Calendar calendarBefore30S = Calendar.getInstance(); 95 Calendar calendarBefore30S = Calendar.getInstance();
93 calendarBefore30S.setTime(new Date()); 96 calendarBefore30S.setTime(new Date());
94 calendarBefore30S.set(Calendar.SECOND, calendarBefore30S.get(Calendar.SECOND) - 30); 97 calendarBefore30S.set(Calendar.SECOND, calendarBefore30S.get(Calendar.SECOND) - 30);
95 - for (String key : keys) {  
96 - CatalogData catalogData = data.get(key);  
97 - if (catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 超过五秒收不到消息任务超时, 只更新这一部分数据  
98 - storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList());  
99 - String errorMsg = "更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条"; 98 + for (String deviceId : keys) {
  99 + CatalogData catalogData = data.get(deviceId);
  100 + if ( catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 超过五秒收不到消息任务超时, 只更新这一部分数据
  101 + if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) {
  102 + storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList());
  103 + if (catalogData.getTotal() != catalogData.getChannelList().size()) {
  104 + String errorMsg = "更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条";
  105 + catalogData.setErrorMsg(errorMsg);
  106 + }
  107 + }else if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.ready)) {
  108 + String errorMsg = "同步失败,等待回复超时";
  109 + catalogData.setErrorMsg(errorMsg);
  110 + }
100 catalogData.setStatus(CatalogData.CatalogDataStatus.end); 111 catalogData.setStatus(CatalogData.CatalogDataStatus.end);
101 - catalogData.setErrorMsg(errorMsg);  
102 } 112 }
103 - if (catalogData.getLastTime().before(calendarBefore30S.getTime())) { // 超过三十秒,如果标记为end则删除  
104 - data.remove(key); 113 + if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end) && catalogData.getLastTime().before(calendarBefore30S.getTime())) { // 超过三十秒,如果标记为end则删除
  114 + data.remove(deviceId);
105 } 115 }
106 } 116 }
107 } 117 }
108 118
109 119
110 - public void setChannelSyncEnd(String key, String errorMsg) {  
111 - CatalogData catalogData = data.get(key); 120 + public void setChannelSyncEnd(String deviceId, String errorMsg) {
  121 + CatalogData catalogData = data.get(deviceId);
112 if (catalogData == null)return; 122 if (catalogData == null)return;
113 catalogData.setStatus(CatalogData.CatalogDataStatus.end); 123 catalogData.setStatus(CatalogData.CatalogDataStatus.end);
114 catalogData.setErrorMsg(errorMsg); 124 catalogData.setErrorMsg(errorMsg);
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
1 package com.genersoft.iot.vmp.gb28181.task; 1 package com.genersoft.iot.vmp.gb28181.task;
2 2
  3 +import javax.sip.DialogState;
  4 +
3 public interface ISubscribeTask extends Runnable{ 5 public interface ISubscribeTask extends Runnable{
4 void stop(); 6 void stop();
  7 +
  8 + DialogState getDialogState();
5 } 9 }
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java
@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
6 import org.slf4j.Logger; 6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory; 7 import org.slf4j.LoggerFactory;
  8 +import org.springframework.scheduling.annotation.Async;
8 9
9 import javax.sip.Dialog; 10 import javax.sip.Dialog;
10 import javax.sip.DialogState; 11 import javax.sip.DialogState;
@@ -72,4 +73,10 @@ public class CatalogSubscribeTask implements ISubscribeTask { @@ -72,4 +73,10 @@ public class CatalogSubscribeTask implements ISubscribeTask {
72 }); 73 });
73 } 74 }
74 } 75 }
  76 +
  77 + @Override
  78 + public DialogState getDialogState() {
  79 + if (dialog == null) return null;
  80 + return dialog.getState();
  81 + }
75 } 82 }
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java
1 package com.genersoft.iot.vmp.gb28181.task.impl; 1 package com.genersoft.iot.vmp.gb28181.task.impl;
2 2
3 -import com.genersoft.iot.vmp.gb28181.bean.GbStream;  
4 -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;  
5 -import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;  
6 -import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; 3 +import com.genersoft.iot.vmp.gb28181.bean.*;
7 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; 4 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
8 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
9 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; 6 import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
10 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 7 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
11 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 8 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  9 +import org.slf4j.Logger;
  10 +import org.slf4j.LoggerFactory;
  11 +import org.springframework.scheduling.annotation.Async;
12 12
13 -import java.text.SimpleDateFormat; 13 +import javax.sip.DialogState;
14 import java.util.List; 14 import java.util.List;
15 15
16 /** 16 /**
@@ -18,20 +18,21 @@ import java.util.List; @@ -18,20 +18,21 @@ import java.util.List;
18 */ 18 */
19 public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { 19 public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
20 20
  21 + private Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeHandlerTask.class);
  22 +
21 private IRedisCatchStorage redisCatchStorage; 23 private IRedisCatchStorage redisCatchStorage;
22 private IVideoManagerStorage storager; 24 private IVideoManagerStorage storager;
23 private ISIPCommanderForPlatform sipCommanderForPlatform; 25 private ISIPCommanderForPlatform sipCommanderForPlatform;
24 private SubscribeHolder subscribeHolder; 26 private SubscribeHolder subscribeHolder;
25 - private String platformId; 27 + private ParentPlatform platform;
26 private String sn; 28 private String sn;
27 private String key; 29 private String key;
28 30
29 - private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
30 -  
31 public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) { 31 public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) {
  32 + System.out.println("MobilePositionSubscribeHandlerTask 初始化");
32 this.redisCatchStorage = redisCatchStorage; 33 this.redisCatchStorage = redisCatchStorage;
33 this.storager = storager; 34 this.storager = storager;
34 - this.platformId = platformId; 35 + this.platform = storager.queryParentPlatByServerGBId(platformId);
35 this.sn = sn; 36 this.sn = sn;
36 this.key = key; 37 this.key = key;
37 this.sipCommanderForPlatform = sipCommanderForPlatform; 38 this.sipCommanderForPlatform = sipCommanderForPlatform;
@@ -41,30 +42,31 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { @@ -41,30 +42,31 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
41 @Override 42 @Override
42 public void run() { 43 public void run() {
43 44
44 - SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platformId);  
45 - 45 + if (platform == null) return;
  46 + SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId());
46 if (subscribe != null) { 47 if (subscribe != null) {
47 - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(platformId);  
48 - if (parentPlatform == null || parentPlatform.isStatus()) {  
49 - // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持  
50 - List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platformId);  
51 - if (gbStreams.size() > 0) {  
52 - for (GbStream gbStream : gbStreams) {  
53 - String gbId = gbStream.getGbId();  
54 - GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);  
55 - if (gpsMsgInfo != null) {  
56 - // 发送GPS消息  
57 - sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);  
58 - }else {  
59 - // 没有在redis找到新的消息就使用数据库的消息  
60 - gpsMsgInfo = new GPSMsgInfo();  
61 - gpsMsgInfo.setId(gbId);  
62 - gpsMsgInfo.setLat(gbStream.getLongitude());  
63 - gpsMsgInfo.setLng(gbStream.getLongitude());  
64 - // 发送GPS消息  
65 - sipCommanderForPlatform.sendNotifyMobilePosition(parentPlatform, gpsMsgInfo, subscribe);  
66 - } 48 +
  49 +// if (!parentPlatform.isStatus()) {
  50 +// logger.info("发送订阅时发现平台已经离线:{}", platformId);
  51 +// return;
  52 +// }
  53 + // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持
  54 + List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId());
  55 + if (gbStreams.size() == 0) {
  56 + logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId());
  57 + return;
  58 + }
  59 + for (GbStream gbStream : gbStreams) {
  60 + String gbId = gbStream.getGbId();
  61 + GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId);
  62 + if (gpsMsgInfo != null) { // 无最新位置不发送
  63 + logger.info("无最新位置不发送");
  64 + // 经纬度都为0不发送
  65 + if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) {
  66 + continue;
67 } 67 }
  68 + // 发送GPS消息
  69 + sipCommanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, subscribe);
68 } 70 }
69 } 71 }
70 } 72 }
@@ -74,4 +76,9 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { @@ -74,4 +76,9 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask {
74 public void stop() { 76 public void stop() {
75 77
76 } 78 }
  79 +
  80 + @Override
  81 + public DialogState getDialogState() {
  82 + return null;
  83 + }
77 } 84 }
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java
@@ -6,10 +6,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; @@ -6,10 +6,13 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
6 import org.dom4j.Element; 6 import org.dom4j.Element;
7 import org.slf4j.Logger; 7 import org.slf4j.Logger;
8 import org.slf4j.LoggerFactory; 8 import org.slf4j.LoggerFactory;
  9 +import org.springframework.scheduling.annotation.Async;
9 10
10 import javax.sip.Dialog; 11 import javax.sip.Dialog;
11 import javax.sip.DialogState; 12 import javax.sip.DialogState;
12 import javax.sip.ResponseEvent; 13 import javax.sip.ResponseEvent;
  14 +import java.util.Timer;
  15 +import java.util.TimerTask;
13 16
14 /** 17 /**
15 * 移动位置订阅的定时更新 18 * 移动位置订阅的定时更新
@@ -20,6 +23,8 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { @@ -20,6 +23,8 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
20 private ISIPCommander sipCommander; 23 private ISIPCommander sipCommander;
21 private Dialog dialog; 24 private Dialog dialog;
22 25
  26 + private Timer timer ;
  27 +
23 public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) { 28 public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) {
24 this.device = device; 29 this.device = device;
25 this.sipCommander = sipCommander; 30 this.sipCommander = sipCommander;
@@ -27,10 +32,14 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { @@ -27,10 +32,14 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
27 32
28 @Override 33 @Override
29 public void run() { 34 public void run() {
  35 + if (timer != null ) {
  36 + timer.cancel();
  37 + timer = null;
  38 + }
30 sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { 39 sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> {
31 - if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {  
32 - dialog = eventResult.dialog;  
33 - } 40 +// if (eventResult.dialog != null || eventResult.dialog.getState().equals(DialogState.CONFIRMED)) {
  41 +// dialog = eventResult.dialog;
  42 +// }
34 ResponseEvent event = (ResponseEvent) eventResult.event; 43 ResponseEvent event = (ResponseEvent) eventResult.event;
35 if (event.getResponse().getRawContent() != null) { 44 if (event.getResponse().getRawContent() != null) {
36 // 成功 45 // 成功
@@ -43,6 +52,13 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { @@ -43,6 +52,13 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
43 dialog = null; 52 dialog = null;
44 // 失败 53 // 失败
45 logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg); 54 logger.warn("[移动位置订阅]失败,信令发送失败: {}-{} ", device.getDeviceId(), eventResult.msg);
  55 + timer = new Timer();
  56 + timer.schedule(new TimerTask() {
  57 + @Override
  58 + public void run() {
  59 + MobilePositionSubscribeTask.this.run();
  60 + }
  61 + }, 2000);
46 }); 62 });
47 63
48 } 64 }
@@ -56,6 +72,10 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { @@ -56,6 +72,10 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
56 * COMPLETED-> Completed Dialog状态-已完成 72 * COMPLETED-> Completed Dialog状态-已完成
57 * TERMINATED-> Terminated Dialog状态-终止 73 * TERMINATED-> Terminated Dialog状态-终止
58 */ 74 */
  75 + if (timer != null ) {
  76 + timer.cancel();
  77 + timer = null;
  78 + }
59 if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) { 79 if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) {
60 logger.info("取消移动订阅时dialog状态为{}", dialog.getState()); 80 logger.info("取消移动订阅时dialog状态为{}", dialog.getState());
61 device.setSubscribeCycleForMobilePosition(0); 81 device.setSubscribeCycleForMobilePosition(0);
@@ -74,4 +94,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { @@ -74,4 +94,9 @@ public class MobilePositionSubscribeTask implements ISubscribeTask {
74 }); 94 });
75 } 95 }
76 } 96 }
  97 + @Override
  98 + public DialogState getDialogState() {
  99 + if (dialog == null) return null;
  100 + return dialog.getState();
  101 + }
77 } 102 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
@@ -250,7 +250,7 @@ public interface ISIPCommander { @@ -250,7 +250,7 @@ public interface ISIPCommander {
250 * 250 *
251 * @param device 视频设备 251 * @param device 视频设备
252 */ 252 */
253 - boolean catalogQuery(Device device, SipSubscribe.Event errorEvent); 253 + boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent);
254 254
255 /** 255 /**
256 * 查询录像信息 256 * 查询录像信息
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -1208,14 +1208,14 @@ public class SIPCommander implements ISIPCommander { @@ -1208,14 +1208,14 @@ public class SIPCommander implements ISIPCommander {
1208 * @param device 视频设备 1208 * @param device 视频设备
1209 */ 1209 */
1210 @Override 1210 @Override
1211 - public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) { 1211 + public boolean catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) {
1212 try { 1212 try {
1213 StringBuffer catalogXml = new StringBuffer(200); 1213 StringBuffer catalogXml = new StringBuffer(200);
1214 String charset = device.getCharset(); 1214 String charset = device.getCharset();
1215 catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n"); 1215 catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
1216 catalogXml.append("<Query>\r\n"); 1216 catalogXml.append("<Query>\r\n");
1217 catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); 1217 catalogXml.append("<CmdType>Catalog</CmdType>\r\n");
1218 - catalogXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n"); 1218 + catalogXml.append("<SN>" + sn + "</SN>\r\n");
1219 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); 1219 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1220 catalogXml.append("</Query>\r\n"); 1220 catalogXml.append("</Query>\r\n");
1221 1221
@@ -1566,17 +1566,28 @@ public class SIPCommander implements ISIPCommander { @@ -1566,17 +1566,28 @@ public class SIPCommander implements ISIPCommander {
1566 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); 1566 cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
1567 cmdXml.append("</Query>\r\n"); 1567 cmdXml.append("</Query>\r\n");
1568 1568
1569 - String tm = Long.toString(System.currentTimeMillis());  
1570 1569
1571 - CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()  
1572 - : udpSipProvider.getNewCallId(); 1570 + Request request;
  1571 + if (dialog != null) {
  1572 + logger.info("发送目录订阅消息时 dialog的状态为: {}", dialog.getState());
  1573 + request = dialog.createRequest(Request.SUBSCRIBE);
  1574 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  1575 + request.setContent(cmdXml.toString(), contentTypeHeader);
  1576 + ExpiresHeader expireHeader = sipFactory.createHeaderFactory().createExpiresHeader(device.getSubscribeCycleForMobilePosition());
  1577 + request.addHeader(expireHeader);
  1578 + }else {
  1579 + String tm = Long.toString(System.currentTimeMillis());
1573 1580
1574 - // 有效时间默认为60秒以上  
1575 - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,  
1576 - "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,  
1577 - callIdHeader);  
1578 - transmitRequest(device, request, errorEvent, okEvent); 1581 + CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
  1582 + : udpSipProvider.getNewCallId();
  1583 +
  1584 + // 有效时间默认为60秒以上
  1585 + request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm,
  1586 + "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "Catalog" ,
  1587 + callIdHeader);
1579 1588
  1589 + }
  1590 + transmitRequest(device, request, errorEvent, okEvent);
1580 return true; 1591 return true;
1581 1592
1582 } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { 1593 } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
@@ -385,7 +385,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -385,7 +385,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
385 if (parentPlatform == null) { 385 if (parentPlatform == null) {
386 return false; 386 return false;
387 } 387 }
388 - 388 + logger.info("[发送 移动位置订阅] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat());
389 try { 389 try {
390 String characterSet = parentPlatform.getCharacterSet(); 390 String characterSet = parentPlatform.getCharacterSet();
391 StringBuffer deviceStatusXml = new StringBuffer(600); 391 StringBuffer deviceStatusXml = new StringBuffer(600);
@@ -405,7 +405,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -405,7 +405,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
405 CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() 405 CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
406 : udpSipProvider.getNewCallId(); 406 : udpSipProvider.getNewCallId();
407 callIdHeader.setCallId(subscribeInfo.getCallId()); 407 callIdHeader.setCallId(subscribeInfo.getCallId());
408 - logger.info("[发送Notify-MobilePosition] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat()); 408 +
409 sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { 409 sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> {
410 logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); 410 logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg);
411 }, null); 411 }, null);
@@ -459,7 +459,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { @@ -459,7 +459,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
459 // 设置编码, 防止中文乱码 459 // 设置编码, 防止中文乱码
460 messageFactory.setDefaultContentEncodingCharset(characterSet); 460 messageFactory.setDefaultContentEncodingCharset(characterSet);
461 Dialog dialog = subscribeInfo.getDialog(); 461 Dialog dialog = subscribeInfo.getDialog();
462 - if (dialog == null) return; 462 + if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) return;
463 SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY); 463 SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY);
464 ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); 464 ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
465 notifyRequest.setContent(catalogXmlContent, contentTypeHeader); 465 notifyRequest.setContent(catalogXmlContent, contentTypeHeader);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
@@ -146,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -146,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
146 } else { 146 } else {
147 mobilePosition.setAltitude(0.0); 147 mobilePosition.setAltitude(0.0);
148 } 148 }
149 - logger.info("[收到Notify-MobilePosition]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(), 149 + logger.info("[收到 移动位置订阅]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(),
150 mobilePosition.getLongitude(), mobilePosition.getLatitude()); 150 mobilePosition.getLongitude(), mobilePosition.getLatitude());
151 mobilePosition.setReportSource("Mobile Position"); 151 mobilePosition.setReportSource("Mobile Position");
152 BaiduPoint bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude())); 152 BaiduPoint bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
@@ -281,7 +281,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements @@ -281,7 +281,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
281 Element eventElement = itemDevice.element("Event"); 281 Element eventElement = itemDevice.element("Event");
282 DeviceChannel channel = XmlUtil.channelContentHander(itemDevice); 282 DeviceChannel channel = XmlUtil.channelContentHander(itemDevice);
283 channel.setDeviceId(device.getDeviceId()); 283 channel.setDeviceId(device.getDeviceId());
284 - logger.info("[收到Notify-Catalog]:{}/{}", device.getDeviceId(), channel.getChannelId()); 284 + logger.info("[收到 目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId());
285 switch (eventElement.getText().toUpperCase()) { 285 switch (eventElement.getText().toUpperCase()) {
286 case CatalogEvent.ON: // 上线 286 case CatalogEvent.ON: // 上线
287 logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); 287 logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId());
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
@@ -149,8 +149,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -149,8 +149,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
149 subscribeInfo.setDialog(dialog); 149 subscribeInfo.setDialog(dialog);
150 } 150 }
151 String sn = XmlUtil.getText(rootElement, "SN"); 151 String sn = XmlUtil.getText(rootElement, "SN");
152 - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_MobilePosition_" + platformId;  
153 - logger.info("[notify-MobilePosition]: {}", platformId); 152 + logger.info("[回复 移动位置订阅]: {}", platformId);
154 StringBuilder resultXml = new StringBuilder(200); 153 StringBuilder resultXml = new StringBuilder(200);
155 resultXml.append("<?xml version=\"1.0\" ?>\r\n") 154 resultXml.append("<?xml version=\"1.0\" ?>\r\n")
156 .append("<Response>\r\n") 155 .append("<Response>\r\n")
@@ -161,14 +160,25 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -161,14 +160,25 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
161 .append("</Response>\r\n"); 160 .append("</Response>\r\n");
162 161
163 if (subscribeInfo.getExpires() > 0) { 162 if (subscribeInfo.getExpires() > 0) {
164 - if (subscribeHolder.getMobilePositionSubscribe(platformId) != null) {  
165 - dynamicTask.stop(key);  
166 - }  
167 String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔 163 String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔
168 - dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(redisCatchStorage, sipCommanderForPlatform, storager, platformId, sn, key, subscribeHolder), Integer.parseInt(interval) -1 ); 164 + if (interval == null) {
  165 + subscribeInfo.setGpsInterval(5);
  166 + }else {
  167 + subscribeInfo.setGpsInterval(Integer.parseInt(interval));
  168 + }
  169 +
  170 + subscribeInfo.setSn(sn);
169 subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo); 171 subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
  172 +// if (subscribeHolder.getMobilePositionSubscribe(platformId) == null ) {
  173 +// subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
  174 +// }else {
  175 +// if (subscribeHolder.getMobilePositionSubscribe(platformId).getDialog() != null
  176 +// && subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState() != null
  177 +// && !subscribeHolder.getMobilePositionSubscribe(platformId).getDialog().getState().equals(DialogState.CONFIRMED)) {
  178 +// subscribeHolder.putMobilePositionSubscribe(platformId, subscribeInfo);
  179 +// }
  180 +// }
170 }else if (subscribeInfo.getExpires() == 0) { 181 }else if (subscribeInfo.getExpires() == 0) {
171 - dynamicTask.stop(key);  
172 subscribeHolder.removeMobilePositionSubscribe(platformId); 182 subscribeHolder.removeMobilePositionSubscribe(platformId);
173 } 183 }
174 184
@@ -202,8 +212,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme @@ -202,8 +212,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme
202 subscribeInfo.setDialog(dialog); 212 subscribeInfo.setDialog(dialog);
203 } 213 }
204 String sn = XmlUtil.getText(rootElement, "SN"); 214 String sn = XmlUtil.getText(rootElement, "SN");
205 - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_Catalog_" + platformId;  
206 - logger.info("[notify-Catalog]: {}", platformId); 215 + logger.info("[回复 目录订阅]: {}/{}", platformId, deviceID);
207 StringBuilder resultXml = new StringBuilder(200); 216 StringBuilder resultXml = new StringBuilder(200);
208 resultXml.append("<?xml version=\"1.0\" ?>\r\n") 217 resultXml.append("<?xml version=\"1.0\" ?>\r\n")
209 .append("<Response>\r\n") 218 .append("<Response>\r\n")
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
@@ -86,23 +86,17 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @@ -86,23 +86,17 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
86 rootElement = getRootElement(evt, device.getCharset()); 86 rootElement = getRootElement(evt, device.getCharset());
87 Element deviceListElement = rootElement.element("DeviceList"); 87 Element deviceListElement = rootElement.element("DeviceList");
88 Element sumNumElement = rootElement.element("SumNum"); 88 Element sumNumElement = rootElement.element("SumNum");
89 - if (sumNumElement == null || deviceListElement == null) { 89 + Element snElement = rootElement.element("SN");
  90 + if (snElement == null || sumNumElement == null || deviceListElement == null) {
90 responseAck(evt, Response.BAD_REQUEST, "xml error"); 91 responseAck(evt, Response.BAD_REQUEST, "xml error");
91 return; 92 return;
92 } 93 }
93 int sumNum = Integer.parseInt(sumNumElement.getText()); 94 int sumNum = Integer.parseInt(sumNumElement.getText());
  95 +
94 if (sumNum == 0) { 96 if (sumNum == 0) {
95 // 数据已经完整接收 97 // 数据已经完整接收
96 storager.cleanChannelsForDevice(device.getDeviceId()); 98 storager.cleanChannelsForDevice(device.getDeviceId());
97 - RequestMessage msg = new RequestMessage();  
98 - msg.setKey(key);  
99 - WVPResult<Object> result = new WVPResult<>();  
100 - result.setCode(0);  
101 - result.setData(device);  
102 - msg.setData(result);  
103 - result.setMsg("更新成功,共0条");  
104 - deferredResultHolder.invokeAllResult(msg);  
105 - catalogDataCatch.del(key); 99 + catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), null);
106 }else { 100 }else {
107 Iterator<Element> deviceListIterator = deviceListElement.elementIterator(); 101 Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
108 if (deviceListIterator != null) { 102 if (deviceListIterator != null) {
@@ -123,31 +117,22 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @@ -123,31 +117,22 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
123 117
124 channelList.add(deviceChannel); 118 channelList.add(deviceChannel);
125 } 119 }
  120 + int sn = Integer.parseInt(snElement.getText());
126 logger.info("收到来自设备【{}】的通道: {}个,{}/{}", device.getDeviceId(), channelList.size(), catalogDataCatch.get(key) == null ? 0 :catalogDataCatch.get(key).size(), sumNum); 121 logger.info("收到来自设备【{}】的通道: {}个,{}/{}", device.getDeviceId(), channelList.size(), catalogDataCatch.get(key) == null ? 0 :catalogDataCatch.get(key).size(), sumNum);
127 - catalogDataCatch.put(key, sumNum, device, channelList);  
128 - if (catalogDataCatch.get(key).size() == sumNum) { 122 + catalogDataCatch.put(device.getDeviceId(), sn, sumNum, device, channelList);
  123 + if (catalogDataCatch.get(device.getDeviceId()).size() == sumNum) {
129 // 数据已经完整接收 124 // 数据已经完整接收
130 - boolean resetChannelsResult = storager.resetChannels(device.getDeviceId(), catalogDataCatch.get(key));  
131 - RequestMessage msg = new RequestMessage();  
132 - msg.setKey(key);  
133 - WVPResult<Object> result = new WVPResult<>();  
134 - result.setCode(0);  
135 - result.setData(device);  
136 - if (resetChannelsResult || sumNum ==0) {  
137 - result.setMsg("更新成功,共" + sumNum + "条,已更新" + catalogDataCatch.get(key).size() + "条"); 125 + boolean resetChannelsResult = storager.resetChannels(device.getDeviceId(), catalogDataCatch.get(device.getDeviceId()));
  126 + if (!resetChannelsResult) {
  127 + String errorMsg = "接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(device.getDeviceId()).size() + "条";
  128 + catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), errorMsg);
138 }else { 129 }else {
139 - result.setMsg("接收成功,写入失败,共" + sumNum + "条,已接收" + catalogDataCatch.get(key).size() + "条"); 130 + catalogDataCatch.setChannelSyncEnd(device.getDeviceId(), null);
140 } 131 }
141 - msg.setData(result);  
142 - deferredResultHolder.invokeAllResult(msg);  
143 - catalogDataCatch.del(key);  
144 } 132 }
145 } 133 }
146 // 回复200 OK 134 // 回复200 OK
147 responseAck(evt, Response.OK); 135 responseAck(evt, Response.OK);
148 - if (offLineDetector.isOnline(device.getDeviceId())) {  
149 - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);  
150 - }  
151 } 136 }
152 } catch (DocumentException e) { 137 } catch (DocumentException e) {
153 e.printStackTrace(); 138 e.printStackTrace();
@@ -231,21 +216,18 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp @@ -231,21 +216,18 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
231 } 216 }
232 217
233 public SyncStatus getChannelSyncProgress(String deviceId) { 218 public SyncStatus getChannelSyncProgress(String deviceId) {
234 - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;  
235 - if (catalogDataCatch.get(key) == null) { 219 + if (catalogDataCatch.get(deviceId) == null) {
236 return null; 220 return null;
237 }else { 221 }else {
238 - return catalogDataCatch.getSyncStatus(key); 222 + return catalogDataCatch.getSyncStatus(deviceId);
239 } 223 }
240 } 224 }
241 225
242 - public void setChannelSyncReady(String deviceId) {  
243 - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;  
244 - catalogDataCatch.addReady(key); 226 + public void setChannelSyncReady(Device device, int sn) {
  227 + catalogDataCatch.addReady(device, sn);
245 } 228 }
246 229
247 public void setChannelSyncEnd(String deviceId, String errorMsg) { 230 public void setChannelSyncEnd(String deviceId, String errorMsg) {
248 - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId;  
249 - catalogDataCatch.setChannelSyncEnd(key, errorMsg); 231 + catalogDataCatch.setChannelSyncEnd(deviceId, errorMsg);
250 } 232 }
251 } 233 }
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
@@ -44,15 +44,8 @@ public interface IDeviceService { @@ -44,15 +44,8 @@ public interface IDeviceService {
44 SyncStatus getChannelSyncStatus(String deviceId); 44 SyncStatus getChannelSyncStatus(String deviceId);
45 45
46 /** 46 /**
47 - * 设置通道同步状态  
48 - * @param deviceId 设备ID  
49 - */  
50 - void setChannelSyncReady(String deviceId);  
51 -  
52 - /**  
53 - * 设置同步结束  
54 - * @param deviceId 设备ID  
55 - * @param errorMsg 错误信息 47 + * 通道同步
  48 + * @param device
56 */ 49 */
57 - void setChannelSyncEnd(String deviceId, String errorMsg); 50 + void sync(Device device);
58 } 51 }
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -14,6 +14,8 @@ import org.slf4j.LoggerFactory; @@ -14,6 +14,8 @@ import org.slf4j.LoggerFactory;
14 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.stereotype.Service; 15 import org.springframework.stereotype.Service;
16 16
  17 +import javax.sip.DialogState;
  18 +
17 /** 19 /**
18 * 设备业务(目录订阅) 20 * 设备业务(目录订阅)
19 */ 21 */
@@ -39,19 +41,17 @@ public class DeviceServiceImpl implements IDeviceService { @@ -39,19 +41,17 @@ public class DeviceServiceImpl implements IDeviceService {
39 if (device == null || device.getSubscribeCycleForCatalog() < 0) { 41 if (device == null || device.getSubscribeCycleForCatalog() < 0) {
40 return false; 42 return false;
41 } 43 }
42 - if (dynamicTask.contains(device.getDeviceId() + "catalog")) {  
43 - // 存在则停止现有的,开启新的  
44 - dynamicTask.stop(device.getDeviceId() + "catalog"); 44 + CatalogSubscribeTask task = (CatalogSubscribeTask)dynamicTask.get(device.getDeviceId() + "catalog");
  45 + if (task != null && task.getDialogState() != null && task.getDialogState().equals(DialogState.CONFIRMED)) { // 已存在不需要再次添加
  46 + return true;
45 } 47 }
46 logger.info("[添加目录订阅] 设备{}", device.getDeviceId()); 48 logger.info("[添加目录订阅] 设备{}", device.getDeviceId());
47 // 添加目录订阅 49 // 添加目录订阅
48 CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); 50 CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander);
49 - catalogSubscribeTask.run();  
50 // 提前开始刷新订阅 51 // 提前开始刷新订阅
51 - int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); 52 + int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30);
52 // 设置最小值为30 53 // 设置最小值为30
53 - subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30);  
54 - dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog); 54 + dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog -1);
55 return true; 55 return true;
56 } 56 }
57 57
@@ -70,18 +70,16 @@ public class DeviceServiceImpl implements IDeviceService { @@ -70,18 +70,16 @@ public class DeviceServiceImpl implements IDeviceService {
70 if (device == null || device.getSubscribeCycleForMobilePosition() < 0) { 70 if (device == null || device.getSubscribeCycleForMobilePosition() < 0) {
71 return false; 71 return false;
72 } 72 }
73 - if (dynamicTask.contains(device.getDeviceId() + "mobile_position")) {  
74 - // 存在则停止现有的,开启新的  
75 - dynamicTask.stop(device.getDeviceId() + "mobile_position");  
76 - }  
77 logger.info("[添加移动位置订阅] 设备{}", device.getDeviceId()); 73 logger.info("[添加移动位置订阅] 设备{}", device.getDeviceId());
  74 + MobilePositionSubscribeTask task = (MobilePositionSubscribeTask)dynamicTask.get(device.getDeviceId() + "mobile_position");
  75 + if (task != null && task.getDialogState() != null && task.getDialogState().equals(DialogState.CONFIRMED)) { // 已存在不需要再次添加
  76 + return true;
  77 + }
78 // 添加目录订阅 78 // 添加目录订阅
79 MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander); 79 MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander);
80 - mobilePositionSubscribeTask.run();  
81 // 提前开始刷新订阅 80 // 提前开始刷新订阅
82 - int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog();  
83 // 设置最小值为30 81 // 设置最小值为30
84 - subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); 82 + int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30);
85 dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 ); 83 dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 );
86 return true; 84 return true;
87 } 85 }
@@ -102,12 +100,16 @@ public class DeviceServiceImpl implements IDeviceService { @@ -102,12 +100,16 @@ public class DeviceServiceImpl implements IDeviceService {
102 } 100 }
103 101
104 @Override 102 @Override
105 - public void setChannelSyncReady(String deviceId) {  
106 - catalogResponseMessageHandler.setChannelSyncReady(deviceId);  
107 - }  
108 -  
109 - @Override  
110 - public void setChannelSyncEnd(String deviceId, String errorMsg) {  
111 - catalogResponseMessageHandler.setChannelSyncEnd(deviceId, errorMsg); 103 + public void sync(Device device) {
  104 + if (catalogResponseMessageHandler.getChannelSyncProgress(device.getDeviceId()) != null) {
  105 + logger.info("开启同步时发现同步已经存在");
  106 + return;
  107 + }
  108 + int sn = (int)((Math.random()*9+1)*100000);
  109 + catalogResponseMessageHandler.setChannelSyncReady(device, sn);
  110 + sipCommander.catalogQuery(device, sn, event -> {
  111 + String errorMsg = String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg);
  112 + catalogResponseMessageHandler.setChannelSyncEnd(device.getDeviceId(), errorMsg);
  113 + });
112 } 114 }
113 } 115 }
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
@@ -238,12 +238,15 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -238,12 +238,15 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
238 238
239 @Override 239 @Override
240 public boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList) { 240 public boolean resetChannels(String deviceId, List<DeviceChannel> deviceChannelList) {
  241 + if (deviceChannelList == null) {
  242 + return false;
  243 + }
241 TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); 244 TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
242 // 数据去重 245 // 数据去重
243 List<DeviceChannel> channels = new ArrayList<>(); 246 List<DeviceChannel> channels = new ArrayList<>();
244 StringBuilder stringBuilder = new StringBuilder(); 247 StringBuilder stringBuilder = new StringBuilder();
245 Map<String, Integer> subContMap = new HashMap<>(); 248 Map<String, Integer> subContMap = new HashMap<>();
246 - if (deviceChannelList.size() > 1) { 249 + if (deviceChannelList != null && deviceChannelList.size() > 1) {
247 // 数据去重 250 // 数据去重
248 Set<String> gbIdSet = new HashSet<>(); 251 Set<String> gbIdSet = new HashSet<>();
249 for (DeviceChannel deviceChannel : deviceChannelList) { 252 for (DeviceChannel deviceChannel : deviceChannelList) {
@@ -300,6 +303,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -300,6 +303,7 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
300 dataSourceTransactionManager.commit(transactionStatus); //手动提交 303 dataSourceTransactionManager.commit(transactionStatus); //手动提交
301 return true; 304 return true;
302 }catch (Exception e) { 305 }catch (Exception e) {
  306 + e.printStackTrace();
303 dataSourceTransactionManager.rollback(transactionStatus); 307 dataSourceTransactionManager.rollback(transactionStatus);
304 return false; 308 return false;
305 } 309 }
@@ -415,10 +419,9 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { @@ -415,10 +419,9 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage {
415 TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); 419 TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
416 boolean result = false; 420 boolean result = false;
417 try { 421 try {
418 - if (platformChannelMapper.delChannelForDeviceId(deviceId) <0 // 删除与国标平台的关联  
419 - || deviceChannelMapper.cleanChannelsByDeviceId(deviceId) < 0 // 删除他的通道  
420 - || deviceMapper.del(deviceId) < 0 // 移除设备信息  
421 - ) { 422 + platformChannelMapper.delChannelForDeviceId(deviceId);
  423 + deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
  424 + if ( deviceMapper.del(deviceId) < 0 ) {
422 //事务回滚 425 //事务回滚
423 dataSourceTransactionManager.rollback(transactionStatus); 426 dataSourceTransactionManager.rollback(transactionStatus);
424 } 427 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -4,8 +4,13 @@ import com.alibaba.fastjson.JSONObject; @@ -4,8 +4,13 @@ import com.alibaba.fastjson.JSONObject;
4 import com.genersoft.iot.vmp.conf.DynamicTask; 4 import com.genersoft.iot.vmp.conf.DynamicTask;
5 import com.genersoft.iot.vmp.gb28181.bean.Device; 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
7 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; 8 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
8 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; 9 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
  10 +import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
  11 +import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
  12 +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
  13 +import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
9 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 14 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
10 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 15 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
11 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 16 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
@@ -29,9 +34,8 @@ import org.springframework.util.StringUtils; @@ -29,9 +34,8 @@ import org.springframework.util.StringUtils;
29 import org.springframework.web.bind.annotation.*; 34 import org.springframework.web.bind.annotation.*;
30 import org.springframework.web.context.request.async.DeferredResult; 35 import org.springframework.web.context.request.async.DeferredResult;
31 36
32 -import java.util.List;  
33 -import java.util.Set;  
34 -import java.util.UUID; 37 +import javax.sip.DialogState;
  38 +import java.util.*;
35 39
36 @Api(tags = "国标设备查询", value = "国标设备查询") 40 @Api(tags = "国标设备查询", value = "国标设备查询")
37 @SuppressWarnings("rawtypes") 41 @SuppressWarnings("rawtypes")
@@ -63,6 +67,9 @@ public class DeviceQuery { @@ -63,6 +67,9 @@ public class DeviceQuery {
63 @Autowired 67 @Autowired
64 private DynamicTask dynamicTask; 68 private DynamicTask dynamicTask;
65 69
  70 + @Autowired
  71 + private SubscribeHolder subscribeHolder;
  72 +
66 /** 73 /**
67 * 使用ID查询国标设备 74 * 使用ID查询国标设备
68 * @param deviceId 国标ID 75 * @param deviceId 国标ID
@@ -165,12 +172,8 @@ public class DeviceQuery { @@ -165,12 +172,8 @@ public class DeviceQuery {
165 wvpResult.setData(syncStatus); 172 wvpResult.setData(syncStatus);
166 return wvpResult; 173 return wvpResult;
167 } 174 }
168 - SyncStatus syncStatusReady = new SyncStatus();  
169 - deviceService.setChannelSyncReady(deviceId);  
170 - cmder.catalogQuery(device, event -> {  
171 - String errorMsg = String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg);  
172 - deviceService.setChannelSyncEnd(deviceId, errorMsg);  
173 - }); 175 + deviceService.sync(device);
  176 +
174 WVPResult<SyncStatus> wvpResult = new WVPResult<>(); 177 WVPResult<SyncStatus> wvpResult = new WVPResult<>();
175 wvpResult.setCode(0); 178 wvpResult.setCode(0);
176 wvpResult.setMsg("开始同步"); 179 wvpResult.setMsg("开始同步");
@@ -469,4 +472,29 @@ public class DeviceQuery { @@ -469,4 +472,29 @@ public class DeviceQuery {
469 } 472 }
470 return wvpResult; 473 return wvpResult;
471 } 474 }
  475 +
  476 + @GetMapping("/{deviceId}/subscribe_info")
  477 + @ApiOperation(value = "获取设备的订阅状态", notes = "获取设备的订阅状态")
  478 + public WVPResult<Map<String, String>> getSubscribeInfo(@PathVariable String deviceId) {
  479 + Set<String> allKeys = dynamicTask.getAllKeys();
  480 + Map<String, String> dialogStateMap = new HashMap<>();
  481 + for (String key : allKeys) {
  482 + if (key.startsWith(deviceId)) {
  483 + ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key);
  484 + DialogState dialogState = subscribeTask.getDialogState();
  485 + if (dialogState == null) {
  486 + continue;
  487 + }
  488 + if (subscribeTask instanceof CatalogSubscribeTask) {
  489 + dialogStateMap.put("catalog", dialogState.toString());
  490 + }else if (subscribeTask instanceof MobilePositionSubscribeTask) {
  491 + dialogStateMap.put("mobilePosition", dialogState.toString());
  492 + }
  493 + }
  494 + }
  495 + WVPResult<Map<String, String>> wvpResult = new WVPResult<>();
  496 + wvpResult.setCode(0);
  497 + wvpResult.setData(dialogStateMap);
  498 + return wvpResult;
  499 + }
472 } 500 }
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
4 import com.alibaba.fastjson.JSONObject; 4 import com.alibaba.fastjson.JSONObject;
5 import com.genersoft.iot.vmp.VManageBootstrap; 5 import com.genersoft.iot.vmp.VManageBootstrap;
6 import com.genersoft.iot.vmp.common.VersionPo; 6 import com.genersoft.iot.vmp.common.VersionPo;
  7 +import com.genersoft.iot.vmp.conf.DynamicTask;
7 import com.genersoft.iot.vmp.conf.SipConfig; 8 import com.genersoft.iot.vmp.conf.SipConfig;
8 import com.genersoft.iot.vmp.conf.UserSetting; 9 import com.genersoft.iot.vmp.conf.UserSetting;
9 import com.genersoft.iot.vmp.conf.VersionInfo; 10 import com.genersoft.iot.vmp.conf.VersionInfo;
@@ -27,6 +28,7 @@ import javax.sip.ObjectInUseException; @@ -27,6 +28,7 @@ import javax.sip.ObjectInUseException;
27 import javax.sip.SipProvider; 28 import javax.sip.SipProvider;
28 import java.util.Iterator; 29 import java.util.Iterator;
29 import java.util.List; 30 import java.util.List;
  31 +import java.util.Set;
30 32
31 @SuppressWarnings("rawtypes") 33 @SuppressWarnings("rawtypes")
32 @Api(tags = "服务控制") 34 @Api(tags = "服务控制")
@@ -42,13 +44,16 @@ public class ServerController { @@ -42,13 +44,16 @@ public class ServerController {
42 private IMediaServerService mediaServerService; 44 private IMediaServerService mediaServerService;
43 45
44 @Autowired 46 @Autowired
45 - VersionInfo versionInfo; 47 + private VersionInfo versionInfo;
46 48
47 @Autowired 49 @Autowired
48 - SipConfig sipConfig; 50 + private SipConfig sipConfig;
49 51
50 @Autowired 52 @Autowired
51 - UserSetting userSetting; 53 + private UserSetting userSetting;
  54 +
  55 + @Autowired
  56 + private DynamicTask dynamicTask;
52 57
53 @Value("${server.port}") 58 @Value("${server.port}")
54 private int serverPort; 59 private int serverPort;
@@ -248,4 +253,35 @@ public class ServerController { @@ -248,4 +253,35 @@ public class ServerController {
248 result.setData(jsonObject); 253 result.setData(jsonObject);
249 return result; 254 return result;
250 } 255 }
  256 +
  257 +// @ApiOperation("当前进行中的动态任务")
  258 +// @GetMapping(value = "/dynamicTask")
  259 +// @ResponseBody
  260 +// public WVPResult<JSONObject> getDynamicTask(){
  261 +// WVPResult<JSONObject> result = new WVPResult<>();
  262 +// result.setCode(0);
  263 +// result.setMsg("success");
  264 +//
  265 +// JSONObject jsonObject = new JSONObject();
  266 +//
  267 +// Set<String> allKeys = dynamicTask.getAllKeys();
  268 +// jsonObject.put("server.port", serverPort);
  269 +// if (StringUtils.isEmpty(type)) {
  270 +// jsonObject.put("sip", JSON.toJSON(sipConfig));
  271 +// jsonObject.put("base", JSON.toJSON(userSetting));
  272 +// }else {
  273 +// switch (type){
  274 +// case "sip":
  275 +// jsonObject.put("sip", sipConfig);
  276 +// break;
  277 +// case "base":
  278 +// jsonObject.put("base", userSetting);
  279 +// break;
  280 +// default:
  281 +// break;
  282 +// }
  283 +// }
  284 +// result.setData(jsonObject);
  285 +// return result;
  286 +// }
251 } 287 }
web_src/src/components/dialog/SyncChannelProgress.vue
@@ -61,23 +61,36 @@ export default { @@ -61,23 +61,36 @@ export default {
61 if (!this.syncFlag) { 61 if (!this.syncFlag) {
62 this.syncFlag = true; 62 this.syncFlag = true;
63 } 63 }
64 - if (res.data.data == null) {  
65 - this.syncStatus = "success"  
66 - this.percentage = 100;  
67 - this.msg = '同步成功';  
68 - }else if (res.data.data.total == 0){  
69 - this.msg = `等待同步中`;  
70 - this.timmer = setTimeout(this.getProgress, 300)  
71 - }else if (res.data.data.errorMsg !== null ){  
72 - this.msg = res.data.data.errorMsg;  
73 - this.syncStatus = "exception"  
74 - }else {  
75 - this.total = res.data.data.total;  
76 - this.current = res.data.data.current;  
77 - this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100;  
78 - this.msg = `同步中...[${res.data.data.current}/${res.data.data.total}]`;  
79 - this.timmer = setTimeout(this.getProgress, 300) 64 +
  65 + if (res.data.data != null) {
  66 + if (res.data.data.total == 0) {
  67 + if (res.data.data.errorMsg !== null ){
  68 + this.msg = res.data.data.errorMsg;
  69 + this.syncStatus = "exception"
  70 + }else {
  71 + this.msg = `等待同步中`;
  72 + this.timmer = setTimeout(this.getProgress, 300)
  73 + }
  74 + }else {
  75 + if (res.data.data.total == res.data.data.current) {
  76 + this.syncStatus = "success"
  77 + this.percentage = 100;
  78 + this.msg = '同步成功';
  79 + }else {
  80 + if (res.data.data.errorMsg !== null ){
  81 + this.msg = res.data.data.errorMsg;
  82 + this.syncStatus = "exception"
  83 + }else {
  84 + this.total = res.data.data.total;
  85 + this.current = res.data.data.current;
  86 + this.percentage = Math.floor(Number(res.data.data.current)/Number(res.data.data.total)* 10000)/100;
  87 + this.msg = `同步中...[${res.data.data.current}/${res.data.data.total}]`;
  88 + this.timmer = setTimeout(this.getProgress, 300)
  89 + }
  90 + }
  91 + }
80 } 92 }
  93 +
81 }else { 94 }else {
82 if (this.syncFlag) { 95 if (this.syncFlag) {
83 this.syncStatus = "success" 96 this.syncStatus = "success"