Commit 40a806329ce08d5f50795cf965ef773aa48fdd3e
Merge remote-tracking branch 'origin/wvp-28181-2.0' into map
# Conflicts: # src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/SubscribeListenerForPlatform.java
Showing
39 changed files
with
1024 additions
and
340 deletions
README.md
| ... | ... | @@ -130,5 +130,14 @@ QQ私信一般不回, 精力有限.欢迎大家在群里讨论.觉得项目对 |
| 130 | 130 | |
| 131 | 131 | |
| 132 | 132 | # 致谢 |
| 133 | -感谢作者[夏楚](https://github.com/xia-chu) 提供这么棒的开源流媒体服务框架 | |
| 133 | +感谢作者[夏楚](https://github.com/xia-chu) 提供这么棒的开源流媒体服务框架,并在开发过程中给予支持与帮助。 | |
| 134 | +感谢作者[dexter langhuihui](https://github.com/langhuihui) 开源这么好用的WEB播放器。 | |
| 135 | +感谢作者[Kyle](https://gitee.com/kkkkk5G) 开源了好用的前端页面 | |
| 136 | +感谢各位大佬的赞助以及对项目的指正与帮助。包括但不限于代码贡献、问题反馈、资金捐赠等各种方式的支持!以下排名不分先后: | |
| 137 | +[lawrencehj](https://github.com/lawrencehj) @陆丰-创奇科技 [swwhaha](https://github.com/swwheihei) | |
| 138 | +[hotcoffie](https://github.com/hotcoffie) [xiaomu](https://github.com/nikmu) [TristingChen](https://github.com/TristingChen) | |
| 139 | +[chenparty](https://github.com/chenparty) [Hotleave](https://github.com/hotleave) [ydwxb](https://github.com/ydwxb) | |
| 140 | +[ydpd](https://github.com/ydpd) [szy833](https://github.com/szy833) [ydwxb](https://github.com/ydwxb) | |
| 141 | + | |
| 142 | +ps: 刚增加了这个名单,肯定遗漏了一些大佬,欢迎大佬联系我添加。 | |
| 134 | 143 | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -22,6 +22,9 @@ public class VideoManagerConstants { |
| 22 | 22 | |
| 23 | 23 | public static final String DEVICE_PREFIX = "VMP_DEVICE_"; |
| 24 | 24 | |
| 25 | + // 设备同步完成 | |
| 26 | + public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_"; | |
| 27 | + | |
| 25 | 28 | public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_"; |
| 26 | 29 | |
| 27 | 30 | public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_"; |
| ... | ... | @@ -69,6 +72,7 @@ public class VideoManagerConstants { |
| 69 | 72 | |
| 70 | 73 | public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_"; |
| 71 | 74 | |
| 75 | + | |
| 72 | 76 | //************************** redis 消息********************************* |
| 73 | 77 | |
| 74 | 78 | // 流变化的通知 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | 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 | 7 | import org.springframework.beans.factory.annotation.Autowired; |
| 5 | 8 | import org.springframework.context.annotation.Bean; |
| 6 | 9 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
| ... | ... | @@ -18,6 +21,8 @@ import java.util.concurrent.ScheduledFuture; |
| 18 | 21 | @Component |
| 19 | 22 | public class DynamicTask { |
| 20 | 23 | |
| 24 | + private Logger logger = LoggerFactory.getLogger(DynamicTask.class); | |
| 25 | + | |
| 21 | 26 | @Autowired |
| 22 | 27 | private ThreadPoolTaskScheduler threadPoolTaskScheduler; |
| 23 | 28 | |
| ... | ... | @@ -26,7 +31,12 @@ public class DynamicTask { |
| 26 | 31 | |
| 27 | 32 | @Bean |
| 28 | 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 | 47 | * @return |
| 38 | 48 | */ |
| 39 | 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 | 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 | /** |
| ... | ... | @@ -53,13 +76,31 @@ public class DynamicTask { |
| 53 | 76 | */ |
| 54 | 77 | public void startDelay(String key, Runnable task, int delay) { |
| 55 | 78 | stop(key); |
| 79 | + System.out.println("定时任务开始了"); | |
| 56 | 80 | Date starTime = new Date(System.currentTimeMillis() + delay); |
| 81 | + | |
| 82 | + ScheduledFuture future = futureMap.get(key); | |
| 83 | + if (future != null) { | |
| 84 | + if (future.isCancelled()) { | |
| 85 | + logger.info("任务【{}】已存在但是关闭状态!!!", key); | |
| 86 | + } else { | |
| 87 | + logger.info("任务【{}】已存在且已启动!!!", key); | |
| 88 | + return; | |
| 89 | + } | |
| 90 | + } | |
| 57 | 91 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 58 | - ScheduledFuture future = threadPoolTaskScheduler.schedule(task, starTime); | |
| 59 | - futureMap.put(key, future); | |
| 92 | + future = threadPoolTaskScheduler.schedule(task, starTime); | |
| 93 | + if (future != null){ | |
| 94 | + futureMap.put(key, future); | |
| 95 | + runnableMap.put(key, task); | |
| 96 | + logger.info("任务【{}】启动成功!!!", key); | |
| 97 | + }else { | |
| 98 | + logger.info("任务【{}】启动失败!!!", key); | |
| 99 | + } | |
| 60 | 100 | } |
| 61 | 101 | |
| 62 | 102 | public void stop(String key) { |
| 103 | + System.out.println("定时任务结束了"); | |
| 63 | 104 | if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) { |
| 64 | 105 | futureMap.get(key).cancel(true); |
| 65 | 106 | Runnable runnable = runnableMap.get(key); |
| ... | ... | @@ -78,4 +119,7 @@ public class DynamicTask { |
| 78 | 119 | return futureMap.keySet(); |
| 79 | 120 | } |
| 80 | 121 | |
| 122 | + public Runnable get(String key) { | |
| 123 | + return runnableMap.get(key); | |
| 124 | + } | |
| 81 | 125 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
| ... | ... | @@ -8,6 +8,12 @@ public class CatalogData { |
| 8 | 8 | private List<DeviceChannel> channelList; |
| 9 | 9 | private Date lastTime; |
| 10 | 10 | private Device device; |
| 11 | + private String errorMsg; | |
| 12 | + | |
| 13 | + public enum CatalogDataStatus{ | |
| 14 | + ready, runIng, end | |
| 15 | + } | |
| 16 | + private CatalogDataStatus status; | |
| 11 | 17 | |
| 12 | 18 | public int getTotal() { |
| 13 | 19 | return total; |
| ... | ... | @@ -40,4 +46,20 @@ public class CatalogData { |
| 40 | 46 | public void setDevice(Device device) { |
| 41 | 47 | this.device = device; |
| 42 | 48 | } |
| 49 | + | |
| 50 | + public String getErrorMsg() { | |
| 51 | + return errorMsg; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public void setErrorMsg(String errorMsg) { | |
| 55 | + this.errorMsg = errorMsg; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public CatalogDataStatus getStatus() { | |
| 59 | + return status; | |
| 60 | + } | |
| 61 | + | |
| 62 | + public void setStatus(CatalogDataStatus status) { | |
| 63 | + this.status = status; | |
| 64 | + } | |
| 43 | 65 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
| 1 | 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 | 10 | import org.springframework.stereotype.Component; |
| 4 | 11 | |
| 5 | 12 | import java.util.ArrayList; |
| ... | ... | @@ -9,12 +16,32 @@ import java.util.concurrent.ConcurrentHashMap; |
| 9 | 16 | @Component |
| 10 | 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 | 33 | private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>(); |
| 13 | 34 | private static ConcurrentHashMap<String, SubscribeInfo> mobilePositionMap = new ConcurrentHashMap<>(); |
| 14 | 35 | |
| 15 | 36 | |
| 16 | 37 | public void putCatalogSubscribe(String platformId, SubscribeInfo subscribeInfo) { |
| 17 | 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 | 47 | public SubscribeInfo getCatalogSubscribe(String platformId) { |
| ... | ... | @@ -23,10 +50,24 @@ public class SubscribeHolder { |
| 23 | 50 | |
| 24 | 51 | public void removeCatalogSubscribe(String platformId) { |
| 25 | 52 | catalogMap.remove(platformId); |
| 53 | + String taskOverdueKey = taskOverduePrefix + "catalog_" + platformId; | |
| 54 | + // 添加任务处理订阅过期 | |
| 55 | + dynamicTask.stop(taskOverdueKey); | |
| 26 | 56 | } |
| 27 | 57 | |
| 28 | 58 | public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) { |
| 29 | 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 | 73 | public SubscribeInfo getMobilePositionSubscribe(String platformId) { |
| ... | ... | @@ -35,6 +76,12 @@ public class SubscribeHolder { |
| 35 | 76 | |
| 36 | 77 | public void removeMobilePositionSubscribe(String platformId) { |
| 37 | 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 | 87 | public List<String> getAllCatalogSubscribePlatform() { |
| ... | ... | @@ -48,7 +95,7 @@ public class SubscribeHolder { |
| 48 | 95 | } |
| 49 | 96 | |
| 50 | 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 | 33 | private ServerTransaction transaction; |
| 34 | 34 | private Dialog dialog; |
| 35 | 35 | |
| 36 | + /** | |
| 37 | + * 以下为可选字段 | |
| 38 | + * @return | |
| 39 | + */ | |
| 40 | + private String sn; | |
| 41 | + private int gpsInterval; | |
| 42 | + | |
| 43 | + | |
| 36 | 44 | public String getId() { |
| 37 | 45 | return id; |
| 38 | 46 | } |
| ... | ... | @@ -88,4 +96,20 @@ public class SubscribeInfo { |
| 88 | 96 | public void setDialog(Dialog dialog) { |
| 89 | 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/bean/SyncStatus.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.gb28181.bean; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 摄像机同步状态 | |
| 5 | + */ | |
| 6 | +public class SyncStatus { | |
| 7 | + private int total; | |
| 8 | + private int current; | |
| 9 | + private String errorMsg; | |
| 10 | + | |
| 11 | + public int getTotal() { | |
| 12 | + return total; | |
| 13 | + } | |
| 14 | + | |
| 15 | + public void setTotal(int total) { | |
| 16 | + this.total = total; | |
| 17 | + } | |
| 18 | + | |
| 19 | + public int getCurrent() { | |
| 20 | + return current; | |
| 21 | + } | |
| 22 | + | |
| 23 | + public void setCurrent(int current) { | |
| 24 | + this.current = current; | |
| 25 | + } | |
| 26 | + | |
| 27 | + public String getErrorMsg() { | |
| 28 | + return errorMsg; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setErrorMsg(String errorMsg) { | |
| 32 | + this.errorMsg = errorMsg; | |
| 33 | + } | |
| 34 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
| ... | ... | @@ -95,11 +95,12 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> { |
| 95 | 95 | } |
| 96 | 96 | // 处理上线监听 |
| 97 | 97 | storager.updateDevice(device); |
| 98 | - List<DeviceChannel> deviceChannelList = storager.queryOnlineChannelsByDeviceId(device.getDeviceId()); | |
| 99 | - eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON); | |
| 100 | 98 | // 上线添加订阅 |
| 101 | 99 | if (device.getSubscribeCycleForCatalog() > 0) { |
| 100 | + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 102 | 101 | deviceService.addCatalogSubscribe(device); |
| 102 | + } | |
| 103 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 103 | 104 | deviceService.addMobilePositionSubscribe(device); |
| 104 | 105 | } |
| 105 | 106 | } | ... | ... |
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 | - // 订阅到期 | |
| 43 | - String PLATFORM_KEEPLIVEKEY_PREFIX = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_"; | |
| 44 | - if (expiredKey.startsWith(PLATFORM_KEEPLIVEKEY_PREFIX)) { | |
| 45 | - // 取消定时任务 | |
| 46 | - dynamicTask.stop(expiredKey); | |
| 47 | - } | |
| 48 | - } | |
| 49 | -} |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| ... | ... | @@ -61,8 +61,6 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 61 | 61 | if (event.getPlatformId() != null) { |
| 62 | 62 | parentPlatform = storager.queryParentPlatByServerGBId(event.getPlatformId()); |
| 63 | 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 | 64 | subscribe = subscribeHolder.getCatalogSubscribe(event.getPlatformId()); |
| 67 | 65 | |
| 68 | 66 | if (subscribe == null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
| ... | ... | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.session; |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.CatalogData; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 6 | +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; | |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 8 | 9 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| ... | ... | @@ -25,6 +26,17 @@ public class CatalogDataCatch { |
| 25 | 26 | @Autowired |
| 26 | 27 | private IVideoManagerStorage storager; |
| 27 | 28 | |
| 29 | + public void addReady(String key) { | |
| 30 | + CatalogData catalogData = data.get(key); | |
| 31 | + if (catalogData == null || catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end)) { | |
| 32 | + catalogData = new CatalogData(); | |
| 33 | + catalogData.setChannelList(new ArrayList<>()); | |
| 34 | + catalogData.setStatus(CatalogData.CatalogDataStatus.ready); | |
| 35 | + catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 36 | + data.put(key, catalogData); | |
| 37 | + } | |
| 38 | + } | |
| 39 | + | |
| 28 | 40 | public void put(String key, int total, Device device, List<DeviceChannel> deviceChannelList) { |
| 29 | 41 | CatalogData catalogData = data.get(key); |
| 30 | 42 | if (catalogData == null) { |
| ... | ... | @@ -32,10 +44,16 @@ public class CatalogDataCatch { |
| 32 | 44 | catalogData.setTotal(total); |
| 33 | 45 | catalogData.setDevice(device); |
| 34 | 46 | catalogData.setChannelList(new ArrayList<>()); |
| 47 | + catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); | |
| 48 | + catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 35 | 49 | data.put(key, catalogData); |
| 50 | + }else { | |
| 51 | + catalogData.setTotal(total); | |
| 52 | + catalogData.setDevice(device); | |
| 53 | + catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); | |
| 54 | + catalogData.getChannelList().addAll(deviceChannelList); | |
| 55 | + catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 36 | 56 | } |
| 37 | - catalogData.getChannelList().addAll(deviceChannelList); | |
| 38 | - catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 39 | 57 | } |
| 40 | 58 | |
| 41 | 59 | public List<DeviceChannel> get(String key) { |
| ... | ... | @@ -44,6 +62,22 @@ public class CatalogDataCatch { |
| 44 | 62 | return catalogData.getChannelList(); |
| 45 | 63 | } |
| 46 | 64 | |
| 65 | + public int getTotal(String key) { | |
| 66 | + CatalogData catalogData = data.get(key); | |
| 67 | + if (catalogData == null) return 0; | |
| 68 | + return catalogData.getTotal(); | |
| 69 | + } | |
| 70 | + | |
| 71 | + public SyncStatus getSyncStatus(String key) { | |
| 72 | + CatalogData catalogData = data.get(key); | |
| 73 | + if (catalogData == null) return null; | |
| 74 | + SyncStatus syncStatus = new SyncStatus(); | |
| 75 | + syncStatus.setCurrent(catalogData.getChannelList().size()); | |
| 76 | + syncStatus.setTotal(catalogData.getTotal()); | |
| 77 | + syncStatus.setErrorMsg(catalogData.getErrorMsg()); | |
| 78 | + return syncStatus; | |
| 79 | + } | |
| 80 | + | |
| 47 | 81 | public void del(String key) { |
| 48 | 82 | data.remove(key); |
| 49 | 83 | } |
| ... | ... | @@ -51,24 +85,32 @@ public class CatalogDataCatch { |
| 51 | 85 | @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时 |
| 52 | 86 | private void timerTask(){ |
| 53 | 87 | Set<String> keys = data.keySet(); |
| 54 | - Calendar calendar = Calendar.getInstance(); | |
| 55 | - calendar.setTime(new Date()); | |
| 56 | - calendar.set(Calendar.SECOND, calendar.get(Calendar.SECOND) - 5); | |
| 88 | + Calendar calendarBefore5S = Calendar.getInstance(); | |
| 89 | + calendarBefore5S.setTime(new Date()); | |
| 90 | + calendarBefore5S.set(Calendar.SECOND, calendarBefore5S.get(Calendar.SECOND) - 5); | |
| 91 | + | |
| 92 | + Calendar calendarBefore30S = Calendar.getInstance(); | |
| 93 | + calendarBefore30S.setTime(new Date()); | |
| 94 | + calendarBefore30S.set(Calendar.SECOND, calendarBefore30S.get(Calendar.SECOND) - 30); | |
| 57 | 95 | for (String key : keys) { |
| 58 | 96 | CatalogData catalogData = data.get(key); |
| 59 | - if (catalogData.getLastTime().before(calendar.getTime())) { | |
| 60 | - | |
| 97 | + if (catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 超过五秒收不到消息任务超时, 只更新这一部分数据 | |
| 61 | 98 | storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); |
| 62 | - RequestMessage msg = new RequestMessage(); | |
| 63 | - msg.setKey(key); | |
| 64 | - WVPResult<Object> result = new WVPResult<>(); | |
| 65 | - result.setCode(0); | |
| 66 | - result.setMsg("更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条"); | |
| 67 | - result.setData(catalogData.getDevice()); | |
| 68 | - msg.setData(result); | |
| 69 | - deferredResultHolder.invokeAllResult(msg); | |
| 99 | + String errorMsg = "更新成功,共" + catalogData.getTotal() + "条,已更新" + catalogData.getChannelList().size() + "条"; | |
| 100 | + catalogData.setStatus(CatalogData.CatalogDataStatus.end); | |
| 101 | + catalogData.setErrorMsg(errorMsg); | |
| 102 | + } | |
| 103 | + if (catalogData.getLastTime().before(calendarBefore30S.getTime())) { // 超过三十秒,如果标记为end则删除 | |
| 70 | 104 | data.remove(key); |
| 71 | 105 | } |
| 72 | 106 | } |
| 73 | 107 | } |
| 108 | + | |
| 109 | + | |
| 110 | + public void setChannelSyncEnd(String key, String errorMsg) { | |
| 111 | + CatalogData catalogData = data.get(key); | |
| 112 | + if (catalogData == null)return; | |
| 113 | + catalogData.setStatus(CatalogData.CatalogDataStatus.end); | |
| 114 | + catalogData.setErrorMsg(errorMsg); | |
| 115 | + } | |
| 74 | 116 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java
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 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 6 | 6 | import org.slf4j.Logger; |
| 7 | 7 | import org.slf4j.LoggerFactory; |
| 8 | +import org.springframework.scheduling.annotation.Async; | |
| 8 | 9 | |
| 9 | 10 | import javax.sip.Dialog; |
| 10 | 11 | import javax.sip.DialogState; |
| ... | ... | @@ -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 | 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 | 4 | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; |
| 8 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 9 | 6 | import com.genersoft.iot.vmp.service.bean.GPSMsgInfo; |
| 10 | 7 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 11 | 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 | 14 | import java.util.List; |
| 15 | 15 | |
| 16 | 16 | /** |
| ... | ... | @@ -18,20 +18,21 @@ import java.util.List; |
| 18 | 18 | */ |
| 19 | 19 | public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { |
| 20 | 20 | |
| 21 | + private Logger logger = LoggerFactory.getLogger(MobilePositionSubscribeHandlerTask.class); | |
| 22 | + | |
| 21 | 23 | private IRedisCatchStorage redisCatchStorage; |
| 22 | 24 | private IVideoManagerStorage storager; |
| 23 | 25 | private ISIPCommanderForPlatform sipCommanderForPlatform; |
| 24 | 26 | private SubscribeHolder subscribeHolder; |
| 25 | - private String platformId; | |
| 27 | + private ParentPlatform platform; | |
| 26 | 28 | private String sn; |
| 27 | 29 | private String key; |
| 28 | 30 | |
| 29 | - private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); | |
| 30 | - | |
| 31 | 31 | public MobilePositionSubscribeHandlerTask(IRedisCatchStorage redisCatchStorage, ISIPCommanderForPlatform sipCommanderForPlatform, IVideoManagerStorage storager, String platformId, String sn, String key, SubscribeHolder subscribeInfo) { |
| 32 | + System.out.println("MobilePositionSubscribeHandlerTask 初始化"); | |
| 32 | 33 | this.redisCatchStorage = redisCatchStorage; |
| 33 | 34 | this.storager = storager; |
| 34 | - this.platformId = platformId; | |
| 35 | + this.platform = storager.queryParentPlatByServerGBId(platformId); | |
| 35 | 36 | this.sn = sn; |
| 36 | 37 | this.key = key; |
| 37 | 38 | this.sipCommanderForPlatform = sipCommanderForPlatform; |
| ... | ... | @@ -41,37 +42,45 @@ public class MobilePositionSubscribeHandlerTask implements ISubscribeTask { |
| 41 | 42 | @Override |
| 42 | 43 | public void run() { |
| 43 | 44 | |
| 44 | - SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platformId); | |
| 45 | - | |
| 45 | + logger.info("执行MobilePositionSubscribeHandlerTask"); | |
| 46 | + if (platform == null) return; | |
| 47 | + SubscribeInfo subscribe = subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()); | |
| 46 | 48 | 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 | - } | |
| 49 | + | |
| 50 | +// if (!parentPlatform.isStatus()) { | |
| 51 | +// logger.info("发送订阅时发现平台已经离线:{}", platformId); | |
| 52 | +// return; | |
| 53 | +// } | |
| 54 | + // TODO 暂时只处理视频流的回复,后续增加对国标设备的支持 | |
| 55 | + List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(platform.getServerGBId()); | |
| 56 | + if (gbStreams.size() == 0) { | |
| 57 | + logger.info("发送订阅时发现平台已经没有关联的直播流:{}", platform.getServerGBId()); | |
| 58 | + return; | |
| 59 | + } | |
| 60 | + for (GbStream gbStream : gbStreams) { | |
| 61 | + String gbId = gbStream.getGbId(); | |
| 62 | + GPSMsgInfo gpsMsgInfo = redisCatchStorage.getGpsMsgInfo(gbId); | |
| 63 | + if (gpsMsgInfo != null) { // 无最新位置不发送 | |
| 64 | + logger.info("无最新位置不发送"); | |
| 65 | + // 经纬度都为0不发送 | |
| 66 | + if (gpsMsgInfo.getLng() == 0 && gpsMsgInfo.getLat() == 0) { | |
| 67 | + continue; | |
| 67 | 68 | } |
| 69 | + // 发送GPS消息 | |
| 70 | + sipCommanderForPlatform.sendNotifyMobilePosition(platform, gpsMsgInfo, subscribe); | |
| 68 | 71 | } |
| 69 | 72 | } |
| 70 | 73 | } |
| 74 | + logger.info("结束执行MobilePositionSubscribeHandlerTask"); | |
| 71 | 75 | } |
| 72 | 76 | |
| 73 | 77 | @Override |
| 74 | 78 | public void stop() { |
| 75 | 79 | |
| 76 | 80 | } |
| 81 | + | |
| 82 | + @Override | |
| 83 | + public DialogState getDialogState() { | |
| 84 | + return null; | |
| 85 | + } | |
| 77 | 86 | } | ... | ... |
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 | 6 | import org.dom4j.Element; |
| 7 | 7 | import org.slf4j.Logger; |
| 8 | 8 | import org.slf4j.LoggerFactory; |
| 9 | +import org.springframework.scheduling.annotation.Async; | |
| 9 | 10 | |
| 10 | 11 | import javax.sip.Dialog; |
| 11 | 12 | import javax.sip.DialogState; |
| 12 | 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 | 23 | private ISIPCommander sipCommander; |
| 21 | 24 | private Dialog dialog; |
| 22 | 25 | |
| 26 | + private Timer timer ; | |
| 27 | + | |
| 23 | 28 | public MobilePositionSubscribeTask(Device device, ISIPCommander sipCommander) { |
| 24 | 29 | this.device = device; |
| 25 | 30 | this.sipCommander = sipCommander; |
| ... | ... | @@ -27,10 +32,14 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { |
| 27 | 32 | |
| 28 | 33 | @Override |
| 29 | 34 | public void run() { |
| 35 | + if (timer != null ) { | |
| 36 | + timer.cancel(); | |
| 37 | + timer = null; | |
| 38 | + } | |
| 30 | 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 | 43 | ResponseEvent event = (ResponseEvent) eventResult.event; |
| 35 | 44 | if (event.getResponse().getRawContent() != null) { |
| 36 | 45 | // 成功 |
| ... | ... | @@ -43,6 +52,13 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { |
| 43 | 52 | dialog = null; |
| 44 | 53 | // 失败 |
| 45 | 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,8 +72,12 @@ public class MobilePositionSubscribeTask implements ISubscribeTask { |
| 56 | 72 | * COMPLETED-> Completed Dialog状态-已完成 |
| 57 | 73 | * TERMINATED-> Terminated Dialog状态-终止 |
| 58 | 74 | */ |
| 59 | - logger.info("取消移动订阅时dialog状态为{}", dialog.getState()); | |
| 75 | + if (timer != null ) { | |
| 76 | + timer.cancel(); | |
| 77 | + timer = null; | |
| 78 | + } | |
| 60 | 79 | if (dialog != null && dialog.getState().equals(DialogState.CONFIRMED)) { |
| 80 | + logger.info("取消移动订阅时dialog状态为{}", dialog.getState()); | |
| 61 | 81 | device.setSubscribeCycleForMobilePosition(0); |
| 62 | 82 | sipCommander.mobilePositionSubscribe(device, dialog, eventResult -> { |
| 63 | 83 | ResponseEvent event = (ResponseEvent) eventResult.event; |
| ... | ... | @@ -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/ISIPCommanderForPlatform.java
| ... | ... | @@ -46,6 +46,7 @@ public interface ISIPCommanderForPlatform { |
| 46 | 46 | * @return |
| 47 | 47 | */ |
| 48 | 48 | boolean catalogQuery(DeviceChannel channel, ParentPlatform parentPlatform, String sn, String fromTag, int size); |
| 49 | + boolean catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag); | |
| 49 | 50 | |
| 50 | 51 | /** |
| 51 | 52 | * 向上级回复DeviceInfo查询信息 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -1566,17 +1566,28 @@ public class SIPCommander implements ISIPCommander { |
| 1566 | 1566 | cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); |
| 1567 | 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 | 1591 | return true; |
| 1581 | 1592 | |
| 1582 | 1593 | } catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -215,44 +215,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 215 | 215 | return false; |
| 216 | 216 | } |
| 217 | 217 | try { |
| 218 | - String characterSet = parentPlatform.getCharacterSet(); | |
| 219 | - StringBuffer catalogXml = new StringBuffer(600); | |
| 220 | - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n"); | |
| 221 | - catalogXml.append("<Response>\r\n"); | |
| 222 | - catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); | |
| 223 | - catalogXml.append("<SN>" +sn + "</SN>\r\n"); | |
| 224 | - catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | |
| 225 | - catalogXml.append("<SumNum>" + size + "</SumNum>\r\n"); | |
| 226 | - catalogXml.append("<DeviceList Num=\"1\">\r\n"); | |
| 227 | - catalogXml.append("<Item>\r\n"); | |
| 228 | - if (channel != null) { | |
| 229 | - catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); | |
| 230 | - catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n"); | |
| 231 | - catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 232 | - catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 233 | - catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n"); | |
| 234 | - catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); | |
| 235 | - catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 236 | - catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 237 | - if (channel.getParentId() != null) { | |
| 238 | - catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 239 | - } | |
| 240 | - catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 241 | - catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 242 | - catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n"); | |
| 243 | - catalogXml.append("<Longitude>" + channel.getLongitude() + "</Longitude>\r\n"); | |
| 244 | - catalogXml.append("<Latitude>" + channel.getLatitude() + "</Latitude>\r\n"); | |
| 245 | - catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); | |
| 246 | - catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); | |
| 247 | - catalogXml.append("<Info>\r\n"); | |
| 248 | - catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); | |
| 249 | - catalogXml.append("</Info>\r\n"); | |
| 250 | - } | |
| 251 | - | |
| 252 | - | |
| 253 | - catalogXml.append("</Item>\r\n"); | |
| 254 | - catalogXml.append("</DeviceList>\r\n"); | |
| 255 | - catalogXml.append("</Response>\r\n"); | |
| 218 | + String catalogXml = getCatalogXml(channel, sn, parentPlatform, size); | |
| 256 | 219 | |
| 257 | 220 | // callid |
| 258 | 221 | CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| ... | ... | @@ -268,6 +231,77 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 268 | 231 | return true; |
| 269 | 232 | } |
| 270 | 233 | |
| 234 | + @Override | |
| 235 | + public boolean catalogQuery(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag) { | |
| 236 | + if ( parentPlatform ==null) { | |
| 237 | + return false; | |
| 238 | + } | |
| 239 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, 0); | |
| 240 | + return true; | |
| 241 | + } | |
| 242 | + private String getCatalogXml(DeviceChannel channel, String sn, ParentPlatform parentPlatform, int size) { | |
| 243 | + String characterSet = parentPlatform.getCharacterSet(); | |
| 244 | + StringBuffer catalogXml = new StringBuffer(600); | |
| 245 | + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet +"\"?>\r\n"); | |
| 246 | + catalogXml.append("<Response>\r\n"); | |
| 247 | + catalogXml.append("<CmdType>Catalog</CmdType>\r\n"); | |
| 248 | + catalogXml.append("<SN>" +sn + "</SN>\r\n"); | |
| 249 | + catalogXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n"); | |
| 250 | + catalogXml.append("<SumNum>" + size + "</SumNum>\r\n"); | |
| 251 | + catalogXml.append("<DeviceList Num=\"1\">\r\n"); | |
| 252 | + catalogXml.append("<Item>\r\n"); | |
| 253 | + if (channel != null) { | |
| 254 | + catalogXml.append("<DeviceID>" + channel.getChannelId() + "</DeviceID>\r\n"); | |
| 255 | + catalogXml.append("<Name>" + channel.getName() + "</Name>\r\n"); | |
| 256 | + catalogXml.append("<Manufacturer>" + channel.getManufacture() + "</Manufacturer>\r\n"); | |
| 257 | + catalogXml.append("<Model>" + channel.getModel() + "</Model>\r\n"); | |
| 258 | + catalogXml.append("<Owner>" + channel.getOwner() + "</Owner>\r\n"); | |
| 259 | + catalogXml.append("<CivilCode>" + channel.getCivilCode() + "</CivilCode>\r\n"); | |
| 260 | + catalogXml.append("<Address>" + channel.getAddress() + "</Address>\r\n"); | |
| 261 | + catalogXml.append("<Parental>" + channel.getParental() + "</Parental>\r\n"); | |
| 262 | + if (channel.getParentId() != null) { | |
| 263 | + catalogXml.append("<ParentID>" + channel.getParentId() + "</ParentID>\r\n"); | |
| 264 | + } | |
| 265 | + catalogXml.append("<Secrecy>" + channel.getSecrecy() + "</Secrecy>\r\n"); | |
| 266 | + catalogXml.append("<RegisterWay>" + channel.getRegisterWay() + "</RegisterWay>\r\n"); | |
| 267 | + catalogXml.append("<Status>" + (channel.getStatus() == 0?"OFF":"ON") + "</Status>\r\n"); | |
| 268 | + catalogXml.append("<Longitude>" + channel.getLongitude() + "</Longitude>\r\n"); | |
| 269 | + catalogXml.append("<Latitude>" + channel.getLatitude() + "</Latitude>\r\n"); | |
| 270 | + catalogXml.append("<IPAddress>" + channel.getIpAddress() + "</IPAddress>\r\n"); | |
| 271 | + catalogXml.append("<Port>" + channel.getPort() + "</Port>\r\n"); | |
| 272 | + catalogXml.append("<Info>\r\n"); | |
| 273 | + catalogXml.append("<PTZType>" + channel.getPTZType() + "</PTZType>\r\n"); | |
| 274 | + catalogXml.append("</Info>\r\n"); | |
| 275 | + } | |
| 276 | + | |
| 277 | + | |
| 278 | + catalogXml.append("</Item>\r\n"); | |
| 279 | + catalogXml.append("</DeviceList>\r\n"); | |
| 280 | + catalogXml.append("</Response>\r\n"); | |
| 281 | + return catalogXml.toString(); | |
| 282 | + } | |
| 283 | + | |
| 284 | + private void sendCatalogResponse(List<DeviceChannel> channels, ParentPlatform parentPlatform, String sn, String fromTag, int index) { | |
| 285 | + if (index >= channels.size()) { | |
| 286 | + return; | |
| 287 | + } | |
| 288 | + try { | |
| 289 | + DeviceChannel deviceChannel = channels.get(index); | |
| 290 | + String catalogXml = getCatalogXml(deviceChannel, sn, parentPlatform, channels.size()); | |
| 291 | + // callid | |
| 292 | + CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() | |
| 293 | + : udpSipProvider.getNewCallId(); | |
| 294 | + | |
| 295 | + Request request = headerProviderPlarformProvider.createMessageRequest(parentPlatform, catalogXml, fromTag, callIdHeader); | |
| 296 | + transmitRequest(parentPlatform, request, null, eventResult -> { | |
| 297 | + int indexNext = index + 1; | |
| 298 | + sendCatalogResponse(channels, parentPlatform, sn, fromTag, indexNext); | |
| 299 | + }); | |
| 300 | + } catch (SipException | ParseException | InvalidArgumentException e) { | |
| 301 | + e.printStackTrace(); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 271 | 305 | /** |
| 272 | 306 | * 向上级回复DeviceInfo查询信息 |
| 273 | 307 | * @param parentPlatform 平台信息 |
| ... | ... | @@ -351,7 +385,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 351 | 385 | if (parentPlatform == null) { |
| 352 | 386 | return false; |
| 353 | 387 | } |
| 354 | - | |
| 388 | + logger.info("[发送 移动位置订阅] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat()); | |
| 355 | 389 | try { |
| 356 | 390 | String characterSet = parentPlatform.getCharacterSet(); |
| 357 | 391 | StringBuffer deviceStatusXml = new StringBuffer(600); |
| ... | ... | @@ -371,7 +405,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 371 | 405 | CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId() |
| 372 | 406 | : udpSipProvider.getNewCallId(); |
| 373 | 407 | callIdHeader.setCallId(subscribeInfo.getCallId()); |
| 374 | - logger.info("[发送Notify-MobilePosition] {}/{}->{},{}", parentPlatform.getServerGBId(), gpsMsgInfo.getId(), gpsMsgInfo.getLng(), gpsMsgInfo.getLat()); | |
| 408 | + | |
| 375 | 409 | sendNotify(parentPlatform, deviceStatusXml.toString(), subscribeInfo, eventResult -> { |
| 376 | 410 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); |
| 377 | 411 | }, null); |
| ... | ... | @@ -425,7 +459,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 425 | 459 | // 设置编码, 防止中文乱码 |
| 426 | 460 | messageFactory.setDefaultContentEncodingCharset(characterSet); |
| 427 | 461 | Dialog dialog = subscribeInfo.getDialog(); |
| 428 | - if (dialog == null) return; | |
| 462 | + if (dialog == null || !dialog.getState().equals(DialogState.CONFIRMED)) return; | |
| 429 | 463 | SIPRequest notifyRequest = (SIPRequest)dialog.createRequest(Request.NOTIFY); |
| 430 | 464 | ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); |
| 431 | 465 | notifyRequest.setContent(catalogXmlContent, contentTypeHeader); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
| ... | ... | @@ -147,7 +147,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 147 | 147 | } else { |
| 148 | 148 | mobilePosition.setAltitude(0.0); |
| 149 | 149 | } |
| 150 | - logger.info("[收到Notify-MobilePosition]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(), | |
| 150 | + logger.info("[收到 移动位置订阅]:{}/{}->{}.{}", mobilePosition.getDeviceId(), mobilePosition.getChannelId(), | |
| 151 | 151 | mobilePosition.getLongitude(), mobilePosition.getLatitude()); |
| 152 | 152 | mobilePosition.setReportSource("Mobile Position"); |
| 153 | 153 | // 默认来源坐标系为WGS-84处理 |
| ... | ... | @@ -283,7 +283,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements |
| 283 | 283 | Element eventElement = itemDevice.element("Event"); |
| 284 | 284 | DeviceChannel channel = XmlUtil.channelContentHander(itemDevice); |
| 285 | 285 | channel.setDeviceId(device.getDeviceId()); |
| 286 | - logger.info("[收到Notify-Catalog]:{}/{}", device.getDeviceId(), channel.getChannelId()); | |
| 286 | + logger.info("[收到 目录订阅]:{}/{}", device.getDeviceId(), channel.getChannelId()); | |
| 287 | 287 | switch (eventElement.getText().toUpperCase()) { |
| 288 | 288 | case CatalogEvent.ON: // 上线 |
| 289 | 289 | logger.info("收到来自设备【{}】的通道【{}】上线通知", device.getDeviceId(), channel.getChannelId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
| ... | ... | @@ -137,6 +137,9 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 137 | 137 | String deviceID = XmlUtil.getText(rootElement, "DeviceID"); |
| 138 | 138 | ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId); |
| 139 | 139 | SubscribeInfo subscribeInfo = new SubscribeInfo(evt, platformId); |
| 140 | + if (platform == null) { | |
| 141 | + return; | |
| 142 | + } | |
| 140 | 143 | if (evt.getServerTransaction() == null) { |
| 141 | 144 | ServerTransaction serverTransaction = platform.getTransport().equals("TCP") ? tcpSipProvider.getNewServerTransaction(evt.getRequest()) |
| 142 | 145 | : udpSipProvider.getNewServerTransaction(evt.getRequest()); |
| ... | ... | @@ -146,8 +149,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 146 | 149 | subscribeInfo.setDialog(dialog); |
| 147 | 150 | } |
| 148 | 151 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 149 | - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_MobilePosition_" + platformId; | |
| 150 | - logger.info("[notify-MobilePosition]: {}", platformId); | |
| 152 | + logger.info("[回复 移动位置订阅]: {}", platformId); | |
| 151 | 153 | StringBuilder resultXml = new StringBuilder(200); |
| 152 | 154 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 153 | 155 | .append("<Response>\r\n") |
| ... | ... | @@ -158,14 +160,25 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 158 | 160 | .append("</Response>\r\n"); |
| 159 | 161 | |
| 160 | 162 | if (subscribeInfo.getExpires() > 0) { |
| 161 | - if (subscribeHolder.getMobilePositionSubscribe(platformId) != null) { | |
| 162 | - dynamicTask.stop(key); | |
| 163 | - } | |
| 164 | 163 | String interval = XmlUtil.getText(rootElement, "Interval"); // GPS上报时间间隔 |
| 165 | - 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); | |
| 166 | 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 | +// } | |
| 167 | 181 | }else if (subscribeInfo.getExpires() == 0) { |
| 168 | - dynamicTask.stop(key); | |
| 169 | 182 | subscribeHolder.removeMobilePositionSubscribe(platformId); |
| 170 | 183 | } |
| 171 | 184 | |
| ... | ... | @@ -199,8 +212,7 @@ public class SubscribeRequestProcessor extends SIPRequestProcessorParent impleme |
| 199 | 212 | subscribeInfo.setDialog(dialog); |
| 200 | 213 | } |
| 201 | 214 | String sn = XmlUtil.getText(rootElement, "SN"); |
| 202 | - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "_Catalog_" + platformId; | |
| 203 | - logger.info("[notify-Catalog]: {}", platformId); | |
| 215 | + logger.info("[回复 目录订阅]: {}/{}", platformId, deviceID); | |
| 204 | 216 | StringBuilder resultXml = new StringBuilder(200); |
| 205 | 217 | resultXml.append("<?xml version=\"1.0\" ?>\r\n") |
| 206 | 218 | .append("<Response>\r\n") | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
| ... | ... | @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorP |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 13 | 13 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 14 | 14 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 15 | +import gov.nist.javax.sip.message.SIPRequest; | |
| 15 | 16 | import org.dom4j.DocumentException; |
| 16 | 17 | import org.dom4j.Element; |
| 17 | 18 | import org.slf4j.Logger; |
| ... | ... | @@ -23,6 +24,7 @@ import org.springframework.stereotype.Component; |
| 23 | 24 | import javax.sip.InvalidArgumentException; |
| 24 | 25 | import javax.sip.RequestEvent; |
| 25 | 26 | import javax.sip.SipException; |
| 27 | +import javax.sip.address.SipURI; | |
| 26 | 28 | import javax.sip.header.CSeqHeader; |
| 27 | 29 | import javax.sip.header.CallIdHeader; |
| 28 | 30 | import javax.sip.message.Response; |
| ... | ... | @@ -81,6 +83,17 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement |
| 81 | 83 | // 查询上级平台是否存在 |
| 82 | 84 | ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId); |
| 83 | 85 | try { |
| 86 | + if (device != null && parentPlatform != null) { | |
| 87 | + logger.warn("[重复]平台与设备编号重复:{}", deviceId); | |
| 88 | + SIPRequest request = (SIPRequest) evt.getRequest(); | |
| 89 | + String hostAddress = request.getRemoteAddress().getHostAddress(); | |
| 90 | + int remotePort = request.getRemotePort(); | |
| 91 | + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) { | |
| 92 | + parentPlatform = null; | |
| 93 | + }else { | |
| 94 | + device = null; | |
| 95 | + } | |
| 96 | + } | |
| 84 | 97 | if (device == null && parentPlatform == null) { |
| 85 | 98 | // 不存在则回复404 |
| 86 | 99 | responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found"); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java
| ... | ... | @@ -23,6 +23,7 @@ import javax.sip.*; |
| 23 | 23 | import javax.sip.address.SipURI; |
| 24 | 24 | import javax.sip.header.HeaderAddress; |
| 25 | 25 | import javax.sip.header.ToHeader; |
| 26 | +import javax.sip.message.Response; | |
| 26 | 27 | import java.text.ParseException; |
| 27 | 28 | import java.util.Iterator; |
| 28 | 29 | |
| ... | ... | @@ -103,6 +104,18 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent |
| 103 | 104 | if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) { |
| 104 | 105 | String cmdString = getText(rootElement,"PTZCmd"); |
| 105 | 106 | Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId); |
| 107 | + if (deviceForPlatform == null) { | |
| 108 | + try { | |
| 109 | + responseAck(evt, Response.NOT_FOUND); | |
| 110 | + return; | |
| 111 | + } catch (SipException e) { | |
| 112 | + e.printStackTrace(); | |
| 113 | + } catch (InvalidArgumentException e) { | |
| 114 | + e.printStackTrace(); | |
| 115 | + } catch (ParseException e) { | |
| 116 | + e.printStackTrace(); | |
| 117 | + } | |
| 118 | + } | |
| 106 | 119 | cmder.fronEndCmd(deviceForPlatform, channelId, cmdString, eventResult -> { |
| 107 | 120 | // 失败的回复 |
| 108 | 121 | try { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
| ... | ... | @@ -18,6 +18,7 @@ import javax.sip.SipException; |
| 18 | 18 | import javax.sip.header.FromHeader; |
| 19 | 19 | import javax.sip.message.Response; |
| 20 | 20 | import java.text.ParseException; |
| 21 | +import java.util.ArrayList; | |
| 21 | 22 | import java.util.List; |
| 22 | 23 | |
| 23 | 24 | @Component |
| ... | ... | @@ -58,7 +59,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 58 | 59 | List<DeviceChannelInPlatform> deviceChannels = storage.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); |
| 59 | 60 | // 查询关联的直播通道 |
| 60 | 61 | List<GbStream> gbStreams = storage.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); |
| 61 | - int size = deviceChannels.size() + gbStreams.size(); | |
| 62 | + | |
| 63 | + List<DeviceChannel> allChannels = new ArrayList<>(); | |
| 62 | 64 | // 回复目录信息 |
| 63 | 65 | List<PlatformCatalog> catalogs = storage.queryCatalogInPlatform(parentPlatform.getServerGBId()); |
| 64 | 66 | if (catalogs.size() > 0) { |
| ... | ... | @@ -81,9 +83,7 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 81 | 83 | deviceChannel.setModel("live"); |
| 82 | 84 | deviceChannel.setOwner("wvp-pro"); |
| 83 | 85 | deviceChannel.setSecrecy("0"); |
| 84 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 85 | - // 防止发送过快 | |
| 86 | - Thread.sleep(100); | |
| 86 | + allChannels.add(deviceChannel); | |
| 87 | 87 | } |
| 88 | 88 | } |
| 89 | 89 | // 回复级联的通道 |
| ... | ... | @@ -96,9 +96,7 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 96 | 96 | deviceChannel.setParental(0); |
| 97 | 97 | deviceChannel.setParentId(channel.getCatalogId()); |
| 98 | 98 | deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6)); |
| 99 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 100 | - // 防止发送过快 | |
| 101 | - Thread.sleep(100); | |
| 99 | + allChannels.add(deviceChannel); | |
| 102 | 100 | } |
| 103 | 101 | } |
| 104 | 102 | // 回复直播的通道 |
| ... | ... | @@ -114,7 +112,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 114 | 112 | deviceChannel.setLatitude(gbStream.getLatitude()); |
| 115 | 113 | deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); |
| 116 | 114 | deviceChannel.setManufacture("wvp-pro"); |
| 117 | - deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 115 | +// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 116 | + deviceChannel.setStatus(1); | |
| 118 | 117 | deviceChannel.setParentId(gbStream.getCatalogId()); |
| 119 | 118 | deviceChannel.setRegisterWay(1); |
| 120 | 119 | deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0,6)); |
| ... | ... | @@ -122,16 +121,16 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple |
| 122 | 121 | deviceChannel.setOwner("wvp-pro"); |
| 123 | 122 | deviceChannel.setParental(0); |
| 124 | 123 | deviceChannel.setSecrecy("0"); |
| 125 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 126 | - // 防止发送过快 | |
| 127 | - Thread.sleep(100); | |
| 124 | + allChannels.add(deviceChannel); | |
| 128 | 125 | } |
| 129 | 126 | } |
| 130 | - if (size == 0) { | |
| 127 | + if (allChannels.size() > 0) { | |
| 128 | + cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag()); | |
| 129 | + }else { | |
| 131 | 130 | // 回复无通道 |
| 132 | - cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); | |
| 131 | + cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0); | |
| 133 | 132 | } |
| 134 | - } catch (SipException | InvalidArgumentException | ParseException | InterruptedException e) { | |
| 133 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 135 | 134 | e.printStackTrace(); |
| 136 | 135 | } |
| 137 | 136 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
| ... | ... | @@ -22,6 +22,7 @@ import javax.sip.SipException; |
| 22 | 22 | import javax.sip.header.FromHeader; |
| 23 | 23 | import javax.sip.message.Response; |
| 24 | 24 | import java.text.ParseException; |
| 25 | +import java.util.ArrayList; | |
| 25 | 26 | import java.util.List; |
| 26 | 27 | |
| 27 | 28 | @Component |
| ... | ... | @@ -45,6 +46,9 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 45 | 46 | @Autowired |
| 46 | 47 | private EventPublisher publisher; |
| 47 | 48 | |
| 49 | + @Autowired | |
| 50 | + private IVideoManagerStorage storage; | |
| 51 | + | |
| 48 | 52 | @Override |
| 49 | 53 | public void afterPropertiesSet() throws Exception { |
| 50 | 54 | queryMessageHandler.addHandler(cmdType, this); |
| ... | ... | @@ -71,10 +75,11 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 71 | 75 | List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); |
| 72 | 76 | // 回复目录信息 |
| 73 | 77 | List<PlatformCatalog> catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId()); |
| 74 | - int size = catalogs.size() + deviceChannelInPlatforms.size() + gbStreams.size(); | |
| 78 | + | |
| 79 | + List<DeviceChannel> allChannels = new ArrayList<>(); | |
| 75 | 80 | if (catalogs.size() > 0) { |
| 76 | 81 | for (PlatformCatalog catalog : catalogs) { |
| 77 | - if (catalog.getParentId().equals(parentPlatform.getServerGBId())) { | |
| 82 | + if (catalog.getParentId().equals(catalog.getPlatformId())) { | |
| 78 | 83 | catalog.setParentId(parentPlatform.getDeviceGBId()); |
| 79 | 84 | } |
| 80 | 85 | DeviceChannel deviceChannel = new DeviceChannel(); |
| ... | ... | @@ -92,9 +97,7 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 92 | 97 | deviceChannel.setModel("live"); |
| 93 | 98 | deviceChannel.setOwner("wvp-pro"); |
| 94 | 99 | deviceChannel.setSecrecy("0"); |
| 95 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 96 | - // 防止发送过快 | |
| 97 | - Thread.sleep(100); | |
| 100 | + allChannels.add(deviceChannel); | |
| 98 | 101 | } |
| 99 | 102 | } |
| 100 | 103 | // 回复级联的通道 |
| ... | ... | @@ -103,20 +106,18 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 103 | 106 | if (channel.getCatalogId().equals(parentPlatform.getServerGBId())) { |
| 104 | 107 | channel.setCatalogId(parentPlatform.getDeviceGBId()); |
| 105 | 108 | } |
| 106 | - DeviceChannel deviceChannel = storager.queryChannel(channel.getDeviceId(), channel.getChannelId()); | |
| 109 | + DeviceChannel deviceChannel = storage.queryChannel(channel.getDeviceId(), channel.getChannelId()); | |
| 107 | 110 | deviceChannel.setParental(0); |
| 108 | 111 | deviceChannel.setParentId(channel.getCatalogId()); |
| 109 | 112 | deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0, 6)); |
| 110 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 111 | - // 防止发送过快 | |
| 112 | - Thread.sleep(100); | |
| 113 | + allChannels.add(deviceChannel); | |
| 113 | 114 | } |
| 114 | 115 | } |
| 115 | 116 | // 回复直播的通道 |
| 116 | 117 | if (gbStreams.size() > 0) { |
| 117 | 118 | for (GbStream gbStream : gbStreams) { |
| 118 | 119 | if (gbStream.getCatalogId().equals(parentPlatform.getServerGBId())) { |
| 119 | - gbStream.setCatalogId(parentPlatform.getDeviceGBId()); | |
| 120 | + gbStream.setCatalogId(null); | |
| 120 | 121 | } |
| 121 | 122 | DeviceChannel deviceChannel = new DeviceChannel(); |
| 122 | 123 | deviceChannel.setChannelId(gbStream.getGbId()); |
| ... | ... | @@ -125,7 +126,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 125 | 126 | deviceChannel.setLatitude(gbStream.getLatitude()); |
| 126 | 127 | deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); |
| 127 | 128 | deviceChannel.setManufacture("wvp-pro"); |
| 128 | - deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 129 | +// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 130 | + deviceChannel.setStatus(1); | |
| 129 | 131 | deviceChannel.setParentId(gbStream.getCatalogId()); |
| 130 | 132 | deviceChannel.setRegisterWay(1); |
| 131 | 133 | deviceChannel.setCivilCode(parentPlatform.getDeviceGBId().substring(0,6)); |
| ... | ... | @@ -133,15 +135,14 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 133 | 135 | deviceChannel.setOwner("wvp-pro"); |
| 134 | 136 | deviceChannel.setParental(0); |
| 135 | 137 | deviceChannel.setSecrecy("0"); |
| 136 | - | |
| 137 | - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); | |
| 138 | - // 防止发送过快 | |
| 139 | - Thread.sleep(100); | |
| 138 | + allChannels.add(deviceChannel); | |
| 140 | 139 | } |
| 141 | 140 | } |
| 142 | - if (size == 0) { | |
| 141 | + if (allChannels.size() > 0) { | |
| 142 | + cmderFroPlatform.catalogQuery(allChannels, parentPlatform, sn, fromHeader.getTag()); | |
| 143 | + }else { | |
| 143 | 144 | // 回复无通道 |
| 144 | - cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size); | |
| 145 | + cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), 0); | |
| 145 | 146 | } |
| 146 | 147 | } catch (SipException e) { |
| 147 | 148 | e.printStackTrace(); |
| ... | ... | @@ -149,8 +150,6 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem |
| 149 | 150 | e.printStackTrace(); |
| 150 | 151 | } catch (ParseException e) { |
| 151 | 152 | e.printStackTrace(); |
| 152 | - } catch (InterruptedException e) { | |
| 153 | - e.printStackTrace(); | |
| 154 | 153 | } |
| 155 | 154 | |
| 156 | 155 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
| ... | ... | @@ -116,16 +116,15 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 116 | 116 | continue; |
| 117 | 117 | } |
| 118 | 118 | //by brewswang |
| 119 | - if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置 | |
| 120 | - processNotifyMobilePosition(evt, itemDevice); | |
| 121 | - } | |
| 122 | - | |
| 119 | +// if (NumericUtil.isDouble(XmlUtil.getText(itemDevice, "Longitude"))) {//如果包含位置信息,就更新一下位置 | |
| 120 | +// processNotifyMobilePosition(evt, itemDevice); | |
| 121 | +// } | |
| 123 | 122 | DeviceChannel deviceChannel = XmlUtil.channelContentHander(itemDevice); |
| 124 | 123 | deviceChannel.setDeviceId(device.getDeviceId()); |
| 125 | - logger.debug("收到来自设备【{}】的通道: {}【{}】", device.getDeviceId(), deviceChannel.getName(), deviceChannel.getChannelId()); | |
| 124 | + | |
| 126 | 125 | channelList.add(deviceChannel); |
| 127 | 126 | } |
| 128 | - | |
| 127 | + logger.info("收到来自设备【{}】的通道: {}个,{}/{}", device.getDeviceId(), channelList.size(), catalogDataCatch.get(key) == null ? 0 :catalogDataCatch.get(key).size(), sumNum); | |
| 129 | 128 | catalogDataCatch.put(key, sumNum, device, channelList); |
| 130 | 129 | if (catalogDataCatch.get(key).size() == sumNum) { |
| 131 | 130 | // 数据已经完整接收 |
| ... | ... | @@ -147,9 +146,6 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 147 | 146 | } |
| 148 | 147 | // 回复200 OK |
| 149 | 148 | responseAck(evt, Response.OK); |
| 150 | - if (offLineDetector.isOnline(device.getDeviceId())) { | |
| 151 | - publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE); | |
| 152 | - } | |
| 153 | 149 | } |
| 154 | 150 | } catch (DocumentException e) { |
| 155 | 151 | e.printStackTrace(); |
| ... | ... | @@ -231,4 +227,23 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp |
| 231 | 227 | e.printStackTrace(); |
| 232 | 228 | } |
| 233 | 229 | } |
| 230 | + | |
| 231 | + public SyncStatus getChannelSyncProgress(String deviceId) { | |
| 232 | + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; | |
| 233 | + if (catalogDataCatch.get(key) == null) { | |
| 234 | + return null; | |
| 235 | + }else { | |
| 236 | + return catalogDataCatch.getSyncStatus(key); | |
| 237 | + } | |
| 238 | + } | |
| 239 | + | |
| 240 | + public void setChannelSyncReady(String deviceId) { | |
| 241 | + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; | |
| 242 | + catalogDataCatch.addReady(key); | |
| 243 | + } | |
| 244 | + | |
| 245 | + public void setChannelSyncEnd(String deviceId, String errorMsg) { | |
| 246 | + String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; | |
| 247 | + catalogDataCatch.setChannelSyncEnd(key, errorMsg); | |
| 248 | + } | |
| 234 | 249 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -396,7 +396,7 @@ public class ZLMHttpHookListener { |
| 396 | 396 | } |
| 397 | 397 | } |
| 398 | 398 | if (gbStreams.size() > 0) { |
| 399 | - eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON); | |
| 399 | +// eventPublisher.catalogEventPublishForStream(null, gbStreams, CatalogEvent.ON); | |
| 400 | 400 | } |
| 401 | 401 | |
| 402 | 402 | }else { |
| ... | ... | @@ -408,7 +408,7 @@ public class ZLMHttpHookListener { |
| 408 | 408 | } |
| 409 | 409 | GbStream gbStream = storager.getGbStream(app, streamId); |
| 410 | 410 | if (gbStream != null) { |
| 411 | - eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | |
| 411 | +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); | |
| 412 | 412 | } |
| 413 | 413 | zlmMediaListManager.removeMedia(app, streamId); |
| 414 | 414 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java
| 1 | 1 | package com.genersoft.iot.vmp.service; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 4 | +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; | |
| 4 | 5 | |
| 5 | 6 | /** |
| 6 | 7 | * 设备相关业务处理 |
| ... | ... | @@ -34,4 +35,24 @@ public interface IDeviceService { |
| 34 | 35 | * @return |
| 35 | 36 | */ |
| 36 | 37 | boolean removeMobilePositionSubscribe(Device device); |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 移除移动位置订阅 | |
| 41 | + * @param deviceId 设备ID | |
| 42 | + * @return | |
| 43 | + */ | |
| 44 | + SyncStatus getChannelSyncStatus(String deviceId); | |
| 45 | + | |
| 46 | + /** | |
| 47 | + * 设置通道同步状态 | |
| 48 | + * @param deviceId 设备ID | |
| 49 | + */ | |
| 50 | + void setChannelSyncReady(String deviceId); | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * 设置同步结束 | |
| 54 | + * @param deviceId 设备ID | |
| 55 | + * @param errorMsg 错误信息 | |
| 56 | + */ | |
| 57 | + void setChannelSyncEnd(String deviceId, String errorMsg); | |
| 37 | 58 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| ... | ... | @@ -3,14 +3,19 @@ package com.genersoft.iot.vmp.service.impl; |
| 3 | 3 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; |
| 6 | +import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler; | |
| 6 | 7 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; |
| 8 | 9 | import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; |
| 10 | +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; | |
| 11 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 9 | 12 | import org.slf4j.Logger; |
| 10 | 13 | import org.slf4j.LoggerFactory; |
| 11 | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 12 | 15 | import org.springframework.stereotype.Service; |
| 13 | 16 | |
| 17 | +import javax.sip.DialogState; | |
| 18 | + | |
| 14 | 19 | /** |
| 15 | 20 | * 设备业务(目录订阅) |
| 16 | 21 | */ |
| ... | ... | @@ -25,24 +30,28 @@ public class DeviceServiceImpl implements IDeviceService { |
| 25 | 30 | @Autowired |
| 26 | 31 | private ISIPCommander sipCommander; |
| 27 | 32 | |
| 33 | + @Autowired | |
| 34 | + private CatalogResponseMessageHandler catalogResponseMessageHandler; | |
| 35 | + | |
| 36 | + @Autowired | |
| 37 | + private IRedisCatchStorage redisCatchStorage; | |
| 38 | + | |
| 28 | 39 | @Override |
| 29 | 40 | public boolean addCatalogSubscribe(Device device) { |
| 30 | 41 | if (device == null || device.getSubscribeCycleForCatalog() < 0) { |
| 31 | 42 | return false; |
| 32 | 43 | } |
| 33 | - if (dynamicTask.contains(device.getDeviceId() + "catalog")) { | |
| 34 | - // 存在则停止现有的,开启新的 | |
| 35 | - 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; | |
| 36 | 47 | } |
| 37 | 48 | logger.info("[添加目录订阅] 设备{}", device.getDeviceId()); |
| 38 | 49 | // 添加目录订阅 |
| 39 | 50 | CatalogSubscribeTask catalogSubscribeTask = new CatalogSubscribeTask(device, sipCommander); |
| 40 | - catalogSubscribeTask.run(); | |
| 41 | 51 | // 提前开始刷新订阅 |
| 42 | - int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); | |
| 52 | + int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForCatalog(),30); | |
| 43 | 53 | // 设置最小值为30 |
| 44 | - subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); | |
| 45 | - dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog); | |
| 54 | + dynamicTask.startCron(device.getDeviceId() + "catalog", catalogSubscribeTask, subscribeCycleForCatalog -1); | |
| 46 | 55 | return true; |
| 47 | 56 | } |
| 48 | 57 | |
| ... | ... | @@ -61,18 +70,16 @@ public class DeviceServiceImpl implements IDeviceService { |
| 61 | 70 | if (device == null || device.getSubscribeCycleForMobilePosition() < 0) { |
| 62 | 71 | return false; |
| 63 | 72 | } |
| 64 | - if (dynamicTask.contains(device.getDeviceId() + "mobile_position")) { | |
| 65 | - // 存在则停止现有的,开启新的 | |
| 66 | - dynamicTask.stop(device.getDeviceId() + "mobile_position"); | |
| 67 | - } | |
| 68 | 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 | + } | |
| 69 | 78 | // 添加目录订阅 |
| 70 | 79 | MobilePositionSubscribeTask mobilePositionSubscribeTask = new MobilePositionSubscribeTask(device, sipCommander); |
| 71 | - mobilePositionSubscribeTask.run(); | |
| 72 | 80 | // 提前开始刷新订阅 |
| 73 | - int subscribeCycleForCatalog = device.getSubscribeCycleForCatalog(); | |
| 74 | 81 | // 设置最小值为30 |
| 75 | - subscribeCycleForCatalog = Math.max(subscribeCycleForCatalog, 30); | |
| 82 | + int subscribeCycleForCatalog = Math.max(device.getSubscribeCycleForMobilePosition(),30); | |
| 76 | 83 | dynamicTask.startCron(device.getDeviceId() + "mobile_position" , mobilePositionSubscribeTask, subscribeCycleForCatalog -1 ); |
| 77 | 84 | return true; |
| 78 | 85 | } |
| ... | ... | @@ -86,4 +93,19 @@ public class DeviceServiceImpl implements IDeviceService { |
| 86 | 93 | dynamicTask.stop(device.getDeviceId() + "mobile_position"); |
| 87 | 94 | return true; |
| 88 | 95 | } |
| 96 | + | |
| 97 | + @Override | |
| 98 | + public SyncStatus getChannelSyncStatus(String deviceId) { | |
| 99 | + return catalogResponseMessageHandler.getChannelSyncProgress(deviceId); | |
| 100 | + } | |
| 101 | + | |
| 102 | + @Override | |
| 103 | + public void setChannelSyncReady(String deviceId) { | |
| 104 | + catalogResponseMessageHandler.setChannelSyncReady(deviceId); | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public void setChannelSyncEnd(String deviceId, String errorMsg) { | |
| 109 | + catalogResponseMessageHandler.setChannelSyncEnd(deviceId, errorMsg); | |
| 110 | + } | |
| 89 | 111 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| ... | ... | @@ -100,7 +100,8 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 100 | 100 | deviceChannel.setLatitude(gbStream.getLatitude()); |
| 101 | 101 | deviceChannel.setDeviceId(deviceGBId); |
| 102 | 102 | deviceChannel.setManufacture("wvp-pro"); |
| 103 | - deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 103 | +// deviceChannel.setStatus(gbStream.isStatus()?1:0); | |
| 104 | + deviceChannel.setStatus(1); | |
| 104 | 105 | deviceChannel.setParentId(catalogId ==null?gbStream.getCatalogId():catalogId); |
| 105 | 106 | deviceChannel.setRegisterWay(1); |
| 106 | 107 | deviceChannel.setCivilCode(deviceGBId.substring(0, 6)); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java
| ... | ... | @@ -445,8 +445,6 @@ public class VideoManagerStorageImpl implements IVideoManagerStorage { |
| 445 | 445 | device.setOnline(1); |
| 446 | 446 | logger.info("更新设备在线: " + deviceId); |
| 447 | 447 | redisCatchStorage.updateDevice(device); |
| 448 | - List<DeviceChannel> deviceChannelList = deviceChannelMapper.queryOnlineChannelsByDeviceId(deviceId); | |
| 449 | - eventPublisher.catalogEventPublish(null, deviceChannelList, CatalogEvent.ON); | |
| 450 | 448 | return deviceMapper.update(device) > 0; |
| 451 | 449 | } |
| 452 | 450 | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.utils; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * 坐标转换 | |
| 5 | + * 一个提供了百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换的工具类 | |
| 6 | + * 参考https://github.com/wandergis/coordtransform 写的Java版本 | |
| 7 | + * @author Xinconan | |
| 8 | + * @date 2016-03-18 | |
| 9 | + * @url https://github.com/xinconan/coordtransform | |
| 10 | + */ | |
| 11 | +public class Coordtransform { | |
| 12 | + | |
| 13 | + private static double x_PI = 3.14159265358979324 * 3000.0 / 180.0; | |
| 14 | + private static double PI = 3.1415926535897932384626; | |
| 15 | + private static double a = 6378245.0; | |
| 16 | + private static double ee = 0.00669342162296594323; | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换 | |
| 20 | + * 即 百度 转 谷歌、高德 | |
| 21 | + * @param bd_lon | |
| 22 | + * @param bd_lat | |
| 23 | + * @return Double[lon,lat] | |
| 24 | + */ | |
| 25 | + public static Double[] BD09ToGCJ02(Double bd_lon,Double bd_lat){ | |
| 26 | + double x = bd_lon - 0.0065; | |
| 27 | + double y = bd_lat - 0.006; | |
| 28 | + double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI); | |
| 29 | + double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI); | |
| 30 | + Double[] arr = new Double[2]; | |
| 31 | + arr[0] = z * Math.cos(theta); | |
| 32 | + arr[1] = z * Math.sin(theta); | |
| 33 | + return arr; | |
| 34 | + } | |
| 35 | + | |
| 36 | + /** | |
| 37 | + * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换 | |
| 38 | + * 即谷歌、高德 转 百度 | |
| 39 | + * @param gcj_lon | |
| 40 | + * @param gcj_lat | |
| 41 | + * @return Double[lon,lat] | |
| 42 | + */ | |
| 43 | + public static Double[] GCJ02ToBD09(Double gcj_lon,Double gcj_lat){ | |
| 44 | + double z = Math.sqrt(gcj_lon * gcj_lon + gcj_lat * gcj_lat) + 0.00002 * Math.sin(gcj_lat * x_PI); | |
| 45 | + double theta = Math.atan2(gcj_lat, gcj_lon) + 0.000003 * Math.cos(gcj_lon * x_PI); | |
| 46 | + Double[] arr = new Double[2]; | |
| 47 | + arr[0] = z * Math.cos(theta) + 0.0065; | |
| 48 | + arr[1] = z * Math.sin(theta) + 0.006; | |
| 49 | + return arr; | |
| 50 | + } | |
| 51 | + | |
| 52 | + /** | |
| 53 | + * WGS84转GCJ02 | |
| 54 | + * @param wgs_lon | |
| 55 | + * @param wgs_lat | |
| 56 | + * @return Double[lon,lat] | |
| 57 | + */ | |
| 58 | + public static Double[] WGS84ToGCJ02(Double wgs_lon,Double wgs_lat){ | |
| 59 | + if(outOfChina(wgs_lon, wgs_lat)){ | |
| 60 | + return new Double[]{wgs_lon,wgs_lat}; | |
| 61 | + } | |
| 62 | + double dlat = transformlat(wgs_lon - 105.0, wgs_lat - 35.0); | |
| 63 | + double dlng = transformlng(wgs_lon - 105.0, wgs_lat - 35.0); | |
| 64 | + double radlat = wgs_lat / 180.0 * PI; | |
| 65 | + double magic = Math.sin(radlat); | |
| 66 | + magic = 1 - ee * magic * magic; | |
| 67 | + double sqrtmagic = Math.sqrt(magic); | |
| 68 | + dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); | |
| 69 | + dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); | |
| 70 | + Double[] arr = new Double[2]; | |
| 71 | + arr[0] = wgs_lon + dlng; | |
| 72 | + arr[1] = wgs_lat + dlat; | |
| 73 | + return arr; | |
| 74 | + } | |
| 75 | + | |
| 76 | + /** | |
| 77 | + * GCJ02转WGS84 | |
| 78 | + * @param gcj_lon | |
| 79 | + * @param gcj_lat | |
| 80 | + * @return Double[lon,lat] | |
| 81 | + */ | |
| 82 | + public static Double[] GCJ02ToWGS84(Double gcj_lon,Double gcj_lat){ | |
| 83 | + if(outOfChina(gcj_lon, gcj_lat)){ | |
| 84 | + return new Double[]{gcj_lon,gcj_lat}; | |
| 85 | + } | |
| 86 | + double dlat = transformlat(gcj_lon - 105.0, gcj_lat - 35.0); | |
| 87 | + double dlng = transformlng(gcj_lon - 105.0, gcj_lat - 35.0); | |
| 88 | + double radlat = gcj_lat / 180.0 * PI; | |
| 89 | + double magic = Math.sin(radlat); | |
| 90 | + magic = 1 - ee * magic * magic; | |
| 91 | + double sqrtmagic = Math.sqrt(magic); | |
| 92 | + dlat = (dlat * 180.0) / ((a * (1 - ee)) / (magic * sqrtmagic) * PI); | |
| 93 | + dlng = (dlng * 180.0) / (a / sqrtmagic * Math.cos(radlat) * PI); | |
| 94 | + double mglat = gcj_lat + dlat; | |
| 95 | + double mglng = gcj_lon + dlng; | |
| 96 | + return new Double[]{gcj_lon * 2 - mglng, gcj_lat * 2 - mglat}; | |
| 97 | + } | |
| 98 | + | |
| 99 | + private static Double transformlat(double lng, double lat) { | |
| 100 | + double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng)); | |
| 101 | + ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; | |
| 102 | + ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0; | |
| 103 | + ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0; | |
| 104 | + return ret; | |
| 105 | + } | |
| 106 | + | |
| 107 | + private static Double transformlng(double lng,double lat) { | |
| 108 | + double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng)); | |
| 109 | + ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0; | |
| 110 | + ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0; | |
| 111 | + ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0; | |
| 112 | + return ret; | |
| 113 | + } | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * outOfChina | |
| 117 | + * @描述: 判断是否在国内,不在国内则不做偏移 | |
| 118 | + * @param lng | |
| 119 | + * @param lat | |
| 120 | + * @return {boolean} | |
| 121 | + */ | |
| 122 | + private static boolean outOfChina(Double lng,Double lat) { | |
| 123 | + return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false); | |
| 124 | + }; | |
| 125 | + | |
| 126 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java
| ... | ... | @@ -17,48 +17,57 @@ public class GpsUtil { |
| 17 | 17 | public static BaiduPoint Wgs84ToBd09(String xx, String yy) { |
| 18 | 18 | |
| 19 | 19 | |
| 20 | - try { | |
| 21 | - Socket s = new Socket("api.map.baidu.com", 80); | |
| 22 | - BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); | |
| 23 | - OutputStream out = s.getOutputStream(); | |
| 24 | - StringBuffer sb = new StringBuffer("GET /ag/coord/convert?from=0&to=4"); | |
| 25 | - sb.append("&x=" + xx + "&y=" + yy); | |
| 26 | - sb.append("&callback=BMap.Convertor.cbk_3976 HTTP/1.1\r\n"); | |
| 27 | - sb.append("User-Agent: Java/1.6.0_20\r\n"); | |
| 28 | - sb.append("Host: api.map.baidu.com:80\r\n"); | |
| 29 | - sb.append("Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n"); | |
| 30 | - sb.append("Connection: Close\r\n"); | |
| 31 | - sb.append("\r\n"); | |
| 32 | - out.write(sb.toString().getBytes()); | |
| 33 | - String json = ""; | |
| 34 | - String tmp = ""; | |
| 35 | - while ((tmp = br.readLine()) != null) { | |
| 36 | - // logger.info(tmp); | |
| 37 | - json += tmp; | |
| 38 | - } | |
| 20 | +// try { | |
| 21 | +// Socket s = new Socket("api.map.baidu.com", 80); | |
| 22 | +// BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8")); | |
| 23 | +// OutputStream out = s.getOutputStream(); | |
| 24 | +// StringBuffer sb = new StringBuffer("GET /ag/coord/convert?from=0&to=4"); | |
| 25 | +// sb.append("&x=" + xx + "&y=" + yy); | |
| 26 | +// sb.append("&callback=BMap.Convertor.cbk_3976 HTTP/1.1\r\n"); | |
| 27 | +// sb.append("User-Agent: Java/1.6.0_20\r\n"); | |
| 28 | +// sb.append("Host: api.map.baidu.com:80\r\n"); | |
| 29 | +// sb.append("Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n"); | |
| 30 | +// sb.append("Connection: Close\r\n"); | |
| 31 | +// sb.append("\r\n"); | |
| 32 | +// out.write(sb.toString().getBytes()); | |
| 33 | +// String json = ""; | |
| 34 | +// String tmp = ""; | |
| 35 | +// while ((tmp = br.readLine()) != null) { | |
| 36 | +// // logger.info(tmp); | |
| 37 | +// json += tmp; | |
| 38 | +// } | |
| 39 | +// | |
| 40 | +// s.close(); | |
| 41 | +// int start = json.indexOf("cbk_3976"); | |
| 42 | +// int end = json.lastIndexOf("}"); | |
| 43 | +// if (start != -1 && end != -1 && json.contains("\"x\":\"")) { | |
| 44 | +// json = json.substring(start, end); | |
| 45 | +// String[] point = json.split(","); | |
| 46 | +// String x = point[1].split(":")[1].replace("\"", ""); | |
| 47 | +// String y = point[2].split(":")[1].replace("\"", ""); | |
| 48 | +// BaiduPoint bdPoint= new BaiduPoint(); | |
| 49 | +// bdPoint.setBdLng(new String(decode(x))); | |
| 50 | +// bdPoint.setBdLat(new String(decode(y))); | |
| 51 | +// return bdPoint; | |
| 52 | +// //return (new String(decode(x)) + "," + new String(decode(y))); | |
| 53 | +// } else { | |
| 54 | +// logger.info("gps坐标无效!!"); | |
| 55 | +// } | |
| 56 | +// out.close(); | |
| 57 | +// br.close(); | |
| 58 | +// } catch (Exception e) { | |
| 59 | +// e.printStackTrace(); | |
| 60 | +// } | |
| 39 | 61 | |
| 40 | - s.close(); | |
| 41 | - int start = json.indexOf("cbk_3976"); | |
| 42 | - int end = json.lastIndexOf("}"); | |
| 43 | - if (start != -1 && end != -1 && json.contains("\"x\":\"")) { | |
| 44 | - json = json.substring(start, end); | |
| 45 | - String[] point = json.split(","); | |
| 46 | - String x = point[1].split(":")[1].replace("\"", ""); | |
| 47 | - String y = point[2].split(":")[1].replace("\"", ""); | |
| 48 | - BaiduPoint bdPoint= new BaiduPoint(); | |
| 49 | - bdPoint.setBdLng(new String(decode(x))); | |
| 50 | - bdPoint.setBdLat(new String(decode(y))); | |
| 51 | - return bdPoint; | |
| 52 | - //return (new String(decode(x)) + "," + new String(decode(y))); | |
| 53 | - } else { | |
| 54 | - logger.info("gps坐标无效!!"); | |
| 55 | - } | |
| 56 | - out.close(); | |
| 57 | - br.close(); | |
| 58 | - } catch (Exception e) { | |
| 59 | - e.printStackTrace(); | |
| 60 | - } | |
| 61 | - return null; | |
| 62 | + | |
| 63 | + double lng = Double.parseDouble(xx); | |
| 64 | + double lat = Double.parseDouble(yy); | |
| 65 | + Double[] gcj02 = Coordtransform.WGS84ToGCJ02(lng, lat); | |
| 66 | + Double[] doubles = Coordtransform.GCJ02ToBD09(gcj02[0], gcj02[1]); | |
| 67 | + BaiduPoint bdPoint= new BaiduPoint(); | |
| 68 | + bdPoint.setBdLng(doubles[0] + ""); | |
| 69 | + bdPoint.setBdLat(doubles[1] + ""); | |
| 70 | + return bdPoint; | |
| 62 | 71 | } |
| 63 | 72 | |
| 64 | 73 | /** | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
| ... | ... | @@ -4,7 +4,13 @@ import com.alibaba.fastjson.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; | |
| 8 | +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; | |
| 7 | 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; | |
| 8 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 9 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 10 | 16 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| ... | ... | @@ -18,6 +24,7 @@ import io.swagger.annotations.Api; |
| 18 | 24 | import io.swagger.annotations.ApiImplicitParam; |
| 19 | 25 | import io.swagger.annotations.ApiImplicitParams; |
| 20 | 26 | import io.swagger.annotations.ApiOperation; |
| 27 | +import org.kxml2.wap.wv.WV; | |
| 21 | 28 | import org.slf4j.Logger; |
| 22 | 29 | import org.slf4j.LoggerFactory; |
| 23 | 30 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -27,9 +34,8 @@ import org.springframework.util.StringUtils; |
| 27 | 34 | import org.springframework.web.bind.annotation.*; |
| 28 | 35 | import org.springframework.web.context.request.async.DeferredResult; |
| 29 | 36 | |
| 30 | -import java.util.List; | |
| 31 | -import java.util.Set; | |
| 32 | -import java.util.UUID; | |
| 37 | +import javax.sip.DialogState; | |
| 38 | +import java.util.*; | |
| 33 | 39 | |
| 34 | 40 | @Api(tags = "国标设备查询", value = "国标设备查询") |
| 35 | 41 | @SuppressWarnings("rawtypes") |
| ... | ... | @@ -61,6 +67,9 @@ public class DeviceQuery { |
| 61 | 67 | @Autowired |
| 62 | 68 | private DynamicTask dynamicTask; |
| 63 | 69 | |
| 70 | + @Autowired | |
| 71 | + private SubscribeHolder subscribeHolder; | |
| 72 | + | |
| 64 | 73 | /** |
| 65 | 74 | * 使用ID查询国标设备 |
| 66 | 75 | * @param deviceId 国标ID |
| ... | ... | @@ -149,48 +158,30 @@ public class DeviceQuery { |
| 149 | 158 | @ApiImplicitParam(name="deviceId", value = "设备id", required = true, dataTypeClass = String.class), |
| 150 | 159 | }) |
| 151 | 160 | @PostMapping("/devices/{deviceId}/sync") |
| 152 | - public DeferredResult<ResponseEntity<Device>> devicesSync(@PathVariable String deviceId){ | |
| 161 | + public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId){ | |
| 153 | 162 | |
| 154 | 163 | if (logger.isDebugEnabled()) { |
| 155 | 164 | logger.debug("设备通道信息同步API调用,deviceId:" + deviceId); |
| 156 | 165 | } |
| 157 | 166 | Device device = storager.queryVideoDevice(deviceId); |
| 158 | - String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + deviceId; | |
| 159 | - String uuid = UUID.randomUUID().toString(); | |
| 160 | - // 默认超时时间为30分钟 | |
| 161 | - DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(30*60*1000L); | |
| 162 | - result.onTimeout(()->{ | |
| 163 | - logger.warn("设备[{}]通道信息同步超时", deviceId); | |
| 164 | - // 释放rtpserver | |
| 165 | - RequestMessage msg = new RequestMessage(); | |
| 166 | - msg.setKey(key); | |
| 167 | - msg.setId(uuid); | |
| 168 | - WVPResult<Object> wvpResult = new WVPResult<>(); | |
| 169 | - wvpResult.setCode(-1); | |
| 170 | - wvpResult.setData(device); | |
| 171 | - wvpResult.setMsg("更新超时"); | |
| 172 | - msg.setData(wvpResult); | |
| 173 | - resultHolder.invokeAllResult(msg); | |
| 174 | - | |
| 175 | - }); | |
| 176 | - // 等待其他相同请求返回时一起返回 | |
| 177 | - if (resultHolder.exist(key, null)) { | |
| 178 | - return result; | |
| 167 | + SyncStatus syncStatus = deviceService.getChannelSyncStatus(deviceId); | |
| 168 | + // 已存在则返回进度 | |
| 169 | + if (syncStatus != null && syncStatus.getErrorMsg() == null) { | |
| 170 | + WVPResult<SyncStatus> wvpResult = new WVPResult<>(); | |
| 171 | + wvpResult.setCode(0); | |
| 172 | + wvpResult.setData(syncStatus); | |
| 173 | + return wvpResult; | |
| 179 | 174 | } |
| 180 | - cmder.catalogQuery(device, event -> { | |
| 181 | - RequestMessage msg = new RequestMessage(); | |
| 182 | - msg.setKey(key); | |
| 183 | - msg.setId(uuid); | |
| 184 | - WVPResult<Object> wvpResult = new WVPResult<>(); | |
| 185 | - wvpResult.setCode(-1); | |
| 186 | - wvpResult.setData(device); | |
| 187 | - wvpResult.setMsg(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg)); | |
| 188 | - msg.setData(wvpResult); | |
| 189 | - resultHolder.invokeAllResult(msg); | |
| 175 | + SyncStatus syncStatusReady = new SyncStatus(); | |
| 176 | + deviceService.setChannelSyncReady(deviceId); | |
| 177 | + cmder.catalogQuery(device, event -> { | |
| 178 | + String errorMsg = String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg); | |
| 179 | + deviceService.setChannelSyncEnd(deviceId, errorMsg); | |
| 190 | 180 | }); |
| 191 | - | |
| 192 | - resultHolder.put(key, uuid, result); | |
| 193 | - return result; | |
| 181 | + WVPResult<SyncStatus> wvpResult = new WVPResult<>(); | |
| 182 | + wvpResult.setCode(0); | |
| 183 | + wvpResult.setMsg("开始同步"); | |
| 184 | + return wvpResult; | |
| 194 | 185 | } |
| 195 | 186 | |
| 196 | 187 | /** |
| ... | ... | @@ -467,4 +458,47 @@ public class DeviceQuery { |
| 467 | 458 | public WVPResult<List<DeviceChannelTree>> tree(@PathVariable String deviceId) { |
| 468 | 459 | return WVPResult.Data(storager.tree(deviceId)); |
| 469 | 460 | } |
| 461 | + | |
| 462 | + @GetMapping("/{deviceId}/sync_status") | |
| 463 | + @ApiOperation(value = "获取通道同步进度", notes = "获取通道同步进度") | |
| 464 | + public WVPResult<SyncStatus> getSyncStatus(@PathVariable String deviceId) { | |
| 465 | + SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId); | |
| 466 | + WVPResult<SyncStatus> wvpResult = new WVPResult<>(); | |
| 467 | + if (channelSyncStatus == null) { | |
| 468 | + wvpResult.setCode(-1); | |
| 469 | + wvpResult.setMsg("同步尚未开始"); | |
| 470 | + }else { | |
| 471 | + wvpResult.setCode(0); | |
| 472 | + wvpResult.setData(channelSyncStatus); | |
| 473 | + if (channelSyncStatus.getErrorMsg() != null) { | |
| 474 | + wvpResult.setMsg(channelSyncStatus.getErrorMsg()); | |
| 475 | + } | |
| 476 | + } | |
| 477 | + return wvpResult; | |
| 478 | + } | |
| 479 | + | |
| 480 | + @GetMapping("/{deviceId}/subscribe_info") | |
| 481 | + @ApiOperation(value = "获取设备的订阅状态", notes = "获取设备的订阅状态") | |
| 482 | + public WVPResult<Map<String, String>> getSubscribeInfo(@PathVariable String deviceId) { | |
| 483 | + Set<String> allKeys = dynamicTask.getAllKeys(); | |
| 484 | + Map<String, String> dialogStateMap = new HashMap<>(); | |
| 485 | + for (String key : allKeys) { | |
| 486 | + if (key.startsWith(deviceId)) { | |
| 487 | + ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key); | |
| 488 | + DialogState dialogState = subscribeTask.getDialogState(); | |
| 489 | + if (dialogState == null) { | |
| 490 | + continue; | |
| 491 | + } | |
| 492 | + if (subscribeTask instanceof CatalogSubscribeTask) { | |
| 493 | + dialogStateMap.put("catalog", dialogState.toString()); | |
| 494 | + }else if (subscribeTask instanceof MobilePositionSubscribeTask) { | |
| 495 | + dialogStateMap.put("mobilePosition", dialogState.toString()); | |
| 496 | + } | |
| 497 | + } | |
| 498 | + } | |
| 499 | + WVPResult<Map<String, String>> wvpResult = new WVPResult<>(); | |
| 500 | + wvpResult.setCode(0); | |
| 501 | + wvpResult.setData(dialogStateMap); | |
| 502 | + return wvpResult; | |
| 503 | + } | |
| 470 | 504 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
| ... | ... | @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON; |
| 4 | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | 5 | import com.genersoft.iot.vmp.VManageBootstrap; |
| 6 | 6 | import com.genersoft.iot.vmp.common.VersionPo; |
| 7 | +import com.genersoft.iot.vmp.conf.DynamicTask; | |
| 7 | 8 | import com.genersoft.iot.vmp.conf.SipConfig; |
| 8 | 9 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 9 | 10 | import com.genersoft.iot.vmp.conf.VersionInfo; |
| ... | ... | @@ -27,6 +28,7 @@ import javax.sip.ObjectInUseException; |
| 27 | 28 | import javax.sip.SipProvider; |
| 28 | 29 | import java.util.Iterator; |
| 29 | 30 | import java.util.List; |
| 31 | +import java.util.Set; | |
| 30 | 32 | |
| 31 | 33 | @SuppressWarnings("rawtypes") |
| 32 | 34 | @Api(tags = "服务控制") |
| ... | ... | @@ -42,13 +44,16 @@ public class ServerController { |
| 42 | 44 | private IMediaServerService mediaServerService; |
| 43 | 45 | |
| 44 | 46 | @Autowired |
| 45 | - VersionInfo versionInfo; | |
| 47 | + private VersionInfo versionInfo; | |
| 46 | 48 | |
| 47 | 49 | @Autowired |
| 48 | - SipConfig sipConfig; | |
| 50 | + private SipConfig sipConfig; | |
| 49 | 51 | |
| 50 | 52 | @Autowired |
| 51 | - UserSetting userSetting; | |
| 53 | + private UserSetting userSetting; | |
| 54 | + | |
| 55 | + @Autowired | |
| 56 | + private DynamicTask dynamicTask; | |
| 52 | 57 | |
| 53 | 58 | @Value("${server.port}") |
| 54 | 59 | private int serverPort; |
| ... | ... | @@ -248,4 +253,35 @@ public class ServerController { |
| 248 | 253 | result.setData(jsonObject); |
| 249 | 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/DeviceList.vue
| ... | ... | @@ -57,7 +57,7 @@ |
| 57 | 57 | |
| 58 | 58 | <el-table-column label="操作" width="450" align="center" fixed="right"> |
| 59 | 59 | <template slot-scope="scope"> |
| 60 | - <el-button size="mini" :loading="scope.row.loading" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)">刷新</el-button> | |
| 60 | + <el-button size="mini" v-if="scope.row.online!=0" icon="el-icon-refresh" @click="refDevice(scope.row)" @mouseover="getTooltipContent(scope.row.deviceId)">刷新</el-button> | |
| 61 | 61 | <el-button-group> |
| 62 | 62 | <el-button size="mini" icon="el-icon-video-camera-solid" v-bind:disabled="scope.row.online==0" type="primary" @click="showChannelList(scope.row)">通道</el-button> |
| 63 | 63 | <el-button size="mini" icon="el-icon-location" v-bind:disabled="scope.row.online==0" type="primary" @click="showDevicePosition(scope.row)">定位</el-button> |
| ... | ... | @@ -78,6 +78,7 @@ |
| 78 | 78 | :total="total"> |
| 79 | 79 | </el-pagination> |
| 80 | 80 | <deviceEdit ref="deviceEdit" ></deviceEdit> |
| 81 | + <syncChannelProgress ref="syncChannelProgress" ></syncChannelProgress> | |
| 81 | 82 | </el-main> |
| 82 | 83 | </el-container> |
| 83 | 84 | </div> |
| ... | ... | @@ -86,11 +87,13 @@ |
| 86 | 87 | <script> |
| 87 | 88 | import uiHeader from './UiHeader.vue' |
| 88 | 89 | import deviceEdit from './dialog/deviceEdit.vue' |
| 90 | + import syncChannelProgress from './dialog/SyncChannelProgress.vue' | |
| 89 | 91 | export default { |
| 90 | 92 | name: 'app', |
| 91 | 93 | components: { |
| 92 | 94 | uiHeader, |
| 93 | - deviceEdit | |
| 95 | + deviceEdit, | |
| 96 | + syncChannelProgress, | |
| 94 | 97 | }, |
| 95 | 98 | data() { |
| 96 | 99 | return { |
| ... | ... | @@ -104,7 +107,7 @@ |
| 104 | 107 | currentPage:1, |
| 105 | 108 | count:15, |
| 106 | 109 | total:0, |
| 107 | - getDeviceListLoading: false | |
| 110 | + getDeviceListLoading: false, | |
| 108 | 111 | }; |
| 109 | 112 | }, |
| 110 | 113 | computed: { |
| ... | ... | @@ -117,8 +120,6 @@ |
| 117 | 120 | }); |
| 118 | 121 | this.currentDeviceChannelsLenth = channels.length; |
| 119 | 122 | } |
| 120 | - | |
| 121 | - console.log("数据:" + JSON.stringify(channels)); | |
| 122 | 123 | return channels; |
| 123 | 124 | } |
| 124 | 125 | }, |
| ... | ... | @@ -153,13 +154,11 @@ |
| 153 | 154 | count: that.count |
| 154 | 155 | } |
| 155 | 156 | }).then(function (res) { |
| 156 | - console.log(res); | |
| 157 | - console.log(res.data.list); | |
| 158 | 157 | that.total = res.data.total; |
| 159 | 158 | that.deviceList = res.data.list; |
| 160 | 159 | that.getDeviceListLoading = false; |
| 161 | 160 | }).catch(function (error) { |
| 162 | - console.log(error); | |
| 161 | + console.error(error); | |
| 163 | 162 | that.getDeviceListLoading = false; |
| 164 | 163 | }); |
| 165 | 164 | |
| ... | ... | @@ -182,7 +181,7 @@ |
| 182 | 181 | }).then((res)=>{ |
| 183 | 182 | this.getDeviceList(); |
| 184 | 183 | }).catch((error) =>{ |
| 185 | - console.log(error); | |
| 184 | + console.error(error); | |
| 186 | 185 | }); |
| 187 | 186 | }).catch(() => { |
| 188 | 187 | |
| ... | ... | @@ -191,11 +190,9 @@ |
| 191 | 190 | |
| 192 | 191 | }, |
| 193 | 192 | showChannelList: function(row) { |
| 194 | - console.log(JSON.stringify(row)) | |
| 195 | 193 | this.$router.push(`/channelList/${row.deviceId}/0/15/1`); |
| 196 | 194 | }, |
| 197 | 195 | showDevicePosition: function(row) { |
| 198 | - console.log(JSON.stringify(row)) | |
| 199 | 196 | this.$router.push(`/devicePosition/${row.deviceId}/0/15/1`); |
| 200 | 197 | }, |
| 201 | 198 | |
| ... | ... | @@ -203,12 +200,11 @@ |
| 203 | 200 | //刷新设备信息 |
| 204 | 201 | refDevice: function(itemData) { |
| 205 | 202 | console.log("刷新对应设备:" + itemData.deviceId); |
| 206 | - var that = this; | |
| 207 | - that.$set(itemData,"loading", true); | |
| 203 | + let that = this; | |
| 208 | 204 | this.$axios({ |
| 209 | 205 | method: 'post', |
| 210 | 206 | url: '/api/device/query/devices/' + itemData.deviceId + '/sync' |
| 211 | - }).then(function(res) { | |
| 207 | + }).then((res) => { | |
| 212 | 208 | console.log("刷新设备结果:"+JSON.stringify(res)); |
| 213 | 209 | if (res.data.code !==0) { |
| 214 | 210 | that.$message({ |
| ... | ... | @@ -217,24 +213,44 @@ |
| 217 | 213 | type: 'error' |
| 218 | 214 | }); |
| 219 | 215 | }else{ |
| 220 | - that.$message({ | |
| 221 | - showClose: true, | |
| 222 | - message: res.data.msg, | |
| 223 | - type: 'success' | |
| 224 | - }); | |
| 216 | + // that.$message({ | |
| 217 | + // showClose: true, | |
| 218 | + // message: res.data.msg, | |
| 219 | + // type: 'success' | |
| 220 | + // }); | |
| 221 | + this.$refs.syncChannelProgress.openDialog(itemData.deviceId) | |
| 225 | 222 | } |
| 226 | 223 | that.initData() |
| 227 | - that.$set(itemData,"loading", true); | |
| 228 | - }).catch(function(e) { | |
| 224 | + }).catch((e) => { | |
| 229 | 225 | console.error(e) |
| 230 | 226 | that.$message({ |
| 231 | 227 | showClose: true, |
| 232 | 228 | message: e, |
| 233 | 229 | type: 'error' |
| 234 | 230 | }); |
| 235 | - that.$set(itemData,"loading", true); | |
| 236 | 231 | }); |
| 232 | + | |
| 237 | 233 | }, |
| 234 | + | |
| 235 | + getTooltipContent: async function (deviceId){ | |
| 236 | + let result = ""; | |
| 237 | + await this.$axios({ | |
| 238 | + method: 'get', | |
| 239 | + async: false, | |
| 240 | + url:`/api/device/query/${deviceId}/sync_status/`, | |
| 241 | + }).then((res) => { | |
| 242 | + if (res.data.code == 0) { | |
| 243 | + if (res.data.data.errorMsg !== null) { | |
| 244 | + result = res.data.data.errorMsg | |
| 245 | + } else if (res.data.msg !== null) { | |
| 246 | + result = res.data.msg | |
| 247 | + } else { | |
| 248 | + result = `同步中...[${res.data.data.current}/${res.data.data.total}]`; | |
| 249 | + } | |
| 250 | + } | |
| 251 | + }) | |
| 252 | + return result; | |
| 253 | + }, | |
| 238 | 254 | //通知设备上传媒体流 |
| 239 | 255 | sendDevicePush: function(itemData) { |
| 240 | 256 | // let deviceId = this.currentDevice.deviceId; |
| ... | ... | @@ -251,7 +267,6 @@ |
| 251 | 267 | // }); |
| 252 | 268 | }, |
| 253 | 269 | transportChange: function (row) { |
| 254 | - console.log(row); | |
| 255 | 270 | console.log(`修改传输方式为 ${row.streamMode}:${row.deviceId} `); |
| 256 | 271 | let that = this; |
| 257 | 272 | this.$axios({ |
| ... | ... | @@ -263,7 +278,6 @@ |
| 263 | 278 | }); |
| 264 | 279 | }, |
| 265 | 280 | edit: function (row) { |
| 266 | - console.log(row); | |
| 267 | 281 | this.$refs.deviceEdit.openDialog(row, ()=>{ |
| 268 | 282 | this.$refs.deviceEdit.close(); |
| 269 | 283 | this.$message({ | ... | ... |
web_src/src/components/dialog/SyncChannelProgress.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <div id="SyncChannelProgress" v-loading="isLoging"> | |
| 3 | + <el-dialog | |
| 4 | + width="240px" | |
| 5 | + top="13%" | |
| 6 | + :append-to-body="true" | |
| 7 | + :close-on-click-modal="false" | |
| 8 | + :visible.sync="showDialog" | |
| 9 | + :destroy-on-close="true" | |
| 10 | + :show-close="true" | |
| 11 | + @close="close()" | |
| 12 | + style="text-align: center"> | |
| 13 | + <el-progress type="circle" :percentage="percentage" :status="syncStatus"></el-progress> | |
| 14 | + <div style="text-align: center"> | |
| 15 | + {{msg}} | |
| 16 | + </div> | |
| 17 | + </el-dialog> | |
| 18 | + </div> | |
| 19 | +</template> | |
| 20 | + | |
| 21 | +<script> | |
| 22 | + | |
| 23 | +export default { | |
| 24 | + name: "SyncChannelProgress", | |
| 25 | + computed: {}, | |
| 26 | + props: ['platformId'], | |
| 27 | + created() {}, | |
| 28 | + data() { | |
| 29 | + return { | |
| 30 | + syncStatus: null, | |
| 31 | + percentage: 0, | |
| 32 | + total: 0, | |
| 33 | + current: 0, | |
| 34 | + showDialog: false, | |
| 35 | + isLoging: false, | |
| 36 | + syncFlag: false, | |
| 37 | + deviceId: null, | |
| 38 | + timmer: null, | |
| 39 | + msg: "正在同步", | |
| 40 | + }; | |
| 41 | + }, | |
| 42 | + methods: { | |
| 43 | + openDialog: function (deviceId) { | |
| 44 | + console.log("deviceId: " + deviceId) | |
| 45 | + this.deviceId = deviceId; | |
| 46 | + this.showDialog = true; | |
| 47 | + this.msg = ""; | |
| 48 | + this.percentage= 0; | |
| 49 | + this.total= 0; | |
| 50 | + this.current= 0; | |
| 51 | + this.syncFlag= false; | |
| 52 | + this.syncStatus = null; | |
| 53 | + this.getProgress() | |
| 54 | + }, | |
| 55 | + getProgress(){ | |
| 56 | + this.$axios({ | |
| 57 | + method: 'get', | |
| 58 | + url:`/api/device/query/${this.deviceId}/sync_status/`, | |
| 59 | + }).then((res) => { | |
| 60 | + if (res.data.code == 0) { | |
| 61 | + if (!this.syncFlag) { | |
| 62 | + this.syncFlag = true; | |
| 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) | |
| 80 | + } | |
| 81 | + }else { | |
| 82 | + if (this.syncFlag) { | |
| 83 | + this.syncStatus = "success" | |
| 84 | + this.percentage = 100; | |
| 85 | + this.msg = '同步成功'; | |
| 86 | + }else { | |
| 87 | + this.syncStatus = "error" | |
| 88 | + this.msg = res.data.msg; | |
| 89 | + } | |
| 90 | + } | |
| 91 | + }).catch((error) =>{ | |
| 92 | + console.log(error); | |
| 93 | + this.syncStatus = "error" | |
| 94 | + this.msg = error.response.data.msg; | |
| 95 | + }); | |
| 96 | + }, | |
| 97 | + close: function (){ | |
| 98 | + window.clearTimeout(this.timmer) | |
| 99 | + } | |
| 100 | + }, | |
| 101 | +}; | |
| 102 | +</script> | ... | ... |