Pārlūkot izejas kodu

完成向上级联->保活

panlinlin 4 gadi atpakaļ
vecāks
revīzija
627a14f37e
28 mainītis faili ar 736 papildinājumiem un 67 dzēšanām
  1. 1 1
      README.md
  2. 9 1
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  3. 46 46
      src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
  4. 36 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java
  5. 15 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java
  6. 11 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
  7. 64 0
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
  8. 23 0
      src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEvent.java
  9. 85 0
      src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java
  10. 6 3
      src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
  11. 8 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
  12. 9 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java
  13. 150 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
  14. 34 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  15. 40 4
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  16. 1 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
  17. 19 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java
  18. 12 0
      src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
  19. 38 0
      src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
  20. 3 0
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
  21. 2 0
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
  22. 54 0
      src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java
  23. 26 0
      src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
  24. 40 2
      src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java
  25. 2 6
      src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java
  26. BIN
      src/main/resources/wvp.sqlite
  27. 1 1
      web_src/src/components/ParentPlatformList.vue
  28. 1 1
      web_src/src/router/index.js

+ 1 - 1
README.md

@@ -39,7 +39,7 @@ https://gitee.com/18010473990/wvp-GB28181.git
 - [ ] 国标通道向上级联  
     - [X] WEB添加上级平台
     - [X] 注册
-    - [ ] 心跳保活
+    - [X] 心跳保活
     - [ ] 通道选择
     - [ ] 通道推送
     - [ ] 点播

+ 9 - 1
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@@ -20,7 +20,15 @@ public class VideoManagerConstants {
 
 	public static final String PLAY_BLACK_PREFIX = "VMP_playback_";
 
-	public static final String PLATFORM_PREFIX = "VMP_platform_";
+	public static final String PLATFORM_PREFIX = "VMP_platform";
+
+	public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_";
+
+	public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_";
+
+	public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
+
+	public static final String Pattern_Topic = "VMP_keeplive_platform_";
 
 	public static final String EVENT_ONLINE_REGISTER = "1";
 	

+ 46 - 46
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java

@@ -1,28 +1,28 @@
 /*
-* Conditions Of Use
-*
-* This software was developed by employees of the National Institute of
-* Standards and Technology (NIST), an agency of the Federal Government.
-* Pursuant to title 15 Untied States Code Section 105, works of NIST
-* employees are not subject to copyright protection in the United States
-* and are considered to be in the public domain.  As a result, a formal
-* license is not needed to use the software.
-*
-* This software is provided by NIST as a service and is expressly
-* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
-* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
-* AND DATA ACCURACY.  NIST does not warrant or make any representations
-* regarding the use of the software or the results thereof, including but
-* not limited to the correctness, accuracy, reliability or usefulness of
-* the software.
-*
-* Permission to use this software is contingent upon your acceptance
-* of the terms of this agreement
-*
-* .
-*
-*/
+ * Conditions Of Use
+ *
+ * This software was developed by employees of the National Institute of
+ * Standards and Technology (NIST), an agency of the Federal Government.
+ * Pursuant to title 15 Untied States Code Section 105, works of NIST
+ * employees are not subject to copyright protection in the United States
+ * and are considered to be in the public domain.  As a result, a formal
+ * license is not needed to use the software.
+ *
+ * This software is provided by NIST as a service and is expressly
+ * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
+ * AND DATA ACCURACY.  NIST does not warrant or make any representations
+ * regarding the use of the software or the results thereof, including but
+ * not limited to the correctness, accuracy, reliability or usefulness of
+ * the software.
+ *
+ * Permission to use this software is contingent upon your acceptance
+ * of the terms of this agreement
+ *
+ * .
+ *
+ */
 package com.genersoft.iot.vmp.gb28181.auth;
 
 import java.security.MessageDigest;
@@ -42,18 +42,18 @@ import gov.nist.core.InternalErrorHandler;
 
 /**
  * Implements the HTTP digest authentication method server side functionality.
- * 
+ *
  * @author M. Ranganathan
  * @author Marc Bednarek
  */
 
 public class DigestServerAuthenticationHelper  {
-    
+
     private MessageDigest messageDigest;
-    
+
     public static final String DEFAULT_ALGORITHM = "MD5";
     public static final String DEFAULT_SCHEME = "Digest";
-    
+
 
 
 
@@ -63,11 +63,11 @@ public class DigestServerAuthenticationHelper  {
 
     /**
      * Default constructor.
-     * @throws NoSuchAlgorithmException 
+     * @throws NoSuchAlgorithmException
      */
-    public DigestServerAuthenticationHelper() 
-        throws NoSuchAlgorithmException {
-            messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
+    public DigestServerAuthenticationHelper()
+            throws NoSuchAlgorithmException {
+        messageDigest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
     }
 
     public static String toHexString(byte b[]) {
@@ -79,7 +79,7 @@ public class DigestServerAuthenticationHelper  {
         }
         return new String(c);
     }
-    
+
     /**
      * Generate the challenge string.
      *
@@ -121,34 +121,34 @@ public class DigestServerAuthenticationHelper  {
      *
      * @param request - the request to authenticate.
      * @param hashedPassword -- the MD5 hashed string of username:realm:plaintext password.
-     * 
+     *
      * @return true if authentication succeded and false otherwise.
      */
     public boolean doAuthenticateHashedPassword(Request request, String hashedPassword) {
-    	AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
+        AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
         if ( authHeader == null ) return false;
         String realm = authHeader.getRealm();
         String username = authHeader.getUsername();
-      
+
         if ( username == null || realm == null ) {
             return false;
         }
-       
+
         String nonce = authHeader.getNonce();
         URI uri = authHeader.getURI();
         if (uri == null) {
             return false;
         }
-        
 
-      
+
+
         String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
         String HA1 = hashedPassword;
 
-       
+
         byte[] mdbytes = messageDigest.digest(A2.getBytes());
         String HA2 = toHexString(mdbytes);
-      
+
         String cnonce = authHeader.getCNonce();
         String KD = HA1 + ":" + nonce;
         if (cnonce != null) {
@@ -158,7 +158,7 @@ public class DigestServerAuthenticationHelper  {
         mdbytes = messageDigest.digest(KD.getBytes());
         String mdString = toHexString(mdbytes);
         String response = authHeader.getResponse();
-       
+
 
         return mdString.equals(response);
     }
@@ -168,11 +168,11 @@ public class DigestServerAuthenticationHelper  {
      *
      * @param request - the request to authenticate.
      * @param pass -- the plain text password.
-     * 
+     *
      * @return true if authentication succeded and false otherwise.
      */
     public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
-    	AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
+        AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
         if ( authHeader == null ) return false;
         String realm = authHeader.getRealm().trim();
         String username = authHeader.getUsername().trim();
@@ -184,7 +184,7 @@ public class DigestServerAuthenticationHelper  {
         String nonce = authHeader.getNonce();
         URI uri = authHeader.getURI();
         if (uri == null) {
-           return false;
+            return false;
         }
         // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
         String qop = authHeader.getQop();
@@ -233,7 +233,7 @@ public class DigestServerAuthenticationHelper  {
         String response = authHeader.getResponse();
         System.out.println("response: " + response);
         return mdString.equals(response);
-        
+
     }
 
 

+ 36 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java

@@ -0,0 +1,36 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+public class ParentPlatformCatch {
+
+    private String id;
+
+    // 心跳未回复次数
+    private int keepAliveReply;
+
+    // 注册未回复次数
+    private int registerAliveReply;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public int getKeepAliveReply() {
+        return keepAliveReply;
+    }
+
+    public void setKeepAliveReply(int keepAliveReply) {
+        this.keepAliveReply = keepAliveReply;
+    }
+
+    public int getRegisterAliveReply() {
+        return registerAliveReply;
+    }
+
+    public void setRegisterAliveReply(int registerAliveReply) {
+        this.registerAliveReply = registerAliveReply;
+    }
+}

+ 15 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java

@@ -0,0 +1,15 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+public class PlatformRegister {
+
+    // 未回复次数
+    private int reply;
+
+    public int getReply() {
+        return reply;
+    }
+
+    public void setReply(int reply) {
+        this.reply = reply;
+    }
+}

+ 11 - 2
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java

@@ -1,8 +1,7 @@
 package com.genersoft.iot.vmp.gb28181.event;
 
-import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire.PlatformKeepaliveExpireEvent;
 import com.genersoft.iot.vmp.gb28181.event.platformNotRegister.PlatformNotRegisterEvent;
-import com.genersoft.iot.vmp.vmanager.platform.PlatformController;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.stereotype.Component;
@@ -35,6 +34,16 @@ public class EventPublisher {
         applicationEventPublisher.publishEvent(outEvent);
     }
 
+	/**
+	 * 平台心跳到期事件
+	 * @param platformGbId
+	 */
+	public void platformKeepaliveExpireEventPublish(String platformGbId){
+		PlatformKeepaliveExpireEvent platformNotRegisterEvent = new PlatformKeepaliveExpireEvent(this);
+		platformNotRegisterEvent.setPlatformGbID(platformGbId);
+        applicationEventPublisher.publishEvent(platformNotRegisterEvent);
+    }
+
 	/**
 	 * 平台未注册事件
 	 * @param platformGbId

+ 64 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java

@@ -0,0 +1,64 @@
+package com.genersoft.iot.vmp.gb28181.event.offline;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.connection.Message;
+import org.springframework.data.redis.connection.MessageListener;
+import org.springframework.data.redis.listener.KeyExpirationEventMessageListener;
+import org.springframework.data.redis.listener.RedisMessageListenerContainer;
+import org.springframework.stereotype.Component;
+
+import com.genersoft.iot.vmp.common.VideoManagerConstants;
+import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
+
+import java.nio.charset.StandardCharsets;
+
+/**    
+ * @Description:设备心跳超时监听,借助redis过期特性,进行监听,监听到说明设备心跳超时,发送离线事件
+ * @author: swwheihei
+ * @date:   2020年5月6日 上午11:35:46     
+ */
+@Component
+public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessageListener {
+
+	@Autowired
+	private EventPublisher publisher;
+
+    public KeepaliveTimeoutListenerForPlatform(RedisMessageListenerContainer listenerContainer) {
+        super(listenerContainer);
+    }
+
+
+    /**
+     * 监听失效的key
+     * @param message
+     * @param bytes
+     */
+    @Override
+    public void onMessage(Message message, byte[] pattern) {
+        //  获取失效的key
+        String expiredKey = message.toString();
+        System.out.println(expiredKey);
+        if(!expiredKey.startsWith(VideoManagerConstants.PLATFORM_PREFIX)){
+        	System.out.println("收到redis过期监听,但开头不是"+VideoManagerConstants.PLATFORM_PREFIX+",忽略");
+        	return;
+        }
+        // 平台心跳到期,需要重发, 判断是否已经多次未收到心跳回复, 多次未收到,则重新发起注册, 注册尝试多次未得到回复,则认为平台离线
+        if (expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)) {
+            String platformGBId = expiredKey.substring(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
+
+            publisher.platformKeepaliveExpireEventPublish(platformGBId);
+        }else if (expiredKey.startsWith(VideoManagerConstants.PLATFORM_REGISTER_PREFIX)) {
+            System.out.println("11111111111111");
+            String platformGBId = expiredKey.substring(VideoManagerConstants.PLATFORM_REGISTER_PREFIX.length(),expiredKey.length());
+
+            publisher.platformNotRegisterEventPublish(platformGBId);
+        }else{
+            String deviceId = expiredKey.substring(VideoManagerConstants.KEEPLIVEKEY_PREFIX.length(),expiredKey.length());
+            publisher.outlineEventPublish(deviceId, VideoManagerConstants.EVENT_OUTLINE_TIMEOUT);
+        }
+
+    }
+}

+ 23 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEvent.java

@@ -0,0 +1,23 @@
+package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
+
+import org.springframework.context.ApplicationEvent;
+
+/**
+ *  平台心跳超时事件
+ */
+public class PlatformKeepaliveExpireEvent extends ApplicationEvent {
+
+    private String platformGbID;
+
+    public PlatformKeepaliveExpireEvent(Object source) {
+        super(source);
+    }
+
+    public String getPlatformGbID() {
+        return platformGbID;
+    }
+
+    public void setPlatformGbID(String platformGbID) {
+        this.platformGbID = platformGbID;
+    }
+}

+ 85 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java

@@ -0,0 +1,85 @@
+package com.genersoft.iot.vmp.gb28181.event.platformKeepaliveExpire;
+
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister;
+import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+import javax.sip.ResponseEvent;
+import javax.sip.message.Response;
+
+/**
+ * @Description: 平台心跳超时事件
+ * @author: panll
+ * @date: 2020年11月5日 10:00
+ */
+@Component
+public class PlatformKeepaliveExpireEventLister implements ApplicationListener<PlatformKeepaliveExpireEvent> {
+
+
+    private final static Logger logger = LoggerFactory.getLogger(PlatformKeepaliveExpireEventLister.class);
+
+    @Autowired
+    private IVideoManagerStorager storager;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private ISIPCommanderForPlatform sipCommanderForPlatform;
+
+    @Autowired
+    private SipSubscribe sipSubscribe;
+
+    @Autowired
+    private EventPublisher publisher;
+
+    @Override
+    public void onApplicationEvent(@NotNull PlatformKeepaliveExpireEvent event) {
+
+        if (logger.isDebugEnabled()) {
+            logger.debug("平台心跳到期事件事件触发,平台国标ID:" + event.getPlatformGbID());
+        }
+        ParentPlatform parentPlatform = storager.queryParentPlatById(event.getPlatformGbID());
+        ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(event.getPlatformGbID());
+        if (parentPlatform == null) {
+            logger.debug("平台心跳到期事件事件触发,但平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
+            return;
+        }
+        if (parentPlatformCatch == null) {
+            return;
+        }
+        // 发送心跳
+        if (parentPlatformCatch.getKeepAliveReply() >= 3) {
+            // 有3次未收到心跳回复, 设置平台状态为离线, 开始重新注册
+            logger.warn("有3次未收到心跳回复,标记设置平台状态为离线, 并重新注册 平台国标ID:" + event.getPlatformGbID());
+            publisher.platformNotRegisterEventPublish(event.getPlatformGbID());
+        }else {
+            // 再次发送心跳
+            String callId = sipCommanderForPlatform.keepalive(parentPlatform);
+
+            parentPlatformCatch.setKeepAliveReply( parentPlatformCatch.getKeepAliveReply() + 1);
+            // 存储心跳信息, 并设置状态为未回复, 如果多次过期仍未收到回复,则认为上级平台已经离线
+            redisCatchStorage.updatePlatformKeepalive(parentPlatform);
+            redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
+
+            sipSubscribe.addOkSubscribe(callId, (ResponseEvent responseEvent) ->{
+                if (responseEvent.getResponse().getStatusCode() == Response.OK) {
+                    // 收到心跳响应信息,
+                    parentPlatformCatch.setKeepAliveReply(0);
+                    redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
+                }
+            } );
+        }
+    }
+}

+ 6 - 3
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java

@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.gb28181.event.platformNotRegister;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
 import com.genersoft.iot.vmp.gb28181.event.online.OnlineEventListener;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
 import org.slf4j.Logger;
@@ -26,6 +27,8 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
 
     @Autowired
     private IVideoManagerStorager storager;
+    @Autowired
+    private SIPCommanderFroPlatform sipCommanderFroPlatform;
 
     @Autowired
     private RedisUtil redis;
@@ -33,13 +36,13 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
     @Override
     public void onApplicationEvent(PlatformNotRegisterEvent event) {
 
-        if (logger.isDebugEnabled()) {
-            logger.debug("平台未注册事件触发,平台国标ID:" + event.getPlatformGbID());
-        }
+        logger.debug("平台未注册事件触发,平台国标ID:" + event.getPlatformGbID());
+
         ParentPlatform parentPlatform = storager.queryParentPlatById(event.getPlatformGbID());
         if (parentPlatform == null) {
             logger.debug("平台未注册事件触发,但平台已经删除!!! 平台国标ID:" + event.getPlatformGbID());
             return;
         }
+        sipCommanderFroPlatform.register(parentPlatform);
     }
 }

+ 8 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java

@@ -4,6 +4,8 @@ import javax.sip.RequestEvent;
 import javax.sip.ResponseEvent;
 import javax.sip.SipProvider;
 import javax.sip.header.CSeqHeader;
+import javax.sip.header.CallIdHeader;
+import javax.sip.header.Header;
 import javax.sip.message.Request;
 import javax.sip.message.Response;
 
@@ -11,6 +13,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.alibaba.fastjson.JSON;
 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -34,6 +37,10 @@ import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor
 import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
+import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor;
+import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor;
+import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor;
+import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import com.genersoft.iot.vmp.utils.SpringBeanFactory;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@@ -88,6 +95,7 @@ public class SIPProcessorFactory {
 	@Lazy
 	private RegisterResponseProcessor registerResponseProcessor;
 
+
 	@Autowired
 	private OtherResponseProcessor otherResponseProcessor;
 

+ 9 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java

@@ -9,5 +9,14 @@ public interface ISIPCommanderForPlatform {
      * @param parentPlatform
      * @return
      */
+    boolean register(ParentPlatform parentPlatform);
+
     boolean register(ParentPlatform parentPlatform, String callId, String realm, String nonce, String scheme);
+
+    /**
+     * 向上级平发送心跳信息
+     * @param parentPlatform
+     * @return callId(作为接受回复的判定)
+     */
+    String keepalive(ParentPlatform parentPlatform);
 }

+ 150 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java

@@ -0,0 +1,150 @@
+package com.genersoft.iot.vmp.gb28181.transmit.cmd;
+
+import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.Host;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+import org.springframework.util.DigestUtils;
+
+import javax.sip.InvalidArgumentException;
+import javax.sip.PeerUnavailableException;
+import javax.sip.SipFactory;
+import javax.sip.SipProvider;
+import javax.sip.address.Address;
+import javax.sip.address.SipURI;
+import javax.sip.header.*;
+import javax.sip.message.Request;
+import javax.validation.constraints.NotNull;
+import java.text.ParseException;
+import java.util.ArrayList;
+
+/**
+ * @Description:摄像头命令request创造器 TODO 冗余代码太多待优化
+ * @author: swwheihei
+ * @date: 2020年5月6日 上午9:29:02
+ */
+@Component
+public class SIPRequestHeaderPlarformProvider {
+
+	@Autowired
+	private SipConfig sipConfig;
+	
+	@Autowired
+	private SipFactory sipFactory;
+	
+	@Autowired
+	@Qualifier(value="tcpSipProvider")
+	private SipProvider tcpSipProvider;
+	
+	@Autowired
+	@Qualifier(value="udpSipProvider")
+	private SipProvider udpSipProvider;
+
+
+	public Request createKeetpaliveMessageRequest(ParentPlatform parentPlatform, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
+		Request request = null;
+		// sipuri
+		SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
+		// via
+		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
+		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
+				parentPlatform.getTransport(), viaTag);
+		viaHeader.setRPort();
+		viaHeaders.add(viaHeader);
+		// from
+		SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(),
+				sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
+		Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
+		FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
+		// to
+		SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort() );
+		Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
+		ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
+		// callid
+		CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+				: udpSipProvider.getNewCallId();
+		// Forwards
+		MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
+		// ceq
+		CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
+
+		request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
+				toHeader, viaHeaders, maxForwards);
+		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
+		request.setContent(content, contentTypeHeader);
+		return request;
+	}
+
+
+	public Request createRegisterRequest(@NotNull ParentPlatform platform, String fromTag, String viaTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
+		Request request = null;
+		String sipAddress = sipConfig.getSipIp() + ":" + sipConfig.getSipPort();
+		//请求行
+		SipURI requestLine = sipFactory.createAddressFactory().createSipURI(platform.getDeviceGBId(),
+				platform.getServerIP() + ":" + platform.getServerPort());
+		//via
+		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
+		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(platform.getServerIP(), platform.getServerPort(), platform.getTransport(), viaTag);
+		viaHeader.setRPort();
+		viaHeaders.add(viaHeader);
+		//from
+		SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(platform.getDeviceGBId(),sipAddress);
+		Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
+		FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
+		//to
+		SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(platform.getDeviceGBId(),sipAddress);
+		Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
+		ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
+
+		//callid
+		CallIdHeader callIdHeader = null;
+		if(platform.getTransport().equals("TCP")) {
+			callIdHeader = tcpSipProvider.getNewCallId();
+		}
+		if(platform.getTransport().equals("UDP")) {
+			callIdHeader = udpSipProvider.getNewCallId();
+		}
+
+		//Forwards
+		MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
+
+		//ceq
+		CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.REGISTER);
+		request = sipFactory.createMessageFactory().createRequest(requestLine, Request.REGISTER, callIdHeader,
+				cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
+
+		Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory()
+				.createSipURI(platform.getDeviceGBId(), sipAddress));
+		request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
+
+		return request;
+	}
+
+	public Request createRegisterRequest(@NotNull ParentPlatform parentPlatform, String fromTag, String viaTag,
+										 String callId, String realm, String nonce, String scheme) throws ParseException, PeerUnavailableException, InvalidArgumentException {
+		Request registerRequest = createRegisterRequest(parentPlatform, fromTag, viaTag);
+
+		CallIdHeader callIdHeader = (CallIdHeader)registerRequest.getHeader(CallIdHeader.NAME);
+		callIdHeader.setCallId(callId);
+
+		String uri = "sip:" + parentPlatform.getServerGBId() +
+				"@" + parentPlatform.getServerIP() +
+				":" + parentPlatform.getServerPort();
+
+		String HA1 = DigestUtils.md5DigestAsHex((parentPlatform.getDeviceGBId() + ":" + realm + ":" + parentPlatform.getPassword()).getBytes());
+		String HA2=DigestUtils.md5DigestAsHex((Request.REGISTER + ":" + uri).getBytes());
+		String RESPONSE = DigestUtils.md5DigestAsHex((HA1 + ":" + nonce + ":" +  HA2).getBytes());
+
+		String authorizationHeaderContent = scheme + " username=\"" + parentPlatform.getDeviceGBId() + "\", " + "realm=\""
+				+ realm + "\", uri=\"" + uri  + "\", response=\"" + RESPONSE + "\", nonce=\""
+				+ nonce + "\"";
+		AuthorizationHeader authorizationHeader = sipFactory.createHeaderFactory().createAuthorizationHeader(authorizationHeaderContent);
+		registerRequest.addHeader(authorizationHeader);
+
+		return registerRequest;
+	}
+
+}

+ 34 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java

@@ -238,4 +238,38 @@ public class SIPRequestHeaderProvider {
 
 		return registerRequest;
 	}
+
+//	public Request createKeetpaliveMessageRequest(ParentPlatform parentPlatform, String content, String fromTag, String toTag, Object o) throws PeerUnavailableException, ParseException, InvalidArgumentException {
+//		Request request = null;
+//		// sipuri
+//		SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
+//		// via
+//		ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
+//		ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
+//				parentPlatform.getTransport(), null);
+//		viaHeader.setRPort();
+//		viaHeaders.add(viaHeader);
+//		// from
+//		SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(),
+//				sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
+//		Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
+//		FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
+//		// to
+//		SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerGBDomain());
+//		Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
+//		ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
+//		// callid
+//		CallIdHeader callIdHeader = parentPlatform.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
+//				: udpSipProvider.getNewCallId();
+//		// Forwards
+//		MaxForwardsHeader maxForwards = sipFactory.createHeaderFactory().createMaxForwardsHeader(70);
+//		// ceq
+//		CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.MESSAGE);
+//
+//		request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
+//				toHeader, viaHeaders, maxForwards);
+//		ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
+//		request.setContent(content, contentTypeHeader);
+//		return request;
+//	}
 }

+ 40 - 4
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@@ -5,8 +5,8 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderPlarformProvider;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
-import com.genersoft.iot.vmp.media.zlm.ZLMUtils;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -15,8 +15,10 @@ import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Component;
 
 import javax.sip.*;
+import javax.sip.header.CallIdHeader;
 import javax.sip.message.Request;
 import java.text.ParseException;
+import java.util.UUID;
 
 @Component
 public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
@@ -27,6 +29,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
     @Autowired
     private SIPRequestHeaderProvider headerProvider;
 
+    @Autowired
+    private SIPRequestHeaderPlarformProvider headerProviderPlarformProvider;
+
     @Autowired
     private VideoStreamSessionManager streamSession;
 
@@ -41,12 +46,14 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
     @Qualifier(value="udpSipProvider")
     private SipProvider udpSipProvider;
 
-    @Autowired
-    private ZLMUtils zlmUtils;
-
     @Value("${media.rtp.enable}")
     private boolean rtpEnable;
 
+    @Override
+    public boolean register(ParentPlatform parentPlatform) {
+        return register(parentPlatform, null, null, null, null);
+    }
+
     @Override
     public boolean register(ParentPlatform parentPlatform, @Nullable String callId, @Nullable String realm, @Nullable String nonce, @Nullable String scheme ) {
         try {
@@ -71,6 +78,35 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
         return false;
     }
 
+    @Override
+    public String keepalive(ParentPlatform parentPlatform) {
+        String callId = null;
+        try {
+
+            StringBuffer keepaliveXml = new StringBuffer(200);
+            keepaliveXml.append("<?xml version=\"1.0\" encoding=\"GB2312\" ?>\r\n");
+            keepaliveXml.append("<Notify>\r\n");
+            keepaliveXml.append("<CmdType>Keepalive</CmdType>\r\n");
+            keepaliveXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
+            keepaliveXml.append("<DeviceID>" + parentPlatform.getServerGBId() + "</DeviceID>\r\n");
+            keepaliveXml.append("<Status>OK</Status>\r\n");
+            keepaliveXml.append("</Notify>\r\n");
+
+            Request request = headerProviderPlarformProvider.createKeetpaliveMessageRequest(
+                    parentPlatform,
+                    keepaliveXml.toString(),
+                    UUID.randomUUID().toString().replace("-", ""),
+                    UUID.randomUUID().toString().replace("-", ""),
+                    null);
+            transmitRequest(parentPlatform, request);
+            CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
+            callId = callIdHeader.getCallId();
+        } catch (ParseException | InvalidArgumentException | SipException e) {
+            e.printStackTrace();
+        }
+        return callId;
+    }
+
     private void transmitRequest(ParentPlatform parentPlatform, Request request) throws SipException {
         if("TCP".equals(parentPlatform.getTransport())) {
             tcpSipProvider.sendRequest(request);

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java

@@ -460,6 +460,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
 					cmder.streamByeCmd(streamInfo.getStreamId());
 				}
 			}
+
 		} catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
 			e.printStackTrace();
 		}

+ 19 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/RegisterResponseProcessor.java

@@ -3,9 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.response.impl;
 import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.gb28181.SipLayer;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
 import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
 import gov.nist.core.Host;
 import gov.nist.javax.sip.address.AddressImpl;
@@ -40,6 +42,12 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
 	@Autowired
 	private IVideoManagerStorager storager;
 
+	@Autowired
+	private IRedisCatchStorage redisCatchStorage;
+
+	public RegisterResponseProcessor() {
+	}
+
 	/**
 	 * 处理Register响应
 	 *
@@ -77,6 +85,17 @@ public class RegisterResponseProcessor implements ISIPResponseProcessor {
 			logger.info(String.format("%s 注册成功", platformGBId ));
 			parentPlatform.setStatus(true);
 			storager.updateParentPlatform(parentPlatform);
+			//
+			redisCatchStorage.updatePlatformRegister(parentPlatform);
+
+			redisCatchStorage.updatePlatformKeepalive(parentPlatform);
+
+			ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getDeviceGBId());
+			if (parentPlatformCatch == null) {
+				parentPlatformCatch = new ParentPlatformCatch();
+				parentPlatformCatch.setId(parentPlatform.getDeviceGBId());
+			}
+			redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
 		}
 	}
 

+ 12 - 0
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java

@@ -2,6 +2,9 @@ package com.genersoft.iot.vmp.storager;
 
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister;
 
 import java.util.Map;
 
@@ -55,4 +58,13 @@ public interface IRedisCatchStorage {
     boolean stopPlayback(StreamInfo streamInfo);
 
     StreamInfo queryPlaybackByDevice(String deviceId, String code);
+
+    void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch);
+
+    ParentPlatformCatch queryPlatformCatchInfo(String platformGbId);
+
+    void updatePlatformKeepalive(ParentPlatform parentPlatform);
+
+    void updatePlatformRegister(ParentPlatform parentPlatform);
+
 }

+ 38 - 0
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java

@@ -1,9 +1,12 @@
 package com.genersoft.iot.vmp.storager;
 
 import java.util.List;
+import java.util.Map;
 
+import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.github.pagehelper.PageInfo;
 
 /**    
@@ -136,4 +139,39 @@ public interface IVideoManagerStorager {
 	 */
 	void cleanChannelsForDevice(String deviceId);
 
+
+	/**
+	 * 更新上级平台
+	 * @param parentPlatform
+	 */
+	boolean updateParentPlatform(ParentPlatform parentPlatform);
+
+
+	/**
+	 * 添加上级平台
+	 * @param parentPlatform
+	 */
+	boolean addParentPlatform(ParentPlatform parentPlatform);
+
+	/**
+	 * 删除上级平台
+	 * @param parentPlatform
+	 */
+	boolean deleteParentPlatform(ParentPlatform parentPlatform);
+
+
+	/**
+	 * 分页获取上级平台
+	 * @param page
+	 * @param count
+	 * @return
+	 */
+	PageInfo<ParentPlatform> queryParentPlatformList(int page, int count);
+
+	/**
+	 * 获取上级平台
+	 * @param platformGbId
+	 * @return
+	 */
+	ParentPlatform queryParentPlatById(String platformGbId);
 }

+ 3 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.storager.dao;
 
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import org.apache.ibatis.annotations.*;
 
 import java.util.List;
@@ -48,4 +49,6 @@ public interface DeviceChannelMapper {
     @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}")
     int cleanChannelsByDeviceId(String deviceId);
 
+
+
 }

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.storager.dao;
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import org.apache.ibatis.annotations.*;
 import org.springframework.stereotype.Repository;
 
@@ -63,4 +64,5 @@ public interface DeviceMapper {
 
     @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
     int del(String deviceId);
+
 }

+ 54 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java

@@ -0,0 +1,54 @@
+package com.genersoft.iot.vmp.storager.dao;
+
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 用于存储上级平台
+ */
+@Mapper
+@Repository
+public interface ParentPlatformMapper {
+
+    @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp,  " +
+            "            devicePort, username, password, expires, keepTimeout, transport, characterSet, PTZEnable, rtcp, " +
+            "            status) " +
+            "            VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " +
+            "            '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${PTZEnable}, ${rtcp}, " +
+            "            ${status})")
+    int addParentPlatform(ParentPlatform parentPlatform);
+
+    @Update("UPDATE parent_platform " +
+            "SET enable=#{enable}, " +
+            "name=#{name}," +
+            "serverGBId=#{serverGBId}," +
+            "serverGBDomain=#{serverGBDomain}, " +
+            "serverIP=#{serverIP}," +
+            "serverPort=#{serverPort}, " +
+            "deviceIp=#{deviceIp}, " +
+            "devicePort=#{devicePort}, " +
+            "username=#{username}, " +
+            "password=#{password}, " +
+            "expires=#{expires}, " +
+            "keepTimeout=#{keepTimeout}, " +
+            "transport=#{transport}, " +
+            "characterSet=#{characterSet}, " +
+            "PTZEnable=#{PTZEnable}, " +
+            "rtcp=#{rtcp}, " +
+            "status=#{status} " +
+            "WHERE deviceGBId=#{deviceGBId}")
+    int updateParentPlatform(ParentPlatform parentPlatform);
+
+    @Delete("DELETE FROM parent_platform WHERE deviceGBId=#{deviceGBId}")
+    int delParentPlatform(ParentPlatform parentPlatform);
+
+
+    @Select("SELECT * FROM parent_platform")
+    List<ParentPlatform> getParentPlatformList();
+
+    @Select("SELECT * FROM parent_platform WHERE deviceGBId=#{platformGbId}")
+    ParentPlatform getParentPlatById(String platformGbId);
+}

+ 26 - 0
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java

@@ -4,6 +4,9 @@ import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.MediaServerConfig;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
+import com.genersoft.iot.vmp.gb28181.bean.PlatformRegister;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
@@ -163,4 +166,27 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
         if (playLeys == null || playLeys.size() == 0) return null;
         return (StreamInfo)redis.get(playLeys.get(0).toString());
     }
+
+    @Override
+    public void updatePlatformCatchInfo(ParentPlatformCatch parentPlatformCatch) {
+        String key = VideoManagerConstants.PLATFORM_CATCH_PREFIX + parentPlatformCatch.getId();
+        redis.set(key, parentPlatformCatch);
+    }
+
+    @Override
+    public void updatePlatformKeepalive(ParentPlatform parentPlatform) {
+        String key = VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX + parentPlatform.getDeviceGBId();
+        redis.set(key, "", Integer.parseInt(parentPlatform.getKeepTimeout()));
+    }
+
+    @Override
+    public void updatePlatformRegister(ParentPlatform parentPlatform) {
+        String key = VideoManagerConstants.PLATFORM_REGISTER_PREFIX + parentPlatform.getDeviceGBId();
+        redis.set(key, "", Integer.parseInt(parentPlatform.getExpires()));
+    }
+
+    @Override
+    public ParentPlatformCatch queryPlatformCatchInfo(String platformGbId) {
+        return (ParentPlatformCatch)redis.get(VideoManagerConstants.PLATFORM_CATCH_PREFIX + platformGbId);
+    }
 }

+ 40 - 2
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java

@@ -3,17 +3,17 @@ package com.genersoft.iot.vmp.storager.impl;
 import java.util.*;
 
 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
+import com.genersoft.iot.vmp.storager.dao.ParentPlatformMapper;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import io.swagger.models.auth.In;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-import org.springframework.util.StringUtils;
 
 /**    
  * @Description:视频设备数据存储-jdbc实现
@@ -29,6 +29,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 	@Autowired
     private DeviceChannelMapper deviceChannelMapper;
 
+	@Autowired
+    private ParentPlatformMapper platformMapper;
+
 
 	/**
 	 * 根据设备ID判断设备是否存在
@@ -198,5 +201,40 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager {
 		int result = deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
 	}
 
+	@Override
+	public boolean addParentPlatform(ParentPlatform parentPlatform) {
+		int result = platformMapper.addParentPlatform(parentPlatform);
+		return result > 0;
+	}
+
+	@Override
+	public boolean updateParentPlatform(ParentPlatform parentPlatform) {
+		int result = 0;
+		if ( platformMapper.getParentPlatById(parentPlatform.getDeviceGBId()) == null) {
+			result = platformMapper.addParentPlatform(parentPlatform);
+		}else {
+			result = platformMapper.updateParentPlatform(parentPlatform);
+		}
+		return result > 0;
+	}
+
+	@Override
+	public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
+		int result = platformMapper.delParentPlatform(parentPlatform);
+		return result > 0;
+	}
+
+	@Override
+	public PageInfo<ParentPlatform> queryParentPlatformList(int page, int count) {
+		PageHelper.startPage(page, count);
+		List<ParentPlatform> all = platformMapper.getParentPlatformList();
+		return new PageInfo<>(all);
+	}
+
+	@Override
+	public ParentPlatform queryParentPlatById(String platformGbId) {
+		return platformMapper.getParentPlatById(platformGbId);
+	}
+
 
 }

+ 2 - 6
src/main/java/com/genersoft/iot/vmp/vmanager/platform/PlatformController.java

@@ -1,19 +1,15 @@
 package com.genersoft.iot.vmp.vmanager.platform;
 
 import com.alibaba.fastjson.JSONObject;
-import com.genersoft.iot.vmp.common.PageResult;
-import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
-import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
-import com.genersoft.iot.vmp.vmanager.device.DeviceController;
+import com.github.pagehelper.PageInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
-import org.springframework.stereotype.Controller;
 import org.springframework.util.StringUtils;
 import org.springframework.web.bind.annotation.*;
 import com.genersoft.iot.vmp.conf.SipConfig;
@@ -46,7 +42,7 @@ public class PlatformController {
     }
 
     @GetMapping("/platforms/{count}/{page}")
-    public PageResult<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count){
+    public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count){
 
         if (logger.isDebugEnabled()) {
             logger.debug("查询所有上级设备API调用");

BIN
src/main/resources/wvp.sqlite


+ 1 - 1
web_src/src/components/ParentPlatformList.vue

@@ -152,7 +152,7 @@ export default {
       this.$axios.get(`/api/platforms/${that.count}/${that.currentPage - 1}`)
         .then(function (res) {
           that.total = res.data.total;
-          that.platformList = res.data.data;
+          that.platformList = res.data.list;
         })
         .catch(function (error) {
           console.log(error);

+ 1 - 1
web_src/src/router/index.js

@@ -35,7 +35,7 @@ export default new VueRouter({
       path: '/channelList/:deviceId/:parentChannelId/:count/:page',
       name: 'channelList',
       component: channelList,
-    },
+    },,
     {
       path: '/parentPlatformList/:count/:page',
       name: 'parentPlatformList',