Ver Fonte

测试1 合并至最新代码

kindring há 3 anos atrás
pai
commit
627674bd08
55 ficheiros alterados com 5914 adições e 0 exclusões
  1. 6 0
      sql/2.6.6-2.6.7更新.sql
  2. 579 0
      sql/初始化.sql
  3. 80 0
      src/main/java/com/genersoft/iot/vmp/common/StreamURL.java
  4. 54 0
      src/main/java/com/genersoft/iot/vmp/common/SystemAllInfo.java
  5. 77 0
      src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java
  6. 30 0
      src/main/java/com/genersoft/iot/vmp/conf/ServiceInfo.java
  7. 74 0
      src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
  8. 138 0
      src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
  9. 53 0
      src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
  10. 143 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java
  11. 94 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java
  12. 27 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java
  13. 92 0
      src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java
  14. 109 0
      src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java
  15. 115 0
      src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
  16. 136 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java
  17. 17 0
      src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java
  18. 44 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java
  19. 4 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java
  20. 17 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java
  21. 36 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java
  22. 44 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
  23. 86 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java
  24. 86 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java
  25. 53 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java
  26. 27 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java
  27. 20 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java
  28. 433 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java
  29. 41 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java
  30. 86 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java
  31. 23 0
      src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java
  32. 50 0
      src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java
  33. 36 0
      src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java
  34. 150 0
      src/main/java/com/genersoft/iot/vmp/utils/UJson.java
  35. 31 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java
  36. 6 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java
  37. 22 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaceInfo.java
  38. 41 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java
  39. 411 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
  40. 47 0
      src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java
  41. 555 0
      src/main/java/com/genersoft/iot/vmp/web/gb28181/dto/DeviceChannelExtend.java
  42. BIN
      src/main/resources/wvpssl.jks
  43. 513 0
      web_src/src/components/GBRecordDetail.vue
  44. 327 0
      web_src/src/components/common/ h265web.vue
  45. 180 0
      web_src/src/components/console.vue
  46. 109 0
      web_src/src/components/console/ConsoleCPU.vue
  47. 81 0
      web_src/src/components/console/ConsoleDisk.vue
  48. 103 0
      web_src/src/components/console/ConsoleMEM.vue
  49. 85 0
      web_src/src/components/console/ConsoleMediaServer.vue
  50. 89 0
      web_src/src/components/console/ConsoleNet.vue
  51. 63 0
      web_src/src/components/console/ConsoleNodeLoad.vue
  52. 90 0
      web_src/src/components/console/ConsoleResource.vue
  53. 59 0
      web_src/src/components/dialog/configInfo.vue
  54. 42 0
      web_src/src/components/service/UserService.js
  55. BIN
      web_src/web_src.7z

+ 6 - 0
sql/2.6.6-2.6.7更新.sql

@@ -0,0 +1,6 @@
+alter table device
+    add asMessageChannel int default 0;
+
+alter table parent_platform
+    add asMessageChannel int default 0;
+

+ 579 - 0
sql/初始化.sql

@@ -0,0 +1,579 @@
+-- MySQL dump 10.13  Distrib 8.0.31, for Linux (x86_64)
+--
+-- Host: 127.0.0.1    Database: wvp
+-- ------------------------------------------------------
+-- Server version	8.0.30
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!50503 SET NAMES utf8mb4 */;
+/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
+/*!40103 SET TIME_ZONE='+00:00' */;
+/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
+/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
+/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
+/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
+
+--
+-- Table structure for table `device`
+--
+
+DROP TABLE IF EXISTS `device`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `device` (
+                          `id` int NOT NULL AUTO_INCREMENT,
+                          `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `manufacturer` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `model` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `firmware` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `streamMode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `online` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `registerTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `keepaliveTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `port` int DEFAULT NULL,
+                          `expires` int DEFAULT NULL,
+                          `keepaliveIntervalTime` int DEFAULT NULL,
+                          `subscribeCycleForCatalog` int DEFAULT NULL,
+                          `hostAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `charset` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `subscribeCycleForMobilePosition` int DEFAULT NULL,
+                          `mobilePositionSubmissionInterval` int DEFAULT '5',
+                          `subscribeCycleForAlarm` int DEFAULT NULL,
+                          `ssrcCheck` int DEFAULT '0',
+                          `asMessageChannel` int DEFAULT '0',
+                          `geoCoordSys` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                          `custom_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `sdpIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          `localIp` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
+                          PRIMARY KEY (`id`),
+                          UNIQUE KEY `device_deviceId_uindex` (`deviceId`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `device`
+--
+
+LOCK TABLES `device` WRITE;
+/*!40000 ALTER TABLE `device` DISABLE KEYS */;
+/*!40000 ALTER TABLE `device` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `device_alarm`
+--
+
+DROP TABLE IF EXISTS `device_alarm`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `device_alarm` (
+                                `id` int NOT NULL AUTO_INCREMENT,
+                                `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `alarmPriority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `alarmMethod` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `alarmTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `alarmDescription` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `longitude` double DEFAULT NULL,
+                                `latitude` double DEFAULT NULL,
+                                `alarmType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `device_alarm`
+--
+
+LOCK TABLES `device_alarm` WRITE;
+/*!40000 ALTER TABLE `device_alarm` DISABLE KEYS */;
+/*!40000 ALTER TABLE `device_alarm` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `device_channel`
+--
+
+DROP TABLE IF EXISTS `device_channel`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `device_channel` (
+                                  `id` int NOT NULL AUTO_INCREMENT,
+                                  `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `manufacture` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `model` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `owner` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `block` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `safetyWay` int DEFAULT NULL,
+                                  `registerWay` int DEFAULT NULL,
+                                  `certNum` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `certifiable` int DEFAULT NULL,
+                                  `errCode` int DEFAULT NULL,
+                                  `endTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `secrecy` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `ipAddress` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `port` int DEFAULT NULL,
+                                  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `PTZType` int DEFAULT NULL,
+                                  `status` int DEFAULT NULL,
+                                  `longitude` double DEFAULT NULL,
+                                  `latitude` double DEFAULT NULL,
+                                  `streamId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                  `parental` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `hasAudio` bit(1) DEFAULT NULL,
+                                  `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                  `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                  `subCount` int DEFAULT '0',
+                                  `longitudeGcj02` double DEFAULT NULL,
+                                  `latitudeGcj02` double DEFAULT NULL,
+                                  `longitudeWgs84` double DEFAULT NULL,
+                                  `latitudeWgs84` double DEFAULT NULL,
+                                  `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  `gpsTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                  PRIMARY KEY (`id`),
+                                  UNIQUE KEY `device_channel_id_uindex` (`id`),
+                                  UNIQUE KEY `device_channel_pk` (`channelId`,`deviceId`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `device_channel`
+--
+
+LOCK TABLES `device_channel` WRITE;
+/*!40000 ALTER TABLE `device_channel` DISABLE KEYS */;
+/*!40000 ALTER TABLE `device_channel` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `device_mobile_position`
+--
+
+DROP TABLE IF EXISTS `device_mobile_position`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `device_mobile_position` (
+                                          `id` int NOT NULL AUTO_INCREMENT,
+                                          `deviceId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                          `channelId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                          `deviceName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                          `time` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                          `longitude` double NOT NULL,
+                                          `latitude` double NOT NULL,
+                                          `altitude` double DEFAULT NULL,
+                                          `speed` double DEFAULT NULL,
+                                          `direction` double DEFAULT NULL,
+                                          `reportSource` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                          `longitudeGcj02` double DEFAULT NULL,
+                                          `latitudeGcj02` double DEFAULT NULL,
+                                          `longitudeWgs84` double DEFAULT NULL,
+                                          `latitudeWgs84` double DEFAULT NULL,
+                                          `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                          PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `device_mobile_position`
+--
+
+LOCK TABLES `device_mobile_position` WRITE;
+/*!40000 ALTER TABLE `device_mobile_position` DISABLE KEYS */;
+/*!40000 ALTER TABLE `device_mobile_position` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `gb_stream`
+--
+
+DROP TABLE IF EXISTS `gb_stream`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `gb_stream` (
+                             `gbStreamId` int NOT NULL AUTO_INCREMENT,
+                             `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `gbId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                             `longitude` double DEFAULT NULL,
+                             `latitude` double DEFAULT NULL,
+                             `streamType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                             `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                             `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                             PRIMARY KEY (`gbStreamId`) USING BTREE,
+                             UNIQUE KEY `app` (`app`,`stream`) USING BTREE,
+                             UNIQUE KEY `gbId` (`gbId`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `gb_stream`
+--
+
+LOCK TABLES `gb_stream` WRITE;
+/*!40000 ALTER TABLE `gb_stream` DISABLE KEYS */;
+/*!40000 ALTER TABLE `gb_stream` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `log`
+--
+
+DROP TABLE IF EXISTS `log`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `log` (
+                       `id` int NOT NULL AUTO_INCREMENT,
+                       `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `uri` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `address` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `result` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `timing` bigint NOT NULL,
+                       `username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                       PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `log`
+--
+
+LOCK TABLES `log` WRITE;
+/*!40000 ALTER TABLE `log` DISABLE KEYS */;
+/*!40000 ALTER TABLE `log` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `media_server`
+--
+
+DROP TABLE IF EXISTS `media_server`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `media_server` (
+                                `id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `hookIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `sdpIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `streamIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `httpPort` int NOT NULL,
+                                `httpSSlPort` int NOT NULL,
+                                `rtmpPort` int NOT NULL,
+                                `rtmpSSlPort` int NOT NULL,
+                                `rtpProxyPort` int NOT NULL,
+                                `rtspPort` int NOT NULL,
+                                `rtspSSLPort` int NOT NULL,
+                                `autoConfig` int NOT NULL,
+                                `secret` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `rtpEnable` int NOT NULL,
+                                `rtpPortRange` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `recordAssistPort` int NOT NULL,
+                                `defaultServer` int NOT NULL,
+                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `hookAliveInterval` int NOT NULL,
+                                PRIMARY KEY (`id`) USING BTREE,
+                                UNIQUE KEY `media_server_i` (`ip`,`httpPort`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `media_server`
+--
+
+LOCK TABLES `media_server` WRITE;
+/*!40000 ALTER TABLE `media_server` DISABLE KEYS */;
+/*!40000 ALTER TABLE `media_server` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `parent_platform`
+--
+
+DROP TABLE IF EXISTS `parent_platform`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `parent_platform` (
+                                   `id` int NOT NULL AUTO_INCREMENT,
+                                   `enable` int DEFAULT NULL,
+                                   `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `serverGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                   `serverGBDomain` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `serverIP` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `serverPort` int DEFAULT NULL,
+                                   `deviceGBId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                   `deviceIp` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `devicePort` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `password` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `expires` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `keepTimeout` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `transport` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `characterSet` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                   `ptz` int DEFAULT NULL,
+                                   `rtcp` int DEFAULT NULL,
+                                   `asMessageChannel` int DEFAULT '0',
+                                   `status` bit(1) DEFAULT NULL,
+                                   `startOfflinePush` int DEFAULT '0',
+                                   `administrativeDivision` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                   `catalogGroup` int DEFAULT '1',
+                                   `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                   `treeType` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                   PRIMARY KEY (`id`),
+                                   UNIQUE KEY `parent_platform_id_uindex` (`id`),
+                                   UNIQUE KEY `parent_platform_pk` (`serverGBId`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `parent_platform`
+--
+
+LOCK TABLES `parent_platform` WRITE;
+/*!40000 ALTER TABLE `parent_platform` DISABLE KEYS */;
+/*!40000 ALTER TABLE `parent_platform` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `platform_catalog`
+--
+
+DROP TABLE IF EXISTS `platform_catalog`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `platform_catalog` (
+                                    `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                    `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                    `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                    `parentId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                    `civilCode` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                    `businessGroupId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                    PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `platform_catalog`
+--
+
+LOCK TABLES `platform_catalog` WRITE;
+/*!40000 ALTER TABLE `platform_catalog` DISABLE KEYS */;
+/*!40000 ALTER TABLE `platform_catalog` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `platform_gb_channel`
+--
+
+DROP TABLE IF EXISTS `platform_gb_channel`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `platform_gb_channel` (
+                                       `id` int NOT NULL AUTO_INCREMENT,
+                                       `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                       `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                       `deviceChannelId` int NOT NULL,
+                                       PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `platform_gb_channel`
+--
+
+LOCK TABLES `platform_gb_channel` WRITE;
+/*!40000 ALTER TABLE `platform_gb_channel` DISABLE KEYS */;
+/*!40000 ALTER TABLE `platform_gb_channel` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `platform_gb_stream`
+--
+
+DROP TABLE IF EXISTS `platform_gb_stream`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `platform_gb_stream` (
+                                      `id` int NOT NULL AUTO_INCREMENT,
+                                      `platformId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                      `catalogId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                      `gbStreamId` int NOT NULL,
+                                      PRIMARY KEY (`id`),
+                                      UNIQUE KEY `platform_gb_stream_pk` (`platformId`,`catalogId`,`gbStreamId`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `platform_gb_stream`
+--
+
+LOCK TABLES `platform_gb_stream` WRITE;
+/*!40000 ALTER TABLE `platform_gb_stream` DISABLE KEYS */;
+/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `stream_proxy`
+--
+
+DROP TABLE IF EXISTS `stream_proxy`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `stream_proxy` (
+                                `id` int NOT NULL AUTO_INCREMENT,
+                                `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `src_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `dst_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `timeout_ms` int DEFAULT NULL,
+                                `ffmpeg_cmd_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `rtp_type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `enable_audio` bit(1) DEFAULT NULL,
+                                `enable_mp4` bit(1) DEFAULT NULL,
+                                `enable` bit(1) NOT NULL,
+                                `status` bit(1) NOT NULL,
+                                `enable_remove_none_reader` bit(1) NOT NULL,
+                                `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                                `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                                `enable_disable_none_reader` bit(1) DEFAULT NULL,
+                                PRIMARY KEY (`id`),
+                                UNIQUE KEY `stream_proxy_pk` (`app`,`stream`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `stream_proxy`
+--
+
+LOCK TABLES `stream_proxy` WRITE;
+/*!40000 ALTER TABLE `stream_proxy` DISABLE KEYS */;
+/*!40000 ALTER TABLE `stream_proxy` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `stream_push`
+--
+
+DROP TABLE IF EXISTS `stream_push`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `stream_push` (
+                               `id` int NOT NULL AUTO_INCREMENT,
+                               `app` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                               `stream` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                               `totalReaderCount` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `originType` int DEFAULT NULL,
+                               `originTypeStr` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `aliveSecond` int DEFAULT NULL,
+                               `mediaServerId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `serverId` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                               `pushTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `status` int DEFAULT NULL,
+                               `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                               `pushIng` int DEFAULT NULL,
+                               `self` int DEFAULT NULL,
+                               PRIMARY KEY (`id`),
+                               UNIQUE KEY `stream_push_pk` (`app`,`stream`)
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `stream_push`
+--
+
+LOCK TABLES `stream_push` WRITE;
+/*!40000 ALTER TABLE `stream_push` DISABLE KEYS */;
+/*!40000 ALTER TABLE `stream_push` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `user`
+--
+
+DROP TABLE IF EXISTS `user`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `user` (
+                        `id` int NOT NULL AUTO_INCREMENT,
+                        `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                        `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                        `roleId` int NOT NULL,
+                        `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                        `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                        `pushKey` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL,
+                        PRIMARY KEY (`id`) USING BTREE,
+                        UNIQUE KEY `user_username_uindex` (`username`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `user`
+--
+
+LOCK TABLES `user` WRITE;
+/*!40000 ALTER TABLE `user` DISABLE KEYS */;
+INSERT INTO `user` VALUES (1,'admin','21232f297a57a5a743894a0e4a801fc3',1,'2021-04-13 14:14:57','2021-04-13 14:14:57','3e80d1762a324d5b0ff636e0bd16f1e3');
+/*!40000 ALTER TABLE `user` ENABLE KEYS */;
+UNLOCK TABLES;
+
+--
+-- Table structure for table `user_role`
+--
+
+DROP TABLE IF EXISTS `user_role`;
+/*!40101 SET @saved_cs_client     = @@character_set_client */;
+/*!50503 SET character_set_client = utf8mb4 */;
+CREATE TABLE `user_role` (
+                             `id` int NOT NULL AUTO_INCREMENT,
+                             `name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `authority` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `createTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             `updateTime` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
+                             PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC;
+/*!40101 SET character_set_client = @saved_cs_client */;
+
+--
+-- Dumping data for table `user_role`
+--
+
+LOCK TABLES `user_role` WRITE;
+/*!40000 ALTER TABLE `user_role` DISABLE KEYS */;
+INSERT INTO `user_role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57');
+/*!40000 ALTER TABLE `user_role` ENABLE KEYS */;
+UNLOCK TABLES;
+/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
+
+/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
+/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
+/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
+/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
+
+-- Dump completed on 2022-11-29 11:47:46

+ 80 - 0
src/main/java/com/genersoft/iot/vmp/common/StreamURL.java

@@ -0,0 +1,80 @@
+package com.genersoft.iot.vmp.common;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+
+@Schema(description = "流地址信息")
+public class StreamURL implements Serializable {
+
+    @Schema(description = "协议")
+    private String protocol;
+
+    @Schema(description = "主机地址")
+    private String host;
+
+    @Schema(description = "端口")
+    private int port = -1;
+
+    @Schema(description = "定位位置")
+    private String file;
+
+    @Schema(description = "拼接后的地址")
+    private String url;
+
+    public StreamURL() {
+    }
+
+    public StreamURL(String protocol, String host, int port, String file) {
+        this.protocol = protocol;
+        this.host = host;
+        this.port = port;
+        this.file = file;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getFile() {
+        return file;
+    }
+
+    public void setFile(String file) {
+        this.file = file;
+    }
+
+    public String getUrl() {
+        return this.toString();
+    }
+
+    @Override
+    public String toString() {
+        if (protocol != null && host != null && port != -1 ) {
+            return String.format("%s://%s:%s/%s", protocol, host, port, file);
+        }else {
+            return null;
+        }
+    }
+}

+ 54 - 0
src/main/java/com/genersoft/iot/vmp/common/SystemAllInfo.java

@@ -0,0 +1,54 @@
+package com.genersoft.iot.vmp.common;
+
+import java.util.List;
+
+public class SystemAllInfo {
+
+    private List<Object> cpu;
+    private List<Object> mem;
+    private List<Object> net;
+
+    private long netTotal;
+
+    private Object disk;
+
+    public List<Object> getCpu() {
+        return cpu;
+    }
+
+    public void setCpu(List<Object> cpu) {
+        this.cpu = cpu;
+    }
+
+    public List<Object> getMem() {
+        return mem;
+    }
+
+    public void setMem(List<Object> mem) {
+        this.mem = mem;
+    }
+
+    public List<Object> getNet() {
+        return net;
+    }
+
+    public void setNet(List<Object> net) {
+        this.net = net;
+    }
+
+    public Object getDisk() {
+        return disk;
+    }
+
+    public void setDisk(Object disk) {
+        this.disk = disk;
+    }
+
+    public long getNetTotal() {
+        return netTotal;
+    }
+
+    public void setNetTotal(long netTotal) {
+        this.netTotal = netTotal;
+    }
+}

+ 77 - 0
src/main/java/com/genersoft/iot/vmp/common/enums/DeviceControlType.java

@@ -0,0 +1,77 @@
+package com.genersoft.iot.vmp.common.enums;
+
+import org.dom4j.Element;
+import org.springframework.util.ObjectUtils;
+
+
+/**
+ * @author gaofuwang
+ * @date 2023/01/18/ 10:09:00
+ * @since 1.0
+ */
+public enum DeviceControlType {
+
+    /**
+     * 云台控制
+     * 上下左右,预置位,扫描,辅助功能,巡航
+     */
+    PTZ("PTZCmd","云台控制"),
+    /**
+     * 远程启动
+     */
+    TELE_BOOT("TeleBoot","远程启动"),
+    /**
+     * 录像控制
+     */
+    RECORD("RecordCmd","录像控制"),
+    /**
+     * 布防撤防
+     */
+    GUARD("GuardCmd","布防撤防"),
+    /**
+     * 告警控制
+     */
+    ALARM("AlarmCmd","告警控制"),
+    /**
+     * 强制关键帧
+     */
+    I_FRAME("IFameCmd","强制关键帧"),
+    /**
+     * 拉框放大
+     */
+    DRAG_ZOOM_IN("DragZoomIn","拉框放大"),
+    /**
+     * 拉框缩小
+     */
+    DRAG_ZOOM_OUT("DragZoomOut","拉框缩小"),
+    /**
+     * 看守位
+     */
+    HOME_POSITION("HomePosition","看守位");
+
+    private final String val;
+
+    private final String desc;
+
+    DeviceControlType(String val, String desc) {
+        this.val = val;
+        this.desc = desc;
+    }
+
+    public String getVal() {
+        return val;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public static DeviceControlType typeOf(Element rootElement) {
+        for (DeviceControlType item : DeviceControlType.values()) {
+            if (!ObjectUtils.isEmpty(rootElement.element(item.val)) || !ObjectUtils.isEmpty(rootElement.elements(item.val))) {
+                return item;
+            }
+        }
+        return null;
+    }
+}

+ 30 - 0
src/main/java/com/genersoft/iot/vmp/conf/ServiceInfo.java

@@ -0,0 +1,30 @@
+package com.genersoft.iot.vmp.conf;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.context.WebServerInitializedEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ServiceInfo implements ApplicationListener<WebServerInitializedEvent> {
+
+    private final Logger logger = LoggerFactory.getLogger(ServiceInfo.class);
+
+    private static int serverPort;
+
+    public static int getServerPort() {
+        return serverPort;
+    }
+
+    @Override
+    public void onApplicationEvent(WebServerInitializedEvent event) {
+        // 项目启动获取启动的端口号
+        ServiceInfo.serverPort = event.getWebServer().getPort();
+        logger.info("项目启动获取启动的端口号:  " + ServiceInfo.serverPort);
+    }
+
+    public void setServerPort(int serverPort) {
+        ServiceInfo.serverPort = serverPort;
+    }
+}

+ 74 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java

@@ -0,0 +1,74 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * jwt token 过滤器
+ */
+
+@Component
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+
+        // 忽略登录请求的token验证
+        String requestURI = request.getRequestURI();
+        if (requestURI.equalsIgnoreCase("/api/user/login")) {
+            chain.doFilter(request, response);
+            return;
+        }
+        String jwt = request.getHeader(JwtUtils.getHeader());
+        // 这里如果没有jwt,继续往后走,因为后面还有鉴权管理器等去判断是否拥有身份凭证,所以是可以放行的
+        // 没有jwt相当于匿名访问,若有一些接口是需要权限的,则不能访问这些接口
+        if (StringUtils.isBlank(jwt)) {
+            jwt = request.getParameter(JwtUtils.getHeader());
+            if (StringUtils.isBlank(jwt)) {
+                chain.doFilter(request, response);
+                return;
+            }
+        }
+
+        JwtUser jwtUser = JwtUtils.verifyToken(jwt);
+        String username = jwtUser.getUserName();
+        // TODO 处理各个状态
+        switch (jwtUser.getStatus()){
+            case EXPIRED:
+                response.setStatus(400);
+                chain.doFilter(request, response);
+                // 异常
+                return;
+            case EXCEPTION:
+                // 过期
+                response.setStatus(400);
+                chain.doFilter(request, response);
+                return;
+            case EXPIRING_SOON:
+                // 即将过期
+//                return;
+            default:
+        }
+
+//        String password = SecurityUtils.encryptPassword(jwtUser.getPassword());
+//        user.setPassword(password);
+
+        // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
+        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword(), new ArrayList<>() );
+        SecurityContextHolder.getContext().setAuthentication(token);
+        chain.doFilter(request, response);
+    }
+
+}

+ 138 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java

@@ -0,0 +1,138 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
+import org.jose4j.json.JsonUtil;
+import org.jose4j.jwk.RsaJsonWebKey;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.NumericDate;
+import org.jose4j.jwt.consumer.ErrorCodes;
+import org.jose4j.jwt.consumer.InvalidJwtException;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+import org.jose4j.lang.JoseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.PrivateKey;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+public class JwtUtils {
+
+    private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
+
+    private static final String HEADER = "access-token";
+    private static final String AUDIENCE = "Audience";
+
+    private static final long EXPIRED_THRESHOLD = 10 * 60;
+
+    private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
+    private static final String privateKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\",\"d\":\"ed7U_k3rJ4yTk70JtRSIfjKGiEb67BO1TabcymnljKO7RU8nage84zZYuSu_XpQsHk6P1f0Gzxkicghm_Er-FrfVn2pp70Xu52z3yRd6BJUgWLDFk97ngScIyw5OiULKU9SrZk2frDpftNCSUcIgb50F8m0QAnBa_CdPsQKbuuhLv8V8tBAV7F_lAwvSBgu56wRo3hPz5dWH8YeXM7XBfQ9viFMNEKd21sP_j5C7ueUnXT66nBxe3ZJEU3iuMYM6D6dB_KW2GfZC6WmTgvGhhxJD0h7aYmfjkD99MDleB7SkpbvoODOqiQ5Epb7Nyh6kv5u4KUv2CJYtATLZkUeMkQ\",\"p\":\"uBUjWPWtlGksmOqsqCNWksfqJvMcnP_8TDYN7e4-WnHL4N-9HjRuPDnp6kHvCIEi9SEfxm7gNxlRcWegvNQr3IZCz7TnCTexXc5NOklB9OavWFla6u-s3Thn6Tz45-EUjpJr0VJMxhO-KxGmuTwUXBBp4vN6K2qV6rQNFmgkWzk\",\"q\":\"tW_i7cCec56bHkhITL_79dXHz_PLC_f7xlynmlZJGU_d6mqOKmLBNBbTMLnYW8uAFiFzWxDeDHh1o5uF0mSQR-Z1Fg35OftnpbWpy0Cbc2la5WgXQjOwtG1eLYIY2BD3-wQ1VYDBCvowr4FDi-sngxwLqvwmrJ0xjhi99O-Gzcs\",\"dp\":\"q1d5jE85Hz_6M-eTh_lEluEf0NtPEc-vvhw-QO4V-cecNpbrCBdTWBmr4dE3NdpFeJc5ZVFEv-SACyei1MBEh0ItI_pFZi4BmMfy2ELh8ptaMMkTOESYyVy8U7veDq9RnBcr5i1Nqr0rsBkA77-9T6gzdvycBZdzLYAkAmwzEvk\",\"dq\":\"q29A2K08Crs-jmp2Bi8Q_8QzvIX6wSBbwZ4ir24AO-5_HNP56IrPS0yV2GCB0pqCOGb6_Hz_koDvhtuYoqdqvMVAtMoXR3YJBUaVXPt65p4RyNmFwIPe31zHs_BNUTsXVRMw4c16mci03-Af1sEm4HdLfxAp6sfM3xr5wcnhcek\",\"qi\":\"rHPgVTyHUHuYzcxfouyBfb1XAY8nshwn0ddo81o1BccD4Z7zo5It6SefDHjxCAbcmbiCcXBSooLcY-NF5FMv3fg19UE21VyLQltHcVjRRp2tRs4OHcM8yaXIU2x6N6Z6BP2tOksHb9MOBY1wAQzFOAKg_G4Sxev6-_6ud6RISuc\"}";
+    private static final String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\"}";
+
+    /**
+     * token过期时间(分钟)
+     */
+    public static final long expirationTime = 30;
+
+    public static String createToken(String username, String password) {
+        try {
+            /**
+             * “iss” (issuer)  发行人
+             *
+             * “sub” (subject)  主题
+             *
+             * “aud” (audience) 接收方 用户
+             *
+             * “exp” (expiration time) 到期时间
+             *
+             * “nbf” (not before)  在此之前不可用
+             *
+             * “iat” (issued at)  jwt的签发时间
+             */
+            //Payload
+            JwtClaims claims = new JwtClaims();
+            claims.setGeneratedJwtId();
+            claims.setIssuedAtToNow();
+            // 令牌将过期的时间 分钟
+            claims.setExpirationTimeMinutesInTheFuture(expirationTime);
+            claims.setNotBeforeMinutesInThePast(0);
+            claims.setSubject("login");
+            claims.setAudience(AUDIENCE);
+            //添加自定义参数,必须是字符串类型
+            claims.setClaim("username", username);
+            claims.setClaim("password", password);
+
+            //jws
+            JsonWebSignature jws = new JsonWebSignature();
+            //签名算法RS256
+            jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
+            jws.setKeyIdHeaderValue(keyId);
+            jws.setPayload(claims.toJson());
+
+            PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
+            jws.setKey(privateKey);
+
+            //get token
+            String idToken = jws.getCompactSerialization();
+            return idToken;
+        } catch (JoseException e) {
+            logger.error("[Token生成失败]: {}", e.getMessage());
+        }
+
+        return null;
+    }
+
+    public static String getHeader() {
+        return HEADER;
+    }
+
+
+    public static JwtUser verifyToken(String token) {
+
+        JwtUser jwtUser = new JwtUser();
+
+        try {
+            JwtConsumer consumer = new JwtConsumerBuilder()
+                    .setRequireExpirationTime()
+                    .setMaxFutureValidityInMinutes(5256000)
+                    .setAllowedClockSkewInSeconds(30)
+                    .setRequireSubject()
+                    //.setExpectedIssuer("")
+                    .setExpectedAudience(AUDIENCE)
+                    .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
+                    .build();
+
+            JwtClaims claims = consumer.processToClaims(token);
+            NumericDate expirationTime = claims.getExpirationTime();
+            // 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
+            // 剩余时间 (秒)
+            long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
+            if (timeRemaining < 5 * 60) {
+                jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
+            }else {
+                jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
+            }
+
+            String username = (String) claims.getClaimValue("username");
+            String password = (String) claims.getClaimValue("password");
+            jwtUser.setUserName(username);
+            jwtUser.setPassword(password);
+
+            return jwtUser;
+        } catch (InvalidJwtException e) {
+            if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
+                jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
+            }else {
+                jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
+            }
+            return jwtUser;
+        }catch (Exception e) {
+            logger.error("[Token解析失败]: {}", e.getMessage());
+            jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
+            return jwtUser;
+        }
+    }
+}

+ 53 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java

@@ -0,0 +1,53 @@
+package com.genersoft.iot.vmp.conf.security.dto;
+
+public class JwtUser {
+
+    public enum TokenStatus{
+        /**
+         * 正常的使用状态
+         */
+        NORMAL,
+        /**
+         * 过期而失效
+         */
+        EXPIRED,
+        /**
+         * 即将过期
+         */
+        EXPIRING_SOON,
+        /**
+         * 异常
+         */
+        EXCEPTION
+    }
+
+    private String userName;
+
+    private String password;
+
+    private TokenStatus status;
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public TokenStatus getStatus() {
+        return status;
+    }
+
+    public void setStatus(TokenStatus status) {
+        this.status = status;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+}

+ 143 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java

@@ -0,0 +1,143 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+
+/**
+ * 设备信息查询响应
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+public class DragZoomRequest {
+    /**
+     * 序列号
+     */
+    @MessageElement("SN")
+    private String sn;
+
+    @MessageElement("DeviceID")
+    private String deviceId;
+
+    @MessageElement(value = "DragZoomIn")
+    private DragZoom dragZoomIn;
+
+    @MessageElement(value = "DragZoomOut")
+    private DragZoom dragZoomOut;
+
+    /**
+     * 基本参数
+     */
+    public static class DragZoom {
+        /**
+         * 播放窗口长度像素值
+         */
+        @MessageElement("Length")
+        protected Integer length;
+        /**
+         * 播放窗口宽度像素值
+         */
+        @MessageElement("Width")
+        protected Integer width;
+        /**
+         * 拉框中心的横轴坐标像素值
+         */
+        @MessageElement("MidPointX")
+        protected Integer midPointX;
+        /**
+         * 拉框中心的纵轴坐标像素值
+         */
+        @MessageElement("MidPointY")
+        protected Integer midPointY;
+        /**
+         * 拉框长度像素值
+         */
+        @MessageElement("LengthX")
+        protected Integer lengthX;
+        /**
+         * 拉框宽度像素值
+         */
+        @MessageElement("LengthY")
+        protected Integer lengthY;
+
+        public Integer getLength() {
+            return length;
+        }
+
+        public void setLength(Integer length) {
+            this.length = length;
+        }
+
+        public Integer getWidth() {
+            return width;
+        }
+
+        public void setWidth(Integer width) {
+            this.width = width;
+        }
+
+        public Integer getMidPointX() {
+            return midPointX;
+        }
+
+        public void setMidPointX(Integer midPointX) {
+            this.midPointX = midPointX;
+        }
+
+        public Integer getMidPointY() {
+            return midPointY;
+        }
+
+        public void setMidPointY(Integer midPointY) {
+            this.midPointY = midPointY;
+        }
+
+        public Integer getLengthX() {
+            return lengthX;
+        }
+
+        public void setLengthX(Integer lengthX) {
+            this.lengthX = lengthX;
+        }
+
+        public Integer getLengthY() {
+            return lengthY;
+        }
+
+        public void setLengthY(Integer lengthY) {
+            this.lengthY = lengthY;
+        }
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public DragZoom getDragZoomIn() {
+        return dragZoomIn;
+    }
+
+    public void setDragZoomIn(DragZoom dragZoomIn) {
+        this.dragZoomIn = dragZoomIn;
+    }
+
+    public DragZoom getDragZoomOut() {
+        return dragZoomOut;
+    }
+
+    public void setDragZoomOut(DragZoom dragZoomOut) {
+        this.dragZoomOut = dragZoomOut;
+    }
+}

+ 94 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java

@@ -0,0 +1,94 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import com.genersoft.iot.vmp.gb28181.utils.MessageElement;
+
+/**
+ * 设备信息查询响应
+ *
+ * @author Y.G
+ * @version 1.0
+ * @date 2022/6/28 14:55
+ */
+public class HomePositionRequest {
+    /**
+     * 序列号
+     */
+    @MessageElement("SN")
+    private String sn;
+
+    @MessageElement("DeviceID")
+    private String deviceId;
+
+    @MessageElement(value = "HomePosition")
+    private HomePosition homePosition;
+
+
+    /**
+     * 基本参数
+     */
+    public static class HomePosition {
+        /**
+         * 播放窗口长度像素值
+         */
+        @MessageElement("Enabled")
+        protected String enabled;
+        /**
+         * 播放窗口宽度像素值
+         */
+        @MessageElement("ResetTime")
+        protected String resetTime;
+        /**
+         * 拉框中心的横轴坐标像素值
+         */
+        @MessageElement("PresetIndex")
+        protected String presetIndex;
+
+        public String getEnabled() {
+            return enabled;
+        }
+
+        public void setEnabled(String enabled) {
+            this.enabled = enabled;
+        }
+
+        public String getResetTime() {
+            return resetTime;
+        }
+
+        public void setResetTime(String resetTime) {
+            this.resetTime = resetTime;
+        }
+
+        public String getPresetIndex() {
+            return presetIndex;
+        }
+
+        public void setPresetIndex(String presetIndex) {
+            this.presetIndex = presetIndex;
+        }
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public HomePosition getHomePosition() {
+        return homePosition;
+    }
+
+    public void setHomePosition(HomePosition homePosition) {
+        this.homePosition = homePosition;
+    }
+}

+ 27 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java

@@ -0,0 +1,27 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+public class RemoteAddressInfo {
+    private String ip;
+    private int port;
+
+    public RemoteAddressInfo(String ip, int port) {
+        this.ip = ip;
+        this.port = port;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+}

+ 92 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java

@@ -0,0 +1,92 @@
+package com.genersoft.iot.vmp.gb28181.conf;
+
+import gov.nist.core.ServerLogger;
+import gov.nist.core.StackLogger;
+import gov.nist.javax.sip.message.SIPMessage;
+import gov.nist.javax.sip.stack.SIPTransactionStack;
+
+import javax.sip.SipStack;
+import java.util.Properties;
+
+public class ServerLoggerImpl implements ServerLogger {
+
+    private boolean showLog = true;
+
+    private SIPTransactionStack sipStack;
+
+    protected StackLogger stackLogger;
+
+    @Override
+    public void closeLogFile() {
+
+    }
+
+    @Override
+    public void logMessage(SIPMessage message, String from, String to, boolean sender, long time) {
+        if (!showLog) {
+            return;
+        }
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(!sender? "发送:目标--->" + from:"接收:来自--->" + to)
+                .append("\r\n")
+                        .append(message);
+        this.stackLogger.logInfo(stringBuilder.toString());
+
+    }
+
+    @Override
+    public void logMessage(SIPMessage message, String from, String to, String status, boolean sender, long time) {
+        if (!showLog) {
+            return;
+        }
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(!sender? "发送: 目标->" + from :"接收:来自->" + to)
+                .append("\r\n")
+                .append(message);
+        this.stackLogger.logInfo(stringBuilder.toString());
+    }
+
+    @Override
+    public void logMessage(SIPMessage message, String from, String to, String status, boolean sender) {
+        if (!showLog) {
+            return;
+        }
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(!sender? "发送: 目标->" + from :"接收:来自->" + to)
+                .append("\r\n")
+                .append(message);
+        this.stackLogger.logInfo(stringBuilder.toString());
+    }
+
+    @Override
+    public void logException(Exception ex) {
+        if (!showLog) {
+            return;
+        }
+        this.stackLogger.logException(ex);
+    }
+
+    @Override
+    public void setStackProperties(Properties stackProperties) {
+        if (!showLog) {
+            return;
+        }
+        String TRACE_LEVEL = stackProperties.getProperty("gov.nist.javax.sip.TRACE_LEVEL");
+        if (TRACE_LEVEL != null) {
+            showLog = true;
+        }
+    }
+
+    @Override
+    public void setSipStack(SipStack sipStack) {
+        if (!showLog) {
+            return;
+        }
+        if(sipStack instanceof SIPTransactionStack) {
+            this.sipStack = (SIPTransactionStack)sipStack;
+            this.stackLogger = this.sipStack.getStackLogger();
+        }
+    }
+
+
+}

+ 109 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java

@@ -0,0 +1,109 @@
+package com.genersoft.iot.vmp.gb28181.conf;
+
+import gov.nist.core.StackLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.Properties;
+
+@Component
+public class StackLoggerImpl implements StackLogger {
+
+    private final static Logger logger = LoggerFactory.getLogger(StackLoggerImpl.class);
+
+    @Override
+    public void logStackTrace() {
+
+    }
+
+    @Override
+    public void logStackTrace(int traceLevel) {
+        System.out.println("traceLevel: "  + traceLevel);
+    }
+
+    @Override
+    public int getLineCount() {
+        return 0;
+    }
+
+    @Override
+    public void logException(Throwable ex) {
+
+    }
+
+    @Override
+    public void logDebug(String message) {
+//        logger.debug(message);
+    }
+
+    @Override
+    public void logDebug(String message, Exception ex) {
+//        logger.debug(message);
+    }
+
+    @Override
+    public void logTrace(String message) {
+        logger.trace(message);
+    }
+
+    @Override
+    public void logFatalError(String message) {
+//        logger.error(message);
+    }
+
+    @Override
+    public void logError(String message) {
+//        logger.error(message);
+    }
+
+    @Override
+    public boolean isLoggingEnabled() {
+        return true;
+    }
+
+    @Override
+    public boolean isLoggingEnabled(int logLevel) {
+        return true;
+    }
+
+    @Override
+    public void logError(String message, Exception ex) {
+//        logger.error(message);
+    }
+
+    @Override
+    public void logWarning(String message) {
+        logger.warn(message);
+    }
+
+    @Override
+    public void logInfo(String message) {
+        logger.info(message);
+    }
+
+    @Override
+    public void disableLogging() {
+
+    }
+
+    @Override
+    public void enableLogging() {
+
+    }
+
+    @Override
+    public void setBuildTimeStamp(String buildTimeStamp) {
+
+    }
+
+    @Override
+    public void setStackProperties(Properties stackProperties) {
+
+    }
+
+    @Override
+    public String getLoggerName() {
+        return null;
+    }
+}

+ 115 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java

@@ -0,0 +1,115 @@
+package com.genersoft.iot.vmp.gb28181.task;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.gb28181.bean.Device;
+import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
+import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
+import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
+import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
+import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
+import com.genersoft.iot.vmp.service.IDeviceService;
+import com.genersoft.iot.vmp.service.IMediaServerService;
+import com.genersoft.iot.vmp.service.IPlatformService;
+import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
+import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * 系统启动时控制设备
+ * @author lin
+ */
+@Component
+@Order(value=14)
+public class SipRunner implements CommandLineRunner {
+
+    @Autowired
+    private IVideoManagerStorage storager;
+
+    @Autowired
+    private IRedisCatchStorage redisCatchStorage;
+
+    @Autowired
+    private UserSetting userSetting;
+
+    @Autowired
+    private IDeviceService deviceService;
+
+    @Autowired
+    private ZLMRESTfulUtils zlmresTfulUtils;
+
+    @Autowired
+    private IMediaServerService mediaServerService;
+
+    @Autowired
+    private IPlatformService platformService;
+
+    @Autowired
+    private ISIPCommanderForPlatform commanderForPlatform;
+
+    @Override
+    public void run(String... args) throws Exception {
+        List<Device> deviceList = deviceService.getAllOnlineDevice();
+
+        for (Device device : deviceList) {
+            if (deviceService.expire(device)){
+                deviceService.offline(device.getDeviceId(), "注册已过期");
+            }else {
+                deviceService.online(device);
+            }
+        }
+        // 重置cseq计数
+        redisCatchStorage.resetAllCSEQ();
+        // 清理redis
+        // 清理数据库不存在但是redis中存在的数据
+        List<Device> devicesInDb = deviceService.getAll();
+        if (devicesInDb.size() == 0) {
+            redisCatchStorage.removeAllDevice();
+        }else {
+            List<Device> devicesInRedis = redisCatchStorage.getAllDevices();
+            if (devicesInRedis.size() > 0) {
+                Map<String, Device> deviceMapInDb = new HashMap<>();
+                devicesInDb.parallelStream().forEach(device -> {
+                    deviceMapInDb.put(device.getDeviceId(), device);
+                });
+                devicesInRedis.parallelStream().forEach(device -> {
+                    if (deviceMapInDb.get(device.getDeviceId()) == null) {
+                        redisCatchStorage.removeDevice(device.getDeviceId());
+                    }
+                });
+            }
+        }
+
+
+        // 查找国标推流
+        List<SendRtpItem> sendRtpItems = redisCatchStorage.queryAllSendRTPServer();
+        if (sendRtpItems.size() > 0) {
+            for (SendRtpItem sendRtpItem : sendRtpItems) {
+                MediaServerItem mediaServerItem = mediaServerService.getOne(sendRtpItem.getMediaServerId());
+                redisCatchStorage.deleteSendRTPServer(sendRtpItem.getPlatformId(),sendRtpItem.getChannelId(), sendRtpItem.getCallId(),sendRtpItem.getStreamId());
+                if (mediaServerItem != null) {
+                    Map<String, Object> param = new HashMap<>();
+                    param.put("vhost","__defaultVhost__");
+                    param.put("app",sendRtpItem.getApp());
+                    param.put("stream",sendRtpItem.getStreamId());
+                    param.put("ssrc",sendRtpItem.getSsrc());
+                    JSONObject jsonObject = zlmresTfulUtils.stopSendRtp(mediaServerItem, param);
+                    if (jsonObject != null && jsonObject.getInteger("code") == 0) {
+                        ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
+                        if (platform != null) {
+                            commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 136 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java

@@ -0,0 +1,136 @@
+package com.genersoft.iot.vmp.gb28181.transmit;
+
+import com.genersoft.iot.vmp.gb28181.SipLayer;
+import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
+import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.utils.GitUtil;
+import gov.nist.javax.sip.SipProviderImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import javax.sip.SipException;
+import javax.sip.header.CallIdHeader;
+import javax.sip.header.UserAgentHeader;
+import javax.sip.header.ViaHeader;
+import javax.sip.message.Message;
+import javax.sip.message.Request;
+import javax.sip.message.Response;
+import java.text.ParseException;
+
+/**
+ * 发送SIP消息
+ * @author lin
+ */
+@Component
+public class SIPSender {
+
+    private final Logger logger = LoggerFactory.getLogger(SIPSender.class);
+
+    @Autowired
+    private SipLayer sipLayer;
+
+    @Autowired
+    private GitUtil gitUtil;
+
+    @Autowired
+    private SipSubscribe sipSubscribe;
+
+    public void transmitRequest(String ip, Message message) throws SipException, ParseException {
+        transmitRequest(ip, message, null, null);
+    }
+
+    public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent) throws SipException, ParseException {
+        transmitRequest(ip, message, errorEvent, null);
+    }
+
+    public void transmitRequest(String ip, Message message, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, ParseException {
+        try {
+            ViaHeader viaHeader = (ViaHeader)message.getHeader(ViaHeader.NAME);
+            String transport = "UDP";
+            if (viaHeader == null) {
+                logger.warn("[消息头缺失]: ViaHeader, 使用默认的UDP方式处理数据");
+            }else {
+                transport = viaHeader.getTransport();
+            }
+            if (message.getHeader(UserAgentHeader.NAME) == null) {
+                try {
+                    message.addHeader(SipUtils.createUserAgentHeader(sipLayer.getSipFactory(), gitUtil));
+                } catch (ParseException e) {
+                    logger.error("添加UserAgentHeader失败", e);
+                }
+            }
+
+            CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME);
+            // 添加错误订阅
+            if (errorEvent != null) {
+                sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
+                    errorEvent.response(eventResult);
+                    sipSubscribe.removeErrorSubscribe(eventResult.callId);
+                    sipSubscribe.removeOkSubscribe(eventResult.callId);
+                }));
+            }
+            // 添加订阅
+            if (okEvent != null) {
+                sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult -> {
+                    okEvent.response(eventResult);
+                    sipSubscribe.removeOkSubscribe(eventResult.callId);
+                    sipSubscribe.removeErrorSubscribe(eventResult.callId);
+                });
+            }
+            if ("TCP".equals(transport)) {
+                SipProviderImpl tcpSipProvider = sipLayer.getTcpSipProvider(ip);
+                if (tcpSipProvider == null) {
+                    logger.error("[发送信息失败] 未找到tcp://{}的监听信息", ip);
+                    return;
+                }
+                if (message instanceof Request) {
+                    tcpSipProvider.sendRequest((Request)message);
+                }else if (message instanceof Response) {
+                    tcpSipProvider.sendResponse((Response)message);
+                }
+
+            } else if ("UDP".equals(transport)) {
+                SipProviderImpl sipProvider = sipLayer.getUdpSipProvider(ip);
+                if (sipProvider == null) {
+                    logger.error("[发送信息失败] 未找到udp://{}的监听信息", ip);
+                    return;
+                }
+                if (message instanceof Request) {
+                    sipProvider.sendRequest((Request)message);
+                }else if (message instanceof Response) {
+                    sipProvider.sendResponse((Response)message);
+                }
+            }
+        } finally {
+//            logger.info("[SEND]:SUCCESS:{}", message);
+        }
+    }
+
+    public CallIdHeader getNewCallIdHeader(String ip, String transport){
+        if (ObjectUtils.isEmpty(transport)) {
+            return sipLayer.getUdpSipProvider().getNewCallId();
+        }
+        SipProviderImpl sipProvider;
+        if (ObjectUtils.isEmpty(ip)) {
+            sipProvider = transport.equalsIgnoreCase("TCP") ? sipLayer.getTcpSipProvider()
+                    : sipLayer.getUdpSipProvider();
+        }else {
+            sipProvider = transport.equalsIgnoreCase("TCP") ? sipLayer.getTcpSipProvider(ip)
+                    : sipLayer.getUdpSipProvider(ip);
+        }
+
+        if (sipProvider == null) {
+            sipProvider = sipLayer.getUdpSipProvider();
+        }
+
+        if (sipProvider != null) {
+            return sipProvider.getNewCallId();
+        }else {
+            logger.warn("[新建CallIdHeader失败], ip={}, transport={}", ip, transport);
+            return null;
+        }
+    }
+}

+ 17 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/utils/MessageElement.java

@@ -0,0 +1,17 @@
+package com.genersoft.iot.vmp.gb28181.utils;
+
+import java.lang.annotation.*;
+
+/**
+ * @author gaofuwang
+ * @version 1.0
+ * @date 2022/6/28 14:58
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface MessageElement {
+    String value();
+
+    String subVal() default "";
+}

+ 44 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java

@@ -0,0 +1,44 @@
+package com.genersoft.iot.vmp.media.zlm.dto;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.alibaba.fastjson2.annotation.JSONField;
+
+import java.time.Instant;
+
+/**
+ * hook订阅-收流超时
+ * @author lin
+ */
+public class HookSubscribeForRtpServerTimeout implements IHookSubscribe{
+
+    private HookType hookType = HookType.on_rtp_server_timeout;
+
+    private JSONObject content;
+
+    @JSONField(format="yyyy-MM-dd HH:mm:ss")
+    private Instant expires;
+
+    @Override
+    public HookType getHookType() {
+        return hookType;
+    }
+
+    @Override
+    public JSONObject getContent() {
+        return content;
+    }
+
+    public void setContent(JSONObject content) {
+        this.content = content;
+    }
+
+    @Override
+    public Instant getExpires() {
+        return expires;
+    }
+
+    @Override
+    public void setExpires(Instant expires) {
+        this.expires = expires;
+    }
+}

+ 4 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java

@@ -0,0 +1,4 @@
+package com.genersoft.iot.vmp.media.zlm.dto;
+
+public class ServerKeepaliveData {
+}

+ 17 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java

@@ -0,0 +1,17 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件的参数
+ * @author lin
+ */
+public class HookParam {
+    private String mediaServerId;
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
+}

+ 36 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java

@@ -0,0 +1,36 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+public class HookResult {
+
+    private int code;
+    private String msg;
+
+
+    public HookResult() {
+    }
+
+    public HookResult(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public static HookResult SUCCESS(){
+        return new HookResult(0, "success");
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+}

+ 44 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java

@@ -0,0 +1,44 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+public class HookResultForOnPublish extends HookResult{
+
+    private boolean enable_audio;
+    private boolean enable_mp4;
+    private int mp4_max_second;
+
+    public HookResultForOnPublish() {
+    }
+
+    public static HookResultForOnPublish SUCCESS(){
+        return new HookResultForOnPublish(0, "success");
+    }
+
+    public HookResultForOnPublish(int code, String msg) {
+        setCode(code);
+        setMsg(msg);
+    }
+
+    public boolean isEnable_audio() {
+        return enable_audio;
+    }
+
+    public void setEnable_audio(boolean enable_audio) {
+        this.enable_audio = enable_audio;
+    }
+
+    public boolean isEnable_mp4() {
+        return enable_mp4;
+    }
+
+    public void setEnable_mp4(boolean enable_mp4) {
+        this.enable_mp4 = enable_mp4;
+    }
+
+    public int getMp4_max_second() {
+        return mp4_max_second;
+    }
+
+    public void setMp4_max_second(int mp4_max_second) {
+        this.mp4_max_second = mp4_max_second;
+    }
+}

+ 86 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java

@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件中的on_play事件的参数
+ * @author lin
+ */
+public class OnPlayHookParam extends HookParam{
+    private String id;
+    private String app;
+    private String stream;
+    private String ip;
+    private String params;
+    private int port;
+    private String schema;
+    private String vhost;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public String getVhost() {
+        return vhost;
+    }
+
+    public void setVhost(String vhost) {
+        this.vhost = vhost;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+    }
+}

+ 86 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java

@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件中的on_publish事件的参数
+ * @author lin
+ */
+public class OnPublishHookParam extends HookParam{
+    private String id;
+    private String app;
+    private String stream;
+    private String ip;
+    private String params;
+    private int port;
+    private String schema;
+    private String vhost;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public String getVhost() {
+        return vhost;
+    }
+
+    public void setVhost(String vhost) {
+        this.vhost = vhost;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+    }
+}

+ 53 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java

@@ -0,0 +1,53 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件中的on_rtp_server_timeout事件的参数
+ * @author lin
+ */
+public class OnRtpServerTimeoutHookParam extends HookParam{
+    private int local_port;
+    private String stream_id;
+    private int tcpMode;
+    private boolean re_use_port;
+    private String ssrc;
+
+    public int getLocal_port() {
+        return local_port;
+    }
+
+    public void setLocal_port(int local_port) {
+        this.local_port = local_port;
+    }
+
+    public String getStream_id() {
+        return stream_id;
+    }
+
+    public void setStream_id(String stream_id) {
+        this.stream_id = stream_id;
+    }
+
+    public int getTcpMode() {
+        return tcpMode;
+    }
+
+    public void setTcpMode(int tcpMode) {
+        this.tcpMode = tcpMode;
+    }
+
+    public boolean isRe_use_port() {
+        return re_use_port;
+    }
+
+    public void setRe_use_port(boolean re_use_port) {
+        this.re_use_port = re_use_port;
+    }
+
+    public String getSsrc() {
+        return ssrc;
+    }
+
+    public void setSsrc(String ssrc) {
+        this.ssrc = ssrc;
+    }
+}

+ 27 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java

@@ -0,0 +1,27 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件中的on_send_rtp_stopped事件的参数
+ * @author lin
+ */
+public class OnSendRtpStoppedHookParam extends HookParam{
+    private String app;
+    private String stream;
+
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+}

+ 20 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java

@@ -0,0 +1,20 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
+
+/**
+ * zlm hook事件中的on_play事件的参数
+ * @author lin
+ */
+public class OnServerKeepaliveHookParam extends HookParam{
+
+    private ServerKeepaliveData data;
+
+    public ServerKeepaliveData getData() {
+        return data;
+    }
+
+    public void setData(ServerKeepaliveData data) {
+        this.data = data;
+    }
+}

+ 433 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java

@@ -0,0 +1,433 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
+
+import java.util.List;
+
+/**
+ * @author lin
+ */
+public class OnStreamChangedHookParam extends HookParam{
+
+    /**
+     * 注册/注销
+     */
+    private boolean regist;
+
+    /**
+     * 应用名
+     */
+    private String app;
+
+    /**
+     * 流id
+     */
+    private String stream;
+
+    /**
+     * 推流鉴权Id
+     */
+    private String callId;
+
+    /**
+     * 观看总人数,包括hls/rtsp/rtmp/http-flv/ws-flv
+     */
+    private String totalReaderCount;
+
+    /**
+     * 协议 包括hls/rtsp/rtmp/http-flv/ws-flv
+     */
+    private String schema;
+
+
+    /**
+     * 产生源类型,
+     * unknown = 0,
+     * rtmp_push=1,
+     * rtsp_push=2,
+     * rtp_push=3,
+     * pull=4,
+     * ffmpeg_pull=5,
+     * mp4_vod=6,
+     * device_chn=7
+     */
+    private int originType;
+
+    /**
+     * 客户端和服务器网络信息,可能为null类型
+     */
+    private OriginSock originSock;
+
+    /**
+     * 产生源类型的字符串描述
+     */
+    private String originTypeStr;
+
+    /**
+     * 产生源的url
+     */
+    private String originUrl;
+
+    /**
+     * 服务器id
+     */
+    private String severId;
+
+    /**
+     * GMT unix系统时间戳,单位秒
+     */
+    private Long createStamp;
+
+    /**
+     * 存活时间,单位秒
+     */
+    private Long aliveSecond;
+
+    /**
+     * 数据产生速度,单位byte/s
+     */
+    private Long bytesSpeed;
+
+    /**
+     * 音视频轨道
+     */
+    private List<MediaTrack> tracks;
+
+    /**
+     * 音视频轨道
+     */
+    private String vhost;
+
+    public boolean isRegist() {
+        return regist;
+    }
+
+    public void setRegist(boolean regist) {
+        this.regist = regist;
+    }
+
+    /**
+     * 是否是docker部署, docker部署不会自动更新zlm使用的端口,需要自己手动修改
+     */
+    private boolean docker;
+
+    public static class MediaTrack {
+        /**
+         * 音频通道数
+         */
+        private int channels;
+
+        /**
+         *  H264 = 0, H265 = 1, AAC = 2, G711A = 3, G711U = 4
+         */
+        private int codecId;
+
+        /**
+         * 编码类型名称 CodecAAC CodecH264
+         */
+        private String codecIdName;
+
+        /**
+         * Video = 0, Audio = 1
+         */
+        private int codecType;
+
+        /**
+         * 轨道是否准备就绪
+         */
+        private boolean ready;
+
+        /**
+         * 音频采样位数
+         */
+        private int sampleBit;
+
+        /**
+         * 音频采样率
+         */
+        private int sampleRate;
+
+        /**
+         * 视频fps
+         */
+        private int fps;
+
+        /**
+         * 视频高
+         */
+        private int height;
+
+        /**
+         * 视频宽
+         */
+        private int width;
+
+        public int getChannels() {
+            return channels;
+        }
+
+        public void setChannels(int channels) {
+            this.channels = channels;
+        }
+
+        public int getCodecId() {
+            return codecId;
+        }
+
+        public void setCodecId(int codecId) {
+            this.codecId = codecId;
+        }
+
+        public String getCodecIdName() {
+            return codecIdName;
+        }
+
+        public void setCodecIdName(String codecIdName) {
+            this.codecIdName = codecIdName;
+        }
+
+        public int getCodecType() {
+            return codecType;
+        }
+
+        public void setCodecType(int codecType) {
+            this.codecType = codecType;
+        }
+
+        public boolean isReady() {
+            return ready;
+        }
+
+        public void setReady(boolean ready) {
+            this.ready = ready;
+        }
+
+        public int getSampleBit() {
+            return sampleBit;
+        }
+
+        public void setSampleBit(int sampleBit) {
+            this.sampleBit = sampleBit;
+        }
+
+        public int getSampleRate() {
+            return sampleRate;
+        }
+
+        public void setSampleRate(int sampleRate) {
+            this.sampleRate = sampleRate;
+        }
+
+        public int getFps() {
+            return fps;
+        }
+
+        public void setFps(int fps) {
+            this.fps = fps;
+        }
+
+        public int getHeight() {
+            return height;
+        }
+
+        public void setHeight(int height) {
+            this.height = height;
+        }
+
+        public int getWidth() {
+            return width;
+        }
+
+        public void setWidth(int width) {
+            this.width = width;
+        }
+    }
+
+    public static class OriginSock{
+        private String identifier;
+        private String local_ip;
+        private int local_port;
+        private String peer_ip;
+        private int peer_port;
+
+        public String getIdentifier() {
+            return identifier;
+        }
+
+        public void setIdentifier(String identifier) {
+            this.identifier = identifier;
+        }
+
+        public String getLocal_ip() {
+            return local_ip;
+        }
+
+        public void setLocal_ip(String local_ip) {
+            this.local_ip = local_ip;
+        }
+
+        public int getLocal_port() {
+            return local_port;
+        }
+
+        public void setLocal_port(int local_port) {
+            this.local_port = local_port;
+        }
+
+        public String getPeer_ip() {
+            return peer_ip;
+        }
+
+        public void setPeer_ip(String peer_ip) {
+            this.peer_ip = peer_ip;
+        }
+
+        public int getPeer_port() {
+            return peer_port;
+        }
+
+        public void setPeer_port(int peer_port) {
+            this.peer_port = peer_port;
+        }
+    }
+
+    private StreamContent streamInfo;
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getTotalReaderCount() {
+        return totalReaderCount;
+    }
+
+    public void setTotalReaderCount(String totalReaderCount) {
+        this.totalReaderCount = totalReaderCount;
+    }
+
+
+    public int getOriginType() {
+        return originType;
+    }
+
+    public void setOriginType(int originType) {
+        this.originType = originType;
+    }
+
+
+    public String getOriginTypeStr() {
+        return originTypeStr;
+    }
+
+    public void setOriginTypeStr(String originTypeStr) {
+        this.originTypeStr = originTypeStr;
+    }
+
+    public String getOriginUrl() {
+        return originUrl;
+    }
+
+    public void setOriginUrl(String originUrl) {
+        this.originUrl = originUrl;
+    }
+
+    public Long getCreateStamp() {
+        return createStamp;
+    }
+
+    public void setCreateStamp(Long createStamp) {
+        this.createStamp = createStamp;
+    }
+
+    public Long getAliveSecond() {
+        return aliveSecond;
+    }
+
+    public void setAliveSecond(Long aliveSecond) {
+        this.aliveSecond = aliveSecond;
+    }
+
+    public List<MediaTrack> getTracks() {
+        return tracks;
+    }
+
+    public void setTracks(List<MediaTrack> tracks) {
+        this.tracks = tracks;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public void setOriginSock(OriginSock originSock) {
+        this.originSock = originSock;
+    }
+
+    public Long getBytesSpeed() {
+        return bytesSpeed;
+    }
+
+    public void setBytesSpeed(Long bytesSpeed) {
+        this.bytesSpeed = bytesSpeed;
+    }
+
+    public String getVhost() {
+        return vhost;
+    }
+
+    public void setVhost(String vhost) {
+        this.vhost = vhost;
+    }
+
+    public OriginSock getOriginSock() {
+        return originSock;
+    }
+
+    public boolean isDocker() {
+        return docker;
+    }
+
+    public void setDocker(boolean docker) {
+        this.docker = docker;
+    }
+
+    public StreamContent getStreamInfo() {
+        return streamInfo;
+    }
+
+    public void setStreamInfo(StreamContent streamInfo) {
+        this.streamInfo = streamInfo;
+    }
+
+    public String getSeverId() {
+        return severId;
+    }
+
+    public void setSeverId(String severId) {
+        this.severId = severId;
+    }
+
+    public String getCallId() {
+        return callId;
+    }
+
+    public void setCallId(String callId) {
+        this.callId = callId;
+    }
+}

+ 41 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java

@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+public class OnStreamNoneReaderHookParam extends HookParam{
+
+    private String schema;
+    private String app;
+    private String stream;
+    private String vhost;
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getVhost() {
+        return vhost;
+    }
+
+    public void setVhost(String vhost) {
+        this.vhost = vhost;
+    }
+}

+ 86 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java

@@ -0,0 +1,86 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+/**
+ * zlm hook事件中的on_stream_not_found事件的参数
+ * @author lin
+ */
+public class OnStreamNotFoundHookParam extends HookParam{
+    private String id;
+    private String app;
+    private String stream;
+    private String ip;
+    private String params;
+    private int port;
+    private String schema;
+    private String vhost;
+
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getParams() {
+        return params;
+    }
+
+    public void setParams(String params) {
+        this.params = params;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    public String getVhost() {
+        return vhost;
+    }
+
+    public void setVhost(String vhost) {
+        this.vhost = vhost;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s://%s:%s/%s/%s?%s", schema, ip, port, app, stream, params);
+    }
+}

+ 23 - 0
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java

@@ -0,0 +1,23 @@
+package com.genersoft.iot.vmp.media.zlm.dto.hook;
+
+public enum OriginType {
+    // 不可调整顺序
+    UNKNOWN("UNKNOWN"),
+    RTMP_PUSH("PUSH"),
+    RTSP_PUSH("PUSH"),
+    RTP_PUSH("RTP"),
+    PULL("PULL"),
+    FFMPEG_PULL("PULL"),
+    MP4_VOD("MP4_VOD"),
+    DEVICE_CHN("DEVICE_CHN"),
+    RTC_PUSH("PUSH");
+
+    private final String type;
+    OriginType(String type) {
+        this.type = type;
+    }
+
+    public String getType() {
+        return type;
+    }
+}

+ 50 - 0
src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java

@@ -0,0 +1,50 @@
+package com.genersoft.iot.vmp.service.bean;
+
+public class MediaServerLoad {
+
+    private String id;
+    private int push;
+    private int proxy;
+    private int gbReceive;
+    private int gbSend;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public int getPush() {
+        return push;
+    }
+
+    public void setPush(int push) {
+        this.push = push;
+    }
+
+    public int getProxy() {
+        return proxy;
+    }
+
+    public void setProxy(int proxy) {
+        this.proxy = proxy;
+    }
+
+    public int getGbReceive() {
+        return gbReceive;
+    }
+
+    public void setGbReceive(int gbReceive) {
+        this.gbReceive = gbReceive;
+    }
+
+    public int getGbSend() {
+        return gbSend;
+    }
+
+    public void setGbSend(int gbSend) {
+        this.gbSend = gbSend;
+    }
+}

+ 36 - 0
src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java

@@ -0,0 +1,36 @@
+package com.genersoft.iot.vmp.utils;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.utils.redis.RedisUtil;
+
+import java.util.Objects;
+
+/**
+ * JsonUtil
+ *
+ * @author KunLong-Luo
+ * @version 1.0.0
+ * @since 2023/2/2 15:24
+ */
+public final class JsonUtil {
+
+    private JsonUtil() {
+    }
+
+    /**
+     * safe json type conversion
+     *
+     * @param key   redis key
+     * @param clazz cast type
+     * @param <T>
+     * @return result type
+     */
+    public static <T> T redisJsonToObject(String key, Class<T> clazz) {
+        Object jsonObject = RedisUtil.get(key);
+        if (Objects.isNull(jsonObject)) {
+            return null;
+        }
+        return clazz.cast(jsonObject);
+    }
+}

+ 150 - 0
src/main/java/com/genersoft/iot/vmp/utils/UJson.java

@@ -0,0 +1,150 @@
+package com.genersoft.iot.vmp.utils;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @author gaofuwang
+ * @version 1.0
+ * @date 2022/3/11 10:17
+ */
+public class UJson {
+
+    private static Logger logger = LoggerFactory.getLogger(UJson.class);
+    public static final ObjectMapper JSON_MAPPER = new ObjectMapper();
+
+    static {
+        JSON_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
+    }
+
+    private ObjectNode node;
+
+    public UJson(){
+        this.node = JSON_MAPPER.createObjectNode();
+    }
+
+    public UJson(String json){
+        if(StringUtils.isBlank(json)){
+            this.node = JSON_MAPPER.createObjectNode();
+        }else{
+            try {
+                this.node = JSON_MAPPER.readValue(json, ObjectNode.class);
+            }catch (Exception e){
+                logger.error(e.getMessage(), e);
+                this.node = JSON_MAPPER.createObjectNode();
+            }
+        }
+    }
+
+    public UJson(ObjectNode node){
+        this.node = node;
+    }
+
+    public String asText(String key){
+        JsonNode jsonNode = node.get(key);
+        if(Objects.isNull(jsonNode)){
+            return "";
+        }
+        return jsonNode.asText();
+    }
+
+    public String asText(String key, String defaultVal){
+        JsonNode jsonNode = node.get(key);
+        if(Objects.isNull(jsonNode)){
+            return "";
+        }
+        return jsonNode.asText(defaultVal);
+    }
+
+    public UJson put(String key, String value){
+        this.node.put(key, value);
+        return this;
+    }
+
+    public UJson put(String key, Integer value){
+        this.node.put(key, value);
+        return this;
+    }
+
+    public static UJson json(){
+        return new UJson();
+    }
+
+    public static UJson json(String json){
+        return new UJson(json);
+    }
+
+    public static <T> T readJson(String json, Class<T> clazz){
+        if(StringUtils.isBlank(json)){
+            return null;
+        }
+        try {
+            return JSON_MAPPER.readValue(json, clazz);
+        }catch (Exception e){
+            logger.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+    public static String writeJson(Object object) {
+        try{
+            return JSON_MAPPER.writeValueAsString(object);
+        }catch (Exception e){
+            logger.error(e.getMessage(), e);
+            return "";
+        }
+    }
+
+    @Override
+    public String toString() {
+        return node.toString();
+    }
+
+    public int asInt(String key, int defValue) {
+        JsonNode jsonNode = this.node.get(key);
+        if(Objects.isNull(jsonNode)){
+            return defValue;
+        }
+        return jsonNode.asInt(defValue);
+    }
+
+    public UJson getSon(String key) {
+        JsonNode sonNode = this.node.get(key);
+        if(Objects.isNull(sonNode)){
+            return new UJson();
+        }
+        return new UJson((ObjectNode) sonNode);
+    }
+
+    public UJson set(String key, ObjectNode sonNode) {
+        this.node.set(key, sonNode);
+        return this;
+    }
+
+    public UJson set(String key, UJson sonNode) {
+        this.node.set(key, sonNode.node);
+        return this;
+    }
+
+    public Iterator<Map.Entry<String, JsonNode>> fields() {
+        return this.node.fields();
+    }
+
+    public ObjectNode getNode() {
+        return this.node;
+    }
+
+    public UJson setAll(UJson json) {
+        this.node.setAll(json.node);
+        return this;
+    }
+}

+ 31 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java

@@ -0,0 +1,31 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import org.springframework.web.context.request.async.DeferredResult;
+
+public class DeferredResultEx<T> {
+
+    private DeferredResult<T> deferredResult;
+
+    private DeferredResultFilter filter;
+
+    public DeferredResultEx(DeferredResult<T> result) {
+        this.deferredResult = result;
+    }
+
+
+    public DeferredResult<T> getDeferredResult() {
+        return deferredResult;
+    }
+
+    public void setDeferredResult(DeferredResult<T> deferredResult) {
+        this.deferredResult = deferredResult;
+    }
+
+    public DeferredResultFilter getFilter() {
+        return filter;
+    }
+
+    public void setFilter(DeferredResultFilter filter) {
+        this.filter = filter;
+    }
+}

+ 6 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java

@@ -0,0 +1,6 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+public interface DeferredResultFilter {
+
+    Object handler(Object o);
+}

+ 22 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaceInfo.java

@@ -0,0 +1,22 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+public class ResourceBaceInfo {
+    private int total;
+    private int online;
+
+    public int getTotal() {
+        return total;
+    }
+
+    public void setTotal(int total) {
+        this.total = total;
+    }
+
+    public int getOnline() {
+        return online;
+    }
+
+    public void setOnline(int online) {
+        this.online = online;
+    }
+}

+ 41 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java

@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+public class ResourceInfo {
+
+    private ResourceBaceInfo device;
+    private ResourceBaceInfo channel;
+    private ResourceBaceInfo push;
+    private ResourceBaceInfo proxy;
+
+    public ResourceBaceInfo getDevice() {
+        return device;
+    }
+
+    public void setDevice(ResourceBaceInfo device) {
+        this.device = device;
+    }
+
+    public ResourceBaceInfo getChannel() {
+        return channel;
+    }
+
+    public void setChannel(ResourceBaceInfo channel) {
+        this.channel = channel;
+    }
+
+    public ResourceBaceInfo getPush() {
+        return push;
+    }
+
+    public void setPush(ResourceBaceInfo push) {
+        this.push = push;
+    }
+
+    public ResourceBaceInfo getProxy() {
+        return proxy;
+    }
+
+    public void setProxy(ResourceBaceInfo proxy) {
+        this.proxy = proxy;
+    }
+}

+ 411 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java

@@ -0,0 +1,411 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.genersoft.iot.vmp.common.StreamInfo;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "流信息")
+public class StreamContent {
+
+    @Schema(description = "应用名")
+    private String app;
+
+    @Schema(description = "流ID")
+    private String stream;
+
+    @Schema(description = "IP")
+    private String ip;
+
+    @Schema(description = "HTTP-FLV流地址")
+    private String flv;
+
+    @Schema(description = "HTTPS-FLV流地址")
+    private String https_flv;
+
+    @Schema(description = "Websocket-FLV流地址")
+    private String ws_flv;
+
+    @Schema(description = "Websockets-FLV流地址")
+    private String wss_flv;
+
+    @Schema(description = "HTTP-FMP4流地址")
+    private String fmp4;
+
+    @Schema(description = "HTTPS-FMP4流地址")
+    private String https_fmp4;
+
+    @Schema(description = "Websocket-FMP4流地址")
+    private String ws_fmp4;
+
+    @Schema(description = "Websockets-FMP4流地址")
+    private String wss_fmp4;
+
+    @Schema(description = "HLS流地址")
+    private String hls;
+
+    @Schema(description = "HTTPS-HLS流地址")
+    private String https_hls;
+
+    @Schema(description = "Websocket-HLS流地址")
+    private String ws_hls;
+
+    @Schema(description = "Websockets-HLS流地址")
+    private String wss_hls;
+
+    @Schema(description = "HTTP-TS流地址")
+    private String ts;
+
+    @Schema(description = "HTTPS-TS流地址")
+    private String https_ts;
+
+    @Schema(description = "Websocket-TS流地址")
+    private String ws_ts;
+
+    @Schema(description = "Websockets-TS流地址")
+    private String wss_ts;
+
+    @Schema(description = "RTMP流地址")
+    private String rtmp;
+
+    @Schema(description = "RTMPS流地址")
+    private String rtmps;
+
+    @Schema(description = "RTSP流地址")
+    private String rtsp;
+
+    @Schema(description = "RTSPS流地址")
+    private String rtsps;
+
+    @Schema(description = "RTC流地址")
+    private String rtc;
+
+    @Schema(description = "RTCS流地址")
+    private String rtcs;
+
+    @Schema(description = "流媒体ID")
+    private String mediaServerId;
+
+    @Schema(description = "流编码信息")
+    private Object tracks;
+
+    @Schema(description = "开始时间")
+    private String startTime;
+
+    @Schema(description = "结束时间")
+    private String endTime;
+
+    private double progress;
+
+    public StreamContent(StreamInfo streamInfo) {
+        if (streamInfo == null) {
+            return;
+        }
+        this.app = streamInfo.getApp();
+        this.stream = streamInfo.getStream();
+        if (streamInfo.getFlv() != null) {
+            this.flv = streamInfo.getFlv().getUrl();
+        }
+        if (streamInfo.getHttps_flv() != null) {
+            this.https_flv = streamInfo.getHttps_flv().getUrl();
+        }
+        if (streamInfo.getWs_flv() != null) {
+            this.ws_flv = streamInfo.getWs_flv().getUrl();
+        }
+        if (streamInfo.getWss_flv() != null) {
+            this.wss_flv = streamInfo.getWss_flv().getUrl();
+        }
+        if (streamInfo.getFmp4() != null) {
+            this.fmp4 = streamInfo.getFmp4().getUrl();
+        }
+        if (streamInfo.getWs_fmp4() != null) {
+            this.ws_fmp4 = streamInfo.getWs_fmp4().getUrl();
+        }
+        if (streamInfo.getWss_fmp4() != null) {
+            this.wss_fmp4 = streamInfo.getWss_fmp4().getUrl();
+        }
+        if (streamInfo.getHls() != null) {
+            this.hls = streamInfo.getHls().getUrl();
+        }
+        if (streamInfo.getHttps_hls() != null) {
+            this.https_hls = streamInfo.getHttps_hls().getUrl();
+        }
+        if (streamInfo.getWs_hls() != null) {
+            this.ws_hls = streamInfo.getWs_hls().getUrl();
+        }
+        if (streamInfo.getWss_hls() != null) {
+            this.wss_hls = streamInfo.getWss_hls().getUrl();
+        }
+        if (streamInfo.getTs() != null) {
+            this.ts = streamInfo.getTs().getUrl();
+        }
+        if (streamInfo.getHttps_ts() != null) {
+            this.https_ts = streamInfo.getHttps_ts().getUrl();
+        }
+        if (streamInfo.getWs_ts() != null) {
+            this.ws_ts = streamInfo.getWs_ts().getUrl();
+        }
+        if (streamInfo.getRtmp() != null) {
+            this.rtmp = streamInfo.getRtmp().getUrl();
+        }
+        if (streamInfo.getRtmps() != null) {
+            this.rtmps = streamInfo.getRtmps().getUrl();
+        }
+        if (streamInfo.getRtsp() != null) {
+            this.rtsp = streamInfo.getRtsp().getUrl();
+        }
+        if (streamInfo.getRtsps() != null) {
+            this.rtsps = streamInfo.getRtsps().getUrl();
+        }
+        if (streamInfo.getRtc() != null) {
+            this.rtc = streamInfo.getRtc().getUrl();
+        }
+        if (streamInfo.getRtcs() != null) {
+            this.rtcs = streamInfo.getRtcs().getUrl();
+        }
+
+        this.mediaServerId = streamInfo.getMediaServerId();
+        this.tracks = streamInfo.getTracks();
+        this.startTime = streamInfo.getStartTime();
+        this.endTime = streamInfo.getEndTime();
+        this.progress = streamInfo.getProgress();
+    }
+
+    public String getApp() {
+        return app;
+    }
+
+    public void setApp(String app) {
+        this.app = app;
+    }
+
+    public String getStream() {
+        return stream;
+    }
+
+    public void setStream(String stream) {
+        this.stream = stream;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getFlv() {
+        return flv;
+    }
+
+    public void setFlv(String flv) {
+        this.flv = flv;
+    }
+
+    public String getHttps_flv() {
+        return https_flv;
+    }
+
+    public void setHttps_flv(String https_flv) {
+        this.https_flv = https_flv;
+    }
+
+    public String getWs_flv() {
+        return ws_flv;
+    }
+
+    public void setWs_flv(String ws_flv) {
+        this.ws_flv = ws_flv;
+    }
+
+    public String getWss_flv() {
+        return wss_flv;
+    }
+
+    public void setWss_flv(String wss_flv) {
+        this.wss_flv = wss_flv;
+    }
+
+    public String getFmp4() {
+        return fmp4;
+    }
+
+    public void setFmp4(String fmp4) {
+        this.fmp4 = fmp4;
+    }
+
+    public String getHttps_fmp4() {
+        return https_fmp4;
+    }
+
+    public void setHttps_fmp4(String https_fmp4) {
+        this.https_fmp4 = https_fmp4;
+    }
+
+    public String getWs_fmp4() {
+        return ws_fmp4;
+    }
+
+    public void setWs_fmp4(String ws_fmp4) {
+        this.ws_fmp4 = ws_fmp4;
+    }
+
+    public String getWss_fmp4() {
+        return wss_fmp4;
+    }
+
+    public void setWss_fmp4(String wss_fmp4) {
+        this.wss_fmp4 = wss_fmp4;
+    }
+
+    public String getHls() {
+        return hls;
+    }
+
+    public void setHls(String hls) {
+        this.hls = hls;
+    }
+
+    public String getHttps_hls() {
+        return https_hls;
+    }
+
+    public void setHttps_hls(String https_hls) {
+        this.https_hls = https_hls;
+    }
+
+    public String getWs_hls() {
+        return ws_hls;
+    }
+
+    public void setWs_hls(String ws_hls) {
+        this.ws_hls = ws_hls;
+    }
+
+    public String getWss_hls() {
+        return wss_hls;
+    }
+
+    public void setWss_hls(String wss_hls) {
+        this.wss_hls = wss_hls;
+    }
+
+    public String getTs() {
+        return ts;
+    }
+
+    public void setTs(String ts) {
+        this.ts = ts;
+    }
+
+    public String getHttps_ts() {
+        return https_ts;
+    }
+
+    public void setHttps_ts(String https_ts) {
+        this.https_ts = https_ts;
+    }
+
+    public String getWs_ts() {
+        return ws_ts;
+    }
+
+    public void setWs_ts(String ws_ts) {
+        this.ws_ts = ws_ts;
+    }
+
+    public String getWss_ts() {
+        return wss_ts;
+    }
+
+    public void setWss_ts(String wss_ts) {
+        this.wss_ts = wss_ts;
+    }
+
+    public String getRtmp() {
+        return rtmp;
+    }
+
+    public void setRtmp(String rtmp) {
+        this.rtmp = rtmp;
+    }
+
+    public String getRtmps() {
+        return rtmps;
+    }
+
+    public void setRtmps(String rtmps) {
+        this.rtmps = rtmps;
+    }
+
+    public String getRtsp() {
+        return rtsp;
+    }
+
+    public void setRtsp(String rtsp) {
+        this.rtsp = rtsp;
+    }
+
+    public String getRtsps() {
+        return rtsps;
+    }
+
+    public void setRtsps(String rtsps) {
+        this.rtsps = rtsps;
+    }
+
+    public String getRtc() {
+        return rtc;
+    }
+
+    public void setRtc(String rtc) {
+        this.rtc = rtc;
+    }
+
+    public String getRtcs() {
+        return rtcs;
+    }
+
+    public void setRtcs(String rtcs) {
+        this.rtcs = rtcs;
+    }
+
+    public String getMediaServerId() {
+        return mediaServerId;
+    }
+
+    public void setMediaServerId(String mediaServerId) {
+        this.mediaServerId = mediaServerId;
+    }
+
+    public Object getTracks() {
+        return tracks;
+    }
+
+    public void setTracks(Object tracks) {
+        this.tracks = tracks;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public double getProgress() {
+        return progress;
+    }
+
+    public void setProgress(double progress) {
+        this.progress = progress;
+    }
+}

+ 47 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java

@@ -0,0 +1,47 @@
+package com.genersoft.iot.vmp.vmanager.bean;
+
+import com.genersoft.iot.vmp.common.VersionPo;
+import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.conf.UserSetting;
+import com.genersoft.iot.vmp.conf.VersionInfo;
+
+public class SystemConfigInfo {
+
+    private int serverPort;
+    private SipConfig sip;
+    private UserSetting addOn;
+    private VersionPo version;
+
+    public int getServerPort() {
+        return serverPort;
+    }
+
+    public void setServerPort(int serverPort) {
+        this.serverPort = serverPort;
+    }
+
+    public SipConfig getSip() {
+        return sip;
+    }
+
+    public void setSip(SipConfig sip) {
+        this.sip = sip;
+    }
+
+    public UserSetting getAddOn() {
+        return addOn;
+    }
+
+    public void setAddOn(UserSetting addOn) {
+        this.addOn = addOn;
+    }
+
+    public VersionPo getVersion() {
+        return version;
+    }
+
+    public void setVersion(VersionPo version) {
+        this.version = version;
+    }
+}
+

+ 555 - 0
src/main/java/com/genersoft/iot/vmp/web/gb28181/dto/DeviceChannelExtend.java

@@ -0,0 +1,555 @@
+package com.genersoft.iot.vmp.web.gb28181.dto;
+
+public class DeviceChannelExtend {
+
+
+	/**
+	 * 数据库自增ID
+	 */
+	private int id;
+
+	/**
+	 * 通道id
+	 */
+	private String channelId;
+
+	/**
+	 * 设备id
+	 */
+	private String deviceId;
+	
+	/**
+	 * 通道名
+	 */
+	private String name;
+
+	private String deviceName;
+
+	private int deviceOnline;
+	
+	/**
+	 * 生产厂商
+	 */
+	private String manufacture;
+	
+	/**
+	 * 型号
+	 */
+	private String model;
+	
+	/**
+	 * 设备归属
+	 */
+	private String owner;
+	
+	/**
+	 * 行政区域
+	 */
+	private String civilCode;
+	
+	/**
+	 * 警区
+	 */
+	private String block;
+
+	/**
+	 * 安装地址
+	 */
+	private String address;
+	
+	/**
+	 * 是否有子设备 1有, 0没有
+	 */
+	private int parental;
+	
+	/**
+	 * 父级id
+	 */
+	private String parentId;
+	
+	/**
+	 * 信令安全模式  缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
+	 */
+	private int safetyWay;
+	
+	/**
+	 * 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
+	 */
+	private int registerWay;
+	
+	/**
+	 * 证书序列号
+	 */
+	private String certNum;
+	
+	/**
+	 * 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
+	 */
+	private int certifiable;
+	
+	/**
+	 * 证书无效原因码
+	 */
+	private int errCode;
+	
+	/**
+	 * 证书终止有效期
+	 */
+	private String endTime;
+	
+	/**
+	 * 保密属性 缺省为0; 0:不涉密, 1:涉密
+	 */
+	private String secrecy;
+	
+	/**
+	 * IP地址
+	 */
+	private String ipAddress;
+	
+	/**
+	 * 端口号
+	 */
+	private int port;
+	
+	/**
+	 * 密码
+	 */
+	private String password;
+
+	/**
+	 * 云台类型
+	 */
+	private int PTZType;
+
+	/**
+	 * 云台类型描述字符串
+	 */
+	private String PTZTypeText;
+
+	/**
+	 * 创建时间
+	 */
+	private String createTime;
+
+	/**
+	 * 更新时间
+	 */
+	private String updateTime;
+	
+	/**
+	 * 在线/离线
+	 * 1在线,0离线
+	 * 默认在线
+	 * 信令:
+	 * <Status>ON</Status>
+	 * <Status>OFF</Status>
+	 * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
+	 */
+	private int status;
+
+	/**
+	 * 经度
+	 */
+	private double longitude;
+	
+	/**
+	 * 纬度
+	 */
+	private double latitude;
+
+	/**
+	 * 经度 GCJ02
+	 */
+	private double longitudeGcj02;
+
+	/**
+	 * 纬度 GCJ02
+	 */
+	private double latitudeGcj02;
+
+	/**
+	 * 经度 WGS84
+	 */
+	private double longitudeWgs84;
+
+	/**
+	 * 纬度 WGS84
+	 */
+	private double latitudeWgs84;
+
+	/**
+	 * 子设备数
+	 */
+	private int subCount;
+
+	/**
+	 * 流唯一编号,存在表示正在直播
+	 */
+	private String  streamId;
+
+	/**
+	 *  是否含有音频
+	 */
+	private boolean hasAudio;
+
+	/**
+	 * 标记通道的类型,0->国标通道 1->直播流通道 2->业务分组/虚拟组织/行政区划
+	 */
+	private int channelType;
+
+	/**
+	 * 业务分组
+	 */
+	private String businessGroupId;
+
+	/**
+	 * GPS的更新时间
+	 */
+	private String gpsTime;
+
+	public int getId() {
+		return id;
+	}
+
+	public void setId(int id) {
+		this.id = id;
+	}
+
+	public String getDeviceId() {
+		return deviceId;
+	}
+
+	public void setDeviceId(String deviceId) {
+		this.deviceId = deviceId;
+	}
+
+	public void setPTZType(int PTZType) {
+		this.PTZType = PTZType;
+		switch (PTZType) {
+			case 0:
+				this.PTZTypeText = "未知";
+				break;
+			case 1:
+				this.PTZTypeText = "球机";
+				break;
+			case 2:
+				this.PTZTypeText = "半球";
+				break;
+			case 3:
+				this.PTZTypeText = "固定枪机";
+				break;
+			case 4:
+				this.PTZTypeText = "遥控枪机";
+				break;
+		}
+	}
+
+	public String getChannelId() {
+		return channelId;
+	}
+
+	public void setChannelId(String channelId) {
+		this.channelId = channelId;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getManufacture() {
+		return manufacture;
+	}
+
+	public void setManufacture(String manufacture) {
+		this.manufacture = manufacture;
+	}
+
+	public String getModel() {
+		return model;
+	}
+
+	public void setModel(String model) {
+		this.model = model;
+	}
+
+	public String getOwner() {
+		return owner;
+	}
+
+	public void setOwner(String owner) {
+		this.owner = owner;
+	}
+
+	public String getCivilCode() {
+		return civilCode;
+	}
+
+	public void setCivilCode(String civilCode) {
+		this.civilCode = civilCode;
+	}
+
+	public String getBlock() {
+		return block;
+	}
+
+	public void setBlock(String block) {
+		this.block = block;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	public int getParental() {
+		return parental;
+	}
+
+	public void setParental(int parental) {
+		this.parental = parental;
+	}
+
+	public String getParentId() {
+		return parentId;
+	}
+
+	public void setParentId(String parentId) {
+		this.parentId = parentId;
+	}
+
+	public int getSafetyWay() {
+		return safetyWay;
+	}
+
+	public void setSafetyWay(int safetyWay) {
+		this.safetyWay = safetyWay;
+	}
+
+	public int getRegisterWay() {
+		return registerWay;
+	}
+
+	public void setRegisterWay(int registerWay) {
+		this.registerWay = registerWay;
+	}
+
+	public String getCertNum() {
+		return certNum;
+	}
+
+	public void setCertNum(String certNum) {
+		this.certNum = certNum;
+	}
+
+	public int getCertifiable() {
+		return certifiable;
+	}
+
+	public void setCertifiable(int certifiable) {
+		this.certifiable = certifiable;
+	}
+
+	public int getErrCode() {
+		return errCode;
+	}
+
+	public void setErrCode(int errCode) {
+		this.errCode = errCode;
+	}
+
+	public String getEndTime() {
+		return endTime;
+	}
+
+	public void setEndTime(String endTime) {
+		this.endTime = endTime;
+	}
+
+	public String getSecrecy() {
+		return secrecy;
+	}
+
+	public void setSecrecy(String secrecy) {
+		this.secrecy = secrecy;
+	}
+
+	public String getIpAddress() {
+		return ipAddress;
+	}
+
+	public void setIpAddress(String ipAddress) {
+		this.ipAddress = ipAddress;
+	}
+
+	public int getPort() {
+		return port;
+	}
+
+	public void setPort(int port) {
+		this.port = port;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+	public int getPTZType() {
+		return PTZType;
+	}
+
+	public String getPTZTypeText() {
+		return PTZTypeText;
+	}
+
+	public void setPTZTypeText(String PTZTypeText) {
+		this.PTZTypeText = PTZTypeText;
+	}
+
+	public int getStatus() {
+		return status;
+	}
+
+	public void setStatus(int status) {
+		this.status = status;
+	}
+
+	public double getLongitude() {
+		return longitude;
+	}
+
+	public void setLongitude(double longitude) {
+		this.longitude = longitude;
+	}
+
+	public double getLatitude() {
+		return latitude;
+	}
+
+	public void setLatitude(double latitude) {
+		this.latitude = latitude;
+	}
+
+	public double getLongitudeGcj02() {
+		return longitudeGcj02;
+	}
+
+	public void setLongitudeGcj02(double longitudeGcj02) {
+		this.longitudeGcj02 = longitudeGcj02;
+	}
+
+	public double getLatitudeGcj02() {
+		return latitudeGcj02;
+	}
+
+	public void setLatitudeGcj02(double latitudeGcj02) {
+		this.latitudeGcj02 = latitudeGcj02;
+	}
+
+	public double getLongitudeWgs84() {
+		return longitudeWgs84;
+	}
+
+	public void setLongitudeWgs84(double longitudeWgs84) {
+		this.longitudeWgs84 = longitudeWgs84;
+	}
+
+	public double getLatitudeWgs84() {
+		return latitudeWgs84;
+	}
+
+	public void setLatitudeWgs84(double latitudeWgs84) {
+		this.latitudeWgs84 = latitudeWgs84;
+	}
+
+	public int getSubCount() {
+		return subCount;
+	}
+
+	public void setSubCount(int subCount) {
+		this.subCount = subCount;
+	}
+
+	public boolean isHasAudio() {
+		return hasAudio;
+	}
+
+	public void setHasAudio(boolean hasAudio) {
+		this.hasAudio = hasAudio;
+	}
+
+	public String getStreamId() {
+		return streamId;
+	}
+
+	public void setStreamId(String streamId) {
+		this.streamId = streamId;
+	}
+
+	public String getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(String createTime) {
+		this.createTime = createTime;
+	}
+
+	public String getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(String updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	public int getChannelType() {
+		return channelType;
+	}
+
+	public void setChannelType(int channelType) {
+		this.channelType = channelType;
+	}
+
+	public String getBusinessGroupId() {
+		return businessGroupId;
+	}
+
+	public void setBusinessGroupId(String businessGroupId) {
+		this.businessGroupId = businessGroupId;
+	}
+
+	public String getGpsTime() {
+		return gpsTime;
+	}
+
+	public void setGpsTime(String gpsTime) {
+		this.gpsTime = gpsTime;
+	}
+
+	public String getDeviceName() {
+		return deviceName;
+	}
+
+	public void setDeviceName(String deviceName) {
+		this.deviceName = deviceName;
+	}
+
+	public int getDeviceOnline() {
+		return deviceOnline;
+	}
+
+	public void setDeviceOnline(int deviceOnline) {
+		this.deviceOnline = deviceOnline;
+	}
+}

BIN
src/main/resources/wvpssl.jks


+ 513 - 0
web_src/src/components/GBRecordDetail.vue

@@ -0,0 +1,513 @@
+<template>
+	<div style="width: 100%">
+    <div class="page-header" >
+      <div class="page-title">
+        <el-page-header @back="goBack" content="国标录像"></el-page-header>
+      </div>
+    </div>
+		<el-container>
+      <el-aside width="300px">
+        <div class="record-list-box-box">
+          <el-date-picker size="mini" v-model="chooseDate" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
+          <div class="record-list-box" v-loading="recordsLoading" :style="recordListStyle">
+            <ul v-if="detailFiles.length >0" class="infinite-list record-list" >
+              <li v-for="item in detailFiles" class="infinite-list-item record-list-item" >
+
+                <el-tag v-if="chooseFile != item" @click="checkedFile(item)">
+                  <i class="el-icon-video-camera"  ></i>
+                  {{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
+                </el-tag>
+                <el-tag v-if="chooseFile == item" type="danger" >
+                  <i class="el-icon-video-camera"  ></i>
+                  {{ moment(item.startTime).format('HH:mm:ss')}}-{{ moment(item.endTime).format('HH:mm:ss')}}
+                </el-tag>
+                <i style="color: #409EFF;margin-left: 5px;" class="el-icon-download" @click="downloadRecord(item)" ></i>
+              </li>
+            </ul>
+          </div>
+          <div size="mini" v-if="detailFiles.length ==0" class="record-list-no-val" >暂无数据</div>
+        </div>
+
+      </el-aside>
+			<el-main style="padding-bottom: 10px;">
+        <div class="playBox" :style="playerStyle">
+          <player ref="recordVideoPlayer"
+                  :videoUrl="videoUrl"
+                  :error="videoError"
+                  :message="videoError"
+                  :hasAudio="hasAudio"
+                  style="max-height: 100%"
+                  fluent autoplay live ></player>
+        </div>
+        <div class="player-option-box">
+          <div>
+            <el-button-group >
+              <el-time-picker
+                size="mini"
+                is-range
+                align="left"
+                v-model="timeRange"
+                value-format="yyyy-MM-dd HH:mm:ss"
+                range-separator="至"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+                @change="timePickerChange"
+                placeholder="选择时间范围">
+              </el-time-picker>
+            </el-button-group>
+
+            <el-button-group >
+              <el-button size="mini" class="iconfont icon-zanting" title="开始" @click="gbPause()"></el-button>
+              <el-button size="mini" class="iconfont icon-kaishi" title="暂停" @click="gbPlay()"></el-button>
+              <el-dropdown size="mini" title="播放倍速"  @command="gbScale">
+                <el-button size="mini">
+                  倍速 <i class="el-icon-arrow-down el-icon--right"></i>
+                </el-button>
+                <el-dropdown-menu  slot="dropdown">
+                  <el-dropdown-item command="0.25">0.25倍速</el-dropdown-item>
+                  <el-dropdown-item command="0.5">0.5倍速</el-dropdown-item>
+                  <el-dropdown-item command="1.0">1倍速</el-dropdown-item>
+                  <el-dropdown-item command="2.0">2倍速</el-dropdown-item>
+                  <el-dropdown-item command="4.0">4倍速</el-dropdown-item>
+                </el-dropdown-menu>
+              </el-dropdown>
+              <el-button size="mini" class="iconfont icon-xiazai1" title="下载选定录像" @click="downloadRecord()"></el-button>
+              <el-button v-if="sliderMIn === 0 && sliderMax === 86400" size="mini" class="iconfont icon-slider" title="放大滑块" @click="setSliderFit()"></el-button>
+              <el-button v-if="sliderMIn !== 0 || sliderMax !== 86400" size="mini" class="iconfont icon-slider-right" title="恢复滑块" @click="setSliderFit()"></el-button>
+            </el-button-group>
+          </div>
+          <el-slider
+            class="playtime-slider"
+            v-model="playTime"
+            id="playtimeSlider"
+            :disabled="detailFiles.length === 0"
+            :min="sliderMIn"
+            :max="sliderMax"
+            :range="true"
+            :format-tooltip="playTimeFormat"
+            @change="playTimeChange"
+            :marks="playTimeSliderMarks">
+          </el-slider>
+          <div class="slider-val-box">
+            <div class="slider-val" v-for="item of detailFiles" :style="'width:' + getDataWidth(item) + '%; left:' + getDataLeft(item) + '%'"></div>
+          </div>
+        </div>
+
+			</el-main>
+		</el-container>
+    <recordDownload ref="recordDownload"></recordDownload>
+	</div>
+</template>
+
+
+<script>
+	import uiHeader from '../layout/UiHeader.vue'
+  import player from './common/jessibuca.vue'
+  import moment  from 'moment'
+  import recordDownload from './dialog/recordDownload.vue'
+	export default {
+		name: 'app',
+		components: {
+			uiHeader, player,recordDownload
+		},
+		data() {
+			return {
+        deviceId: this.$route.params.deviceId,
+        channelId: this.$route.params.channelId,
+        recordsLoading: false,
+        streamId: "",
+        hasAudio: false,
+			  detailFiles: [],
+        chooseDate: null,
+        videoUrl: null,
+        chooseFile: null,
+        streamInfo: null,
+        app: null,
+        mediaServerId: null,
+        ssrc: null,
+
+        sliderMIn: 0,
+        sliderMax: 86400,
+        autoPlay: true,
+        taskUpdate: null,
+        tabVal: "running",
+        recordListStyle: {
+			    height: this.winHeight + "px",
+          overflow: "auto",
+          margin: "10px auto 10px auto"
+        },
+        playerStyle: {
+			    "margin": "0 auto 20px auto",
+          "height": this.winHeight + "px",
+        },
+        winHeight: window.innerHeight - 240,
+        playTime: null,
+        timeRange: null,
+        startTime: null,
+        endTime: null,
+        playTimeSliderMarks: {
+			    0: "00:00",
+			    3600: "01:00",
+			    7200: "02:00",
+			    10800: "03:00",
+			    14400: "04:00",
+			    18000: "05:00",
+			    21600: "06:00",
+			    25200: "07:00",
+			    28800: "08:00",
+			    32400: "09:00",
+			    36000: "10:00",
+          39600: "11:00",
+			    43200: "12:00",
+			    46800: "13:00",
+			    50400: "14:00",
+			    54000: "15:00",
+			    57600: "16:00",
+			    61200: "17:00",
+			    64800: "18:00",
+			    68400: "19:00",
+          72000: "20:00",
+			    75600: "21:00",
+			    79200: "22:00",
+			    82800: "23:00",
+          86400: "24:00",
+        },
+			};
+		},
+		computed: {
+
+		},
+		mounted() {
+      this.recordListStyle.height = this.winHeight + "px";
+      this.playerStyle["height"] = this.winHeight + "px";
+      this.chooseDate = moment().format('YYYY-MM-DD')
+      this.dateChange();
+		},
+		destroyed() {
+			this.$destroy('recordVideoPlayer');
+		},
+		methods: {
+      dateChange(){
+        if (!this.chooseDate) {
+          return;
+        }
+
+        this.setTime(this.chooseDate + " 00:00:00", this.chooseDate + " 23:59:59");
+        this.recordsLoading = true;
+        this.detailFiles = [];
+        this.$axios({
+          method: 'get',
+          url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' + this.endTime
+        }).then((res)=>{
+          this.recordsLoading = false;
+          if(res.data.code === 0) {
+            // 处理时间信息
+            this.detailFiles = res.data.data.recordList;
+
+          }else {
+            this.$message({
+              showClose: true,
+              message: res.data.msg,
+              type: "error",
+            });
+          }
+
+        }).catch((e)=> {
+          this.recordsLoading = false;
+          // that.videoHistory.searchHistoryResult = falsificationData.recordData;
+        });
+      },
+      moment: function (v) {
+        return moment(v)
+      },
+      setTime: function (startTime, endTime){
+        this.startTime = startTime;
+        this.endTime = endTime;
+        let start = (new Date(this.startTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
+        let end = (new Date(this.endTime).getTime() - new Date(this.chooseDate + " 00:00:00").getTime())/1000;
+        console.log(start)
+        console.log(end)
+        this.playTime = [start, end];
+        this.timeRange = [startTime, endTime];
+      },
+      videoError: function (e) {
+        console.log("播放器错误:" + JSON.stringify(e));
+      },
+      checkedFile(file){
+        this.chooseFile = file;
+        this.setTime(file.startTime, file.endTime);
+			  // 开始回放
+        this.playRecord()
+      },
+      playRecord: function () {
+
+        if (this.streamId !== "") {
+          this.stopPlayRecord(()=> {
+            this.streamId = "";
+            this.playRecord();
+          })
+        } else {
+          this.$axios({
+            method: 'get',
+            url: '/api/playback/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + this.startTime + '&endTime=' +
+              this.endTime
+          }).then((res)=> {
+            if (res.data.code === 0) {
+              this.streamInfo = res.data.data;
+              this.app = this.streamInfo.app;
+              this.streamId = this.streamInfo.stream;
+              this.mediaServerId = this.streamInfo.mediaServerId;
+              this.ssrc = this.streamInfo.ssrc;
+              this.videoUrl = this.getUrlByStreamInfo();
+            }else {
+              this.$message({
+                showClose: true,
+                message: res.data.msg,
+                type: "error",
+              });
+            }
+          });
+        }
+      },
+      gbPlay(){
+        console.log('前端控制:播放');
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/resume/' + this.streamId
+        }).then((res)=> {
+          this.$refs["recordVideoPlayer"].play(this.videoUrl)
+        });
+      },
+      gbPause(){
+        console.log('前端控制:暂停');
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/pause/' + this.streamId
+        }).then(function (res) {});
+      },
+      gbScale(command){
+        console.log('前端控制:倍速 ' + command);
+        this.$axios({
+          method: 'get',
+          url: `/api/playback/speed/${this.streamId }/${command}`
+        }).then(function (res) {});
+      },
+      downloadRecord: function (row) {
+        if (!row) {
+          let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[0]*1000).format("YYYY-MM-DD HH:mm:ss");
+          let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + this.playTime[1]*1000).format("YYYY-MM-DD HH:mm:ss");
+          console.log(startTimeStr);
+          console.log(endTimeStr);
+          row = {
+            startTime: startTimeStr,
+            endTime: endTimeStr
+          }
+        }
+        if (this.streamId !== "") {
+          this.stopPlayRecord(()=> {
+            this.streamId = "";
+            this.downloadRecord(row);
+          })
+        }else {
+          this.$axios({
+            method: 'get',
+            url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' +
+              row.endTime + '&downloadSpeed=4'
+          }).then( (res)=> {
+            if (res.data.code === 0) {
+              let streamInfo = res.data.data;
+              this.$refs.recordDownload.openDialog(this.deviceId, this.channelId, streamInfo.app, streamInfo.stream, streamInfo.mediaServerId);
+            }else {
+              this.$message({
+                showClose: true,
+                message: res.data.msg,
+                type: "error",
+              });
+            }
+          });
+        }
+      },
+      stopDownloadRecord: function (callback) {
+        this.$refs["recordVideoPlayer"].pause();
+        this.videoUrl = '';
+        this.$axios({
+          method: 'get',
+          url: '/api/gb_record/download/stop/' + this.deviceId + "/" + this.channelId+ "/" + this.streamId
+        }).then((res)=> {
+          if (callback) callback(res)
+        });
+      },
+      stopPlayRecord: function (callback) {
+        this.$refs["recordVideoPlayer"].pause();
+        this.videoUrl = '';
+        this.$axios({
+          method: 'get',
+          url: '/api/playback/stop/' + this.deviceId + "/" + this.channelId + "/" + this.streamId
+        }).then(function (res) {
+          if (callback) callback()
+        });
+      },
+      getDataWidth(item){
+        let timeForFile = this.getTimeForFile(item);
+        let result = (timeForFile[2])/((this.sliderMax - this.sliderMIn)*1000)
+        return result*100
+      },
+      getDataLeft(item){
+        let timeForFile = this.getTimeForFile(item);
+        let differenceTime = timeForFile[0].getTime() - new Date(this.chooseDate + " 00:00:00").getTime()
+        return parseFloat((differenceTime - this.sliderMIn * 1000)/((this.sliderMax - this.sliderMIn)*1000))*100   ;
+      },
+      getUrlByStreamInfo(){
+        if (location.protocol === "https:") {
+          this.videoUrl = this.streamInfo["wss_flv"]
+        }else {
+          this.videoUrl = this.streamInfo["ws_flv"]
+        }
+        return this.videoUrl;
+
+      },
+      timePickerChange: function (val){
+        this.setTime(val[0], val[1])
+      },
+      playTimeChange(val){
+        console.log(val)
+
+        let startTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[0]*1000).format("YYYY-MM-DD HH:mm:ss");
+        let endTimeStr = moment(new Date(this.chooseDate + " 00:00:00").getTime() + val[1]*1000).format("YYYY-MM-DD HH:mm:ss");
+
+        this.setTime(startTimeStr, endTimeStr)
+
+        this.playRecord();
+      },
+      setSliderFit() {
+        if (this.sliderMIn === 0 && this.sliderMax === 86400) {
+          if (this.detailFiles.length > 0){
+            let timeForFile = this.getTimeForFile(this.detailFiles[0]);
+            let lastTimeForFile = this.getTimeForFile(this.detailFiles[this.detailFiles.length - 1]);
+            let timeNum = timeForFile[0].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
+            let lastTimeNum = lastTimeForFile[1].getTime() - new Date(this.chooseDate + " " + "00:00:00").getTime()
+
+            this.playTime = parseInt(timeNum/1000)
+            this.sliderMIn = parseInt(timeNum/1000 - timeNum/1000%(60*60))
+            this.sliderMax = parseInt(lastTimeNum/1000 - lastTimeNum/1000%(60*60)) + 60*60
+
+            this.playTime = [this.sliderMIn, this.sliderMax];
+          }
+        }else {
+          this.sliderMIn = 0;
+          this.sliderMax = 86400;
+        }
+      },
+      getTimeForFile(file){
+        let startTime = new Date(file.startTime);
+        let endTime = new Date(file.endTime);
+        return [startTime, endTime, endTime.getTime() - startTime.getTime()];
+      },
+      playTimeFormat(val){
+        let h = parseInt(val/3600);
+        let m = parseInt((val - h*3600)/60);
+        let s = parseInt(val - h*3600 - m*60);
+
+        let hStr = h;
+        let mStr = m;
+        let sStr = s;
+        if (h < 10) {
+          hStr = "0" + hStr;
+        }
+        if (m < 10) {
+          mStr = "0" + mStr;s
+        }
+        if (s < 10) {
+          sStr = "0" + sStr;
+        }
+        return hStr + ":" + mStr + ":" + sStr
+      },
+      goBack(){
+        window.history.go(-1);
+      }
+		}
+	};
+</script>
+
+<style>
+  .el-slider__runway {
+    background-color:rgba(206, 206, 206, 0.47) !important;
+  }
+  .el-slider__bar {
+    background-color: rgba(153, 153, 153, 0) !important;
+  }
+  .playtime-slider {
+    position: relative;
+    z-index: 100;
+  }
+  .data-picker-true{
+
+  }
+  .data-picker-true:after{
+    content: "";
+    position: absolute;
+    width: 4px;
+    height: 4px;
+    background-color: #606060;
+    border-radius: 4px;
+    left: 45%;
+    top: 74%;
+
+  }
+  .data-picker-false{
+
+  }
+  .slider-val-box{
+    height: 6px;
+    position: relative;
+    top: -22px;
+  }
+  .slider-val{
+    height: 6px;
+    background-color: #007CFF;
+    position: absolute;
+  }
+  .record-list-box-box{
+    width: 250px;
+    float: left;
+  }
+  .record-list-box{
+    overflow: auto;
+    width: 220px;
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    margin-top: 0px;
+    padding: 1rem 0;
+    background-color: #FFF;
+    margin-top: 10px;
+  }
+  .record-list{
+    list-style: none;
+    padding: 0;
+    margin: 0;
+    background-color: #FFF;
+
+  }
+  .record-list-no-val {
+    position: absolute;
+    color: #9f9f9f;
+    top: 50%;
+    left: 110px;
+  }
+  .record-list-item{
+    padding: 0;
+    margin: 0;
+    margin: 0.5rem 0;
+    cursor: pointer;
+  }
+  .record-list-option {
+    width: 10px;
+    float: left;
+    margin-top: 39px;
+
+  }
+  .player-option-box{
+    padding: 0 20px;
+  }
+</style>

+ 327 - 0
web_src/src/components/common/ h265web.vue

@@ -0,0 +1,327 @@
+<template>
+  <div ref="container" @dblclick="fullscreenSwich" style="width:100%;height:100%;background-color: #000000;margin:0 auto;">
+    <div class="buttons-box" id="buttonsBox">
+      <div class="buttons-box-left">
+        <i v-if="!playing" class="iconfont icon-play jessibuca-btn" @click="playBtnClick"></i>
+        <i v-if="playing" class="iconfont icon-pause jessibuca-btn" @click="pause"></i>
+        <i class="iconfont icon-stop jessibuca-btn" @click="destroy"></i>
+        <i v-if="isNotMute" class="iconfont icon-audio-high jessibuca-btn" @click="mute()"></i>
+        <i v-if="!isNotMute" class="iconfont icon-audio-mute jessibuca-btn" @click="cancelMute()"></i>
+      </div>
+      <div class="buttons-box-right">
+        <span class="jessibuca-btn">{{ kBps }} kb/s</span>
+        <!--          <i class="iconfont icon-file-record1 jessibuca-btn"></i>-->
+        <!--          <i class="iconfont icon-xiangqing2 jessibuca-btn" ></i>-->
+        <i class="iconfont icon-camera1196054easyiconnet jessibuca-btn" @click="jessibuca.screenshot('截图','png',0.5)"
+           style="font-size: 1rem !important"></i>
+        <i class="iconfont icon-shuaxin11 jessibuca-btn" @click="playBtnClick"></i>
+        <i v-if="!fullscreen" class="iconfont icon-weibiaoti10 jessibuca-btn" @click="fullscreenSwich"></i>
+        <i v-if="fullscreen" class="iconfont icon-weibiaoti11 jessibuca-btn" @click="fullscreenSwich"></i>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+let jessibucaPlayer = {};
+export default {
+  name: 'jessibuca',
+  data() {
+    return {
+      playing: false,
+      isNotMute: false,
+      quieting: false,
+      fullscreen: false,
+      loaded: false, // mute
+      speed: 0,
+      performance: "", // 工作情况
+      kBps: 0,
+      btnDom: null,
+      videoInfo: null,
+      volume: 1,
+      rotate: 0,
+      vod: true, // 点播
+      forceNoOffscreen: false,
+    };
+  },
+  props: ['videoUrl', 'error', 'hasAudio', 'height'],
+  mounted() {
+    window.onerror = (msg) => {
+      // console.error(msg)
+    };
+    console.log(this._uid)
+    let paramUrl = decodeURIComponent(this.$route.params.url)
+    this.$nextTick(() => {
+      this.updatePlayerDomSize()
+      window.onresize = () => {
+        this.updatePlayerDomSize()
+      }
+      if (typeof (this.videoUrl) == "undefined") {
+        this.videoUrl = paramUrl;
+      }
+      this.btnDom = document.getElementById("buttonsBox");
+      console.log("初始化时的地址为: " + this.videoUrl)
+      this.play(this.videoUrl)
+    })
+  },
+  watch: {
+    videoUrl(newData, oldData) {
+      this.play(newData)
+    },
+    immediate: true
+  },
+  methods: {
+    updatePlayerDomSize() {
+      let dom = this.$refs.container;
+      let width = dom.parentNode.clientWidth
+      let height = (9 / 16) * width
+
+      const clientHeight = Math.min(document.body.clientHeight, document.documentElement.clientHeight)
+      if (height > clientHeight) {
+        height = clientHeight
+        width = (16 / 9) * height
+      }
+
+      dom.style.width = width + 'px';
+      dom.style.height = height + "px";
+    },
+    create() {
+      let options = {};
+      console.log("hasAudio  " + this.hasAudio)
+
+      jessibucaPlayer[this._uid] = new window.Jessibuca(Object.assign(
+        {
+          container: this.$refs.container,
+          videoBuffer: 0.2, // 最大缓冲时长,单位秒
+          isResize: true,
+          decoder: "static/js/jessibuca/decoder.js",
+          useMSE: false,
+          showBandwidth: false,
+          isFlv: true,
+          // text: "WVP-PRO",
+          // background: "static/images/zlm-logo.png",
+          loadingText: "加载中",
+          hasAudio: typeof (this.hasAudio) == "undefined" ? true : this.hasAudio,
+          debug: false,
+          supportDblclickFullscreen: false, // 是否支持屏幕的双击事件,触发全屏,取消全屏事件。
+          operateBtns: {
+            fullscreen: false,
+            screenshot: false,
+            play: false,
+            audio: false,
+            recorder: false,
+          },
+          record: "record",
+          vod: this.vod,
+          forceNoOffscreen: this.forceNoOffscreen,
+          isNotMute: this.isNotMute,
+        },
+        options
+      ));
+      let jessibuca = jessibucaPlayer[this._uid];
+      let _this = this;
+      jessibuca.on("load", function () {
+        console.log("on load init");
+      });
+
+      jessibuca.on("log", function (msg) {
+        console.log("on log", msg);
+      });
+      jessibuca.on("record", function (msg) {
+        console.log("on record:", msg);
+      });
+      jessibuca.on("pause", function () {
+        _this.playing = false;
+      });
+      jessibuca.on("play", function () {
+        _this.playing = true;
+      });
+      jessibuca.on("fullscreen", function (msg) {
+        console.log("on fullscreen", msg);
+        _this.fullscreen = msg
+      });
+
+      jessibuca.on("mute", function (msg) {
+        console.log("on mute", msg);
+        _this.isNotMute = !msg;
+      });
+      jessibuca.on("audioInfo", function (msg) {
+        // console.log("audioInfo", msg);
+      });
+
+      jessibuca.on("videoInfo", function (msg) {
+        // this.videoInfo = msg;
+        console.log("videoInfo", msg);
+
+      });
+
+      jessibuca.on("bps", function (bps) {
+        // console.log('bps', bps);
+
+      });
+      let _ts = 0;
+      jessibuca.on("timeUpdate", function (ts) {
+        // console.log('timeUpdate,old,new,timestamp', _ts, ts, ts - _ts);
+        _ts = ts;
+      });
+
+      jessibuca.on("videoInfo", function (info) {
+        console.log("videoInfo", info);
+      });
+
+      jessibuca.on("error", function (error) {
+        console.log("error", error);
+      });
+
+      jessibuca.on("timeout", function () {
+        console.log("timeout");
+      });
+
+      jessibuca.on('start', function () {
+        console.log('start');
+      })
+
+      jessibuca.on("performance", function (performance) {
+        let show = "卡顿";
+        if (performance === 2) {
+          show = "非常流畅";
+        } else if (performance === 1) {
+          show = "流畅";
+        }
+        _this.performance = show;
+      });
+      jessibuca.on('buffer', function (buffer) {
+        // console.log('buffer', buffer);
+      })
+
+      jessibuca.on('stats', function (stats) {
+        // console.log('stats', stats);
+      })
+
+      jessibuca.on('kBps', function (kBps) {
+        _this.kBps = Math.round(kBps);
+      });
+
+      // 显示时间戳 PTS
+      jessibuca.on('videoFrame', function () {
+
+      })
+
+      //
+      jessibuca.on('metadata', function () {
+
+      });
+    },
+    playBtnClick: function (event) {
+      this.play(this.videoUrl)
+    },
+    play: function (url) {
+      console.log(url)
+      if (jessibucaPlayer[this._uid]) {
+        this.destroy();
+      }
+      this.create();
+      jessibucaPlayer[this._uid].on("play", () => {
+        this.playing = true;
+        this.loaded = true;
+        this.quieting = jessibuca.quieting;
+      });
+      if (jessibucaPlayer[this._uid].hasLoaded()) {
+        jessibucaPlayer[this._uid].play(url);
+      } else {
+        jessibucaPlayer[this._uid].on("load", () => {
+          console.log("load 播放")
+          jessibucaPlayer[this._uid].play(url);
+        });
+      }
+    },
+    pause: function () {
+      if (jessibucaPlayer[this._uid]) {
+        jessibucaPlayer[this._uid].pause();
+      }
+      this.playing = false;
+      this.err = "";
+      this.performance = "";
+    },
+    mute: function () {
+      if (jessibucaPlayer[this._uid]) {
+        jessibucaPlayer[this._uid].mute();
+      }
+    },
+    cancelMute: function () {
+      if (jessibucaPlayer[this._uid]) {
+        jessibucaPlayer[this._uid].cancelMute();
+      }
+    },
+    destroy: function () {
+      if (jessibucaPlayer[this._uid]) {
+        jessibucaPlayer[this._uid].destroy();
+      }
+      if (document.getElementById("buttonsBox") == null) {
+        this.$refs.container.appendChild(this.btnDom)
+      }
+      jessibucaPlayer[this._uid] = null;
+      this.playing = false;
+      this.err = "";
+      this.performance = "";
+
+    },
+    eventcallbacK: function (type, message) {
+      // console.log("player 事件回调")
+      // console.log(type)
+      // console.log(message)
+    },
+    fullscreenSwich: function () {
+      let isFull = this.isFullscreen()
+      jessibucaPlayer[this._uid].setFullscreen(!isFull)
+      this.fullscreen = !isFull;
+    },
+    isFullscreen: function () {
+      return document.fullscreenElement ||
+        document.msFullscreenElement ||
+        document.mozFullScreenElement ||
+        document.webkitFullscreenElement || false;
+    }
+  },
+  destroyed() {
+    if (jessibucaPlayer[this._uid]) {
+      jessibucaPlayer[this._uid].destroy();
+    }
+    this.playing = false;
+    this.loaded = false;
+    this.performance = "";
+  },
+}
+</script>
+
+<style>
+.buttons-box {
+  width: 100%;
+  height: 28px;
+  background-color: rgba(43, 51, 63, 0.7);
+  position: absolute;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  left: 0;
+  bottom: 0;
+  user-select: none;
+  z-index: 10;
+}
+
+.jessibuca-btn {
+  width: 20px;
+  color: rgb(255, 255, 255);
+  line-height: 27px;
+  margin: 0px 10px;
+  padding: 0px 2px;
+  cursor: pointer;
+  text-align: center;
+  font-size: 0.8rem !important;
+}
+
+.buttons-box-right {
+  position: absolute;
+  right: 0;
+}
+</style>

+ 180 - 0
web_src/src/components/console.vue

@@ -0,0 +1,180 @@
+<template>
+  <div id="app" style="width: 100%">
+    <div class="page-header">
+      <div class="page-title">控制台</div>
+      <div class="page-header-btn">
+        <el-button icon="el-icon-info" size="mini" style="margin-right: 1rem;" type="primary" @click="showInfo">平台信息
+        </el-button>
+      </div>
+    </div>
+    <el-row style="width: 100%">
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="ThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+            <consoleCPU ref="consoleCPU"></consoleCPU>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="WorkThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+            <consoleResource ref="consoleResource"></consoleResource>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="WorkThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+            <consoleNet ref="consoleNet"></consoleNet>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="WorkThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+
+            <consoleMem ref="consoleMem"></consoleMem>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="WorkThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+            <consoleNodeLoad ref="consoleNodeLoad"></consoleNodeLoad>
+          </div>
+        </div>
+      </el-col>
+      <el-col :xl="{ span: 8 }" :lg="{ span: 8 }" :md="{ span: 12 }" :sm="{ span: 12 }" :xs="{ span: 24 }" >
+        <div class="control-cell" id="WorkThreadsLoad" >
+          <div style="width:100%; height:100%; ">
+            <consoleDisk ref="consoleDisk"></consoleDisk>
+          </div>
+        </div>
+      </el-col>
+    </el-row>
+    <configInfo ref="configInfo"></configInfo>
+  </div>
+</template>
+
+<script>
+import uiHeader from '../layout/UiHeader.vue'
+import consoleCPU from './console/ConsoleCPU.vue'
+import consoleMem from './console/ConsoleMEM.vue'
+import consoleNet from './console/ConsoleNet.vue'
+import consoleNodeLoad from './console/ConsoleNodeLoad.vue'
+import consoleDisk from './console/ConsoleDisk.vue'
+import consoleResource from './console/ConsoleResource.vue'
+import configInfo from './dialog/configInfo.vue'
+
+import echarts from 'echarts';
+
+export default {
+  name: 'app',
+  components: {
+    echarts,
+    uiHeader,
+    consoleCPU,
+    consoleMem,
+    consoleNet,
+    consoleNodeLoad,
+    consoleDisk,
+    consoleResource,
+    configInfo,
+  },
+  data() {
+    return {
+      timer: null,
+    };
+  },
+  created() {
+    this.getSystemInfo();
+    this.getLoad();
+    this.getResourceInfo();
+    this.loopForSystemInfo();
+
+  },
+  destroyed() {
+  },
+  methods: {
+    loopForSystemInfo: function (){
+      if (this.timer != null) {
+        window.clearTimeout(this.timer);
+      }
+      this.timer = setTimeout(()=>{
+        if (this.$route.path === "/console") {
+          this.getSystemInfo();
+          this.getLoad();
+          this.timer = null;
+          this.loopForSystemInfo()
+          this.getResourceInfo()
+        }
+
+      }, 2000)
+    },
+    getSystemInfo: function (){
+      this.$axios({
+        method: 'get',
+        url: `/api/server/system/info`,
+      }).then( (res)=> {
+        if (res.data.code === 0) {
+          this.$refs.consoleCPU.setData(res.data.data.cpu)
+          this.$refs.consoleMem.setData(res.data.data.mem)
+          this.$refs.consoleNet.setData(res.data.data.net, res.data.data.netTotal)
+          this.$refs.consoleDisk.setData(res.data.data.disk)
+        }
+      }).catch( (error)=> {
+      });
+    },
+    getLoad: function (){
+      this.$axios({
+        method: 'get',
+        url: `/api/server/media_server/load`,
+      }).then( (res)=> {
+        if (res.data.code === 0) {
+          this.$refs.consoleNodeLoad.setData(res.data.data)
+        }
+      }).catch( (error)=> {
+      });
+    },
+    getResourceInfo: function (){
+      this.$axios({
+        method: 'get',
+        url: `/api/server/resource/info`,
+      }).then( (res)=> {
+        if (res.data.code === 0) {
+          this.$refs.consoleResource.setData(res.data.data)
+        }
+      }).catch( (error)=> {
+      });
+    },
+    showInfo: function (){
+
+      this.$axios({
+        method: 'get',
+        url: `/api/server/system/configInfo`,
+      }).then( (res)=> {
+        console.log(res)
+        if (res.data.code === 0) {
+          console.log(2222)
+          console.log(this.$refs.configInfo)
+          this.$refs.configInfo.openDialog(res.data.data)
+        }
+      }).catch( (error)=> {
+      });
+    }
+
+  }
+};
+</script>
+
+<style>
+#app {
+  height: 100%;
+}
+.control-cell {
+  padding-top: 10px;
+  padding-left: 5px;
+  padding-right: 10px;
+  height: 360px;
+}
+</style>

+ 109 - 0
web_src/src/components/console/ConsoleCPU.vue

@@ -0,0 +1,109 @@
+<template>
+  <div id="consoleCPU" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-line ref="consoleCPU" :data="chartData" :extend="extend"  width="100%" height="100%" :legend-visible="false"></ve-line>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'consoleCPU',
+  data() {
+    return {
+      chartData: {
+        columns: ['time', 'data'],
+        rows: []
+      },
+
+      extend: {
+        title: {
+          show: true,
+          text: "CPU",
+          left: "center",
+          top: 20,
+
+        },
+        grid: {
+          show: true,
+          right: "30px",
+          containLabel: true,
+        },
+        xAxis: {
+          time: "time",
+          max: 'dataMax',
+          boundaryGap: ['20%', '20%'],
+          axisLabel: {
+            formatter:(v)=>{
+              return moment(v).format("HH:mm:ss");
+            },
+            showMaxLabel: true,
+          }
+        },
+        yAxis: {
+          type: 'value',
+          min: 0,
+          max: 1,
+          splitNumber: 6,
+          position: "left",
+          silent: true,
+          axisLabel: {
+            formatter: (v)=>{
+              return v*100 + "%";
+            },
+          }
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (data)=>{
+            console.log(data)
+            return moment(data[0].data[0]).format("HH:mm:ss") +  "</br> "
+              + data[0].marker + "使用:" + (data[0].data[1]*100).toFixed(2) + "%";
+          }
+        },
+        series: {
+          itemStyle: {
+            color: "#409EFF"
+          },
+          areaStyle: {
+            color: {
+              type: 'linear',
+              x: 0,
+              y: 0,
+              x2: 0,
+              y2: 1,
+              colorStops: [{
+                offset: 0, color: '#50a3f8' // 0% 处的颜色
+              }, {
+                offset: 1, color: '#69b0fa' // 100% 处的颜色
+              }],
+              global: false // 缺省为 false
+            }
+          }
+        }
+      }
+    };
+  },
+  created() {
+
+
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.consoleCPU.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      this.chartData .rows = data;
+    }
+
+  }
+};
+</script>

+ 81 - 0
web_src/src/components/console/ConsoleDisk.vue

@@ -0,0 +1,81 @@
+<template>
+  <div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-bar ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-bar>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'ConsoleNet',
+  data() {
+    return {
+      chartData: {
+        columns: ['path','free','use'],
+        rows: []
+      },
+      chartSettings: {
+        stack: {
+          'xxx': ['free', 'use']
+        },
+        labelMap: {
+          'free': '剩余',
+          'use': '已使用'
+        },
+      },
+      extend: {
+        title: {
+          show: true,
+          text: "磁盘",
+          left: "center",
+          top: 20,
+        },
+        grid: {
+          show: true,
+          right: "30px",
+          containLabel: true,
+        },
+        series: {
+          barWidth: 30
+        },
+        legend: {
+          left: "center",
+          bottom: "15px",
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (data)=>{
+            console.log(data)
+            let relVal = "";
+            for (let i = 0; i < data.length; i++) {
+              relVal +=  data[i].marker + data[i].seriesName + ":" + data[i].value.toFixed(2) + "GB"
+              if (i < data.length - 1) {
+                relVal += "</br>";
+              }
+            }
+            return relVal;
+          }
+        },
+
+      }
+    };
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.ConsoleNet.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      this.chartData.rows = data;
+    }
+  }
+};
+</script>

+ 103 - 0
web_src/src/components/console/ConsoleMEM.vue

@@ -0,0 +1,103 @@
+<template>
+  <div id="ConsoleMEM" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-line ref="ConsoleMEM" :data="chartData" :extend="extend"  width="100%" height="100%" :legend-visible="false"></ve-line>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'ConsoleMEM',
+  data() {
+    return {
+      chartData: {
+        columns: ['time', 'data'],
+        rows: []
+      },
+
+      extend: {
+        title: {
+          show: true,
+          text: "内存",
+          left: "center",
+          top: 20,
+
+        },
+        grid: {
+          show: true,
+          right: "30px",
+          containLabel: true,
+        },
+        xAxis: {
+          time: "time",
+          max: 'dataMax',
+          boundaryGap: ['20%', '20%'],
+          axisLabel: {
+            formatter:(v)=>{
+              return moment(v).format("HH:mm:ss");
+            },
+            showMaxLabel: true,
+          }
+        },
+        yAxis: {
+          type: 'value',
+          min: 0,
+          max: 1,
+          splitNumber: 6,
+          position: "left",
+          silent: true,
+          axisLabel: {
+            formatter: (v)=>{
+              return v*100 + "%";
+            },
+          }
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (data)=>{
+            console.log(data)
+            return moment(data[0].data[0]).format("HH:mm:ss") +  "</br>"+ data[0].marker +" 使用:" + (data[0].data[1]*100).toFixed(2) + "%";
+          }
+        },
+        series: {
+          itemStyle: {
+            color: "#409EFF"
+          },
+          areaStyle: {
+            color: {
+              type: 'linear',
+              x: 0,
+              y: 0,
+              x2: 0,
+              y2: 1,
+              colorStops: [{
+                offset: 0, color: '#50a3f8' // 0% 处的颜色
+              }, {
+                offset: 1, color: '#69b0fa' // 100% 处的颜色
+              }],
+              global: false // 缺省为 false
+            }
+          }
+        }
+      }
+    };
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.ConsoleMEM.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      this.chartData .rows = data;
+    }
+  }
+};
+</script>

+ 85 - 0
web_src/src/components/console/ConsoleMediaServer.vue

@@ -0,0 +1,85 @@
+<template>
+  <div id="ConsoleMediaServer" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-histogram ref="ConsoleMEM" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-histogram>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'ConsoleMediaServer',
+  data() {
+    return {
+      chartData: {
+        columns: ['time', 'in', 'out'],
+        rows: [
+        ]
+      },
+      chartSettings: {
+        area: true,
+        labelMap: {
+          'in': '下载',
+          'out': '上传'
+        },
+      },
+      extend: {
+        title: {
+          show: true,
+          text: "网络",
+          left: "center",
+          top: 20,
+
+        },
+        grid: {
+          show: true,
+          right: "30px",
+          containLabel: true,
+        },
+        xAxis: {
+          time: "time",
+          max: 'dataMax',
+          boundaryGap: ['20%', '20%'],
+          axisLabel: {
+            formatter:(v)=>{
+              return moment(v).format("HH:mm:ss");
+            },
+            showMaxLabel: true,
+          },
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (data)=>{
+            console.log(parseFloat(data[0].data[1]).toFixed(2))
+            console.log(parseFloat(data[1].data[1]).toFixed(2))
+            console.log("############")
+            return "下载:" + parseFloat(data[0].data[1]).toFixed(2) + "Mbps" +  "</br> 上传:" + parseFloat(data[1].data[1]).toFixed(2) + "Mbps";
+          }
+        },
+        legend: {
+          left: "center",
+          bottom: "15px",
+        }
+      }
+    };
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.ConsoleMEM.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      console.log(data)
+      this.chartData .rows = data;
+    }
+
+  }
+};
+</script>

+ 89 - 0
web_src/src/components/console/ConsoleNet.vue

@@ -0,0 +1,89 @@
+<template>
+  <div id="ConsoleNet" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-line ref="ConsoleNet" :data="chartData" :extend="extend" :settings="chartSettings" width="100%" height="100%" ></ve-line>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'ConsoleNet',
+  data() {
+    return {
+      chartData: {
+        columns: ['time','out','in'],
+        rows: []
+      },
+      chartSettings: {
+        area: true,
+        labelMap: {
+          'in': '下载',
+          'out': '上传'
+        },
+      },
+      extend: {
+        title: {
+          show: true,
+          text: "网络",
+          left: "center",
+          top: 20,
+
+        },
+        grid: {
+          show: true,
+          right: "30px",
+          containLabel: true,
+        },
+        xAxis: {
+          time: "time",
+          max: 'dataMax',
+          boundaryGap: ['20%', '20%'],
+          axisLabel: {
+            formatter:(v)=>{
+              return moment(v).format("HH:mm:ss");
+            },
+            showMaxLabel: true,
+          },
+        },
+        yAxis: {
+          type: 'value',
+          min: 0,
+          max: 1000,
+          splitNumber: 6,
+          position: "left",
+          silent: true,
+        },
+        tooltip: {
+          trigger: 'axis',
+          formatter: (data)=>{
+            return data[1].marker + "下载:" + parseFloat(data[1].data[1]).toFixed(2) + "Mbps" +  "</br> "+ data[0].marker +" 上传:" + parseFloat(data[0].data[1]).toFixed(2) + "Mbps";
+          }
+        },
+        legend: {
+          left: "center",
+          bottom: "15px",
+        }
+      }
+    };
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.ConsoleNet.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data, total) {
+      this.chartData .rows = data;
+      this.extend.yAxis.max= total;
+    }
+
+  }
+};
+</script>

+ 63 - 0
web_src/src/components/console/ConsoleNodeLoad.vue

@@ -0,0 +1,63 @@
+<template>
+  <div id="ConsoleNodeLoad" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <ve-histogram ref="consoleNodeLoad" :data="chartData" :extend="extend"  :settings="chartSettings" width="100%" height="100%" :legend-visible="true"></ve-histogram>
+  </div>
+</template>
+
+<script>
+
+
+import moment from "moment/moment";
+
+export default {
+  name: 'ConsoleNodeLoad',
+  data() {
+    return {
+      chartData: {
+        columns: ['id', 'push', 'proxy', 'gbReceive', 'gbSend'],
+        rows: []
+      },
+      chartSettings: {
+        labelMap: {
+          'push': '直播推流',
+          'proxy': '拉流代理',
+          'gbReceive': '国标收流',
+          'gbSend': '国标推流',
+        },
+      },
+      extend: {
+        title: {
+          show: true,
+          text: "节点负载",
+          left: "center",
+          top: 20,
+
+        },
+        legend: {
+          left: "center",
+          bottom: "15px",
+        },
+        label: {
+          show: true,
+          position: "top"
+        }
+      }
+    };
+  },
+  mounted() {
+    this.$nextTick(_ => {
+      setTimeout(()=>{
+        this.$refs.consoleNodeLoad.echarts.resize()
+      }, 100)
+    })
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      this.chartData .rows = data;
+    }
+
+  }
+};
+</script>

+ 90 - 0
web_src/src/components/console/ConsoleResource.vue

@@ -0,0 +1,90 @@
+<template >
+  <div id="consoleResource" style="width: 100%; height: 100%; background: #FFFFFF; text-align: center">
+    <div style="width: 50%;height: 50%; float:left; ">
+      <el-progress v-if="deviceInfo.total > 0" :width="100" :stroke-width="8" type="circle" :percentage="Math.floor(deviceInfo.online/deviceInfo.total*100)" style="margin-top: 20px; font-size: 18px"></el-progress>
+      <el-progress v-if="deviceInfo.total === 0" :width="100" :stroke-width="8" type="circle" :percentage="0" style="margin-top: 20px; font-size: 18px"></el-progress>
+      <div class="resourceInfo">
+        设备总数:{{deviceInfo.total}}<br/>
+        在线数:{{deviceInfo.online}}
+      </div>
+    </div>
+    <div style="width: 50%;height: 50%; float:left; ">
+      <el-progress v-if="channelInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(channelInfo.online/channelInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="channelInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
+      <div class="resourceInfo">
+        通道总数:{{channelInfo.total}}<br/>
+        在线数:{{channelInfo.online}}
+      </div>
+    </div>
+    <div style="width: 50%;height: 50%; float:left; ">
+      <el-progress v-if="pushInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(pushInfo.online/pushInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="pushInfo.total === 0"  :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
+      <div class="resourceInfo">
+        推流总数:{{pushInfo.total}}<br/>
+        在线数:{{pushInfo.online}}
+      </div>
+    </div>
+    <div style="width: 50%;height: 50%; float:left; ">
+      <el-progress v-if="proxyInfo.total > 0" :width="100" :stroke-width="10" type="circle" :percentage="Math.floor(proxyInfo.online/proxyInfo.total*100)" style="margin-top: 20px"></el-progress>
+      <el-progress v-if="proxyInfo.total === 0" :width="100" :stroke-width="10" type="circle" :percentage="0" style="margin-top: 20px"></el-progress>
+      <div class="resourceInfo">
+        拉流代理总数:{{proxyInfo.total}}<br/>
+        在线数:{{proxyInfo.online}}
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'consoleResource',
+  data() {
+    return {
+      deviceInfo: {
+        total: 0,
+        online: 0
+      },
+      channelInfo: {
+        total: 0,
+        online: 0
+      },
+      pushInfo: {
+        total: 0,
+        online: 0
+      },
+      proxyInfo: {
+        total: 0,
+        online: 0
+      },
+    };
+  },
+  created() {
+
+
+  },
+  mounted() {
+  },
+  destroyed() {
+  },
+  methods: {
+    setData: function(data) {
+      this.deviceInfo = data.device;
+      this.channelInfo = data.channel;
+      this.pushInfo = data.push;
+      this.proxyInfo = data.proxy;
+    }
+  }
+};
+</script>
+
+<style>
+.resourceInfo{
+  width: 100%;
+  text-align: center;
+  font-size: 12px
+}
+.el-progress__text {
+  font-size: 18px !important;
+}
+</style>

+ 59 - 0
web_src/src/components/dialog/configInfo.vue

@@ -0,0 +1,59 @@
+<template>
+  <div id="configInfo">
+    <el-dialog
+      title="系统信息"
+      width="=80%"
+      top="2rem"
+      :close-on-click-modal="false"
+      :visible.sync="showDialog"
+      :destroy-on-close="true"
+      @close="close()"
+    >
+      <div id="shared" style="margin-top: 1rem;margin-right: 100px;">
+        <el-descriptions title="国标服务信息" v-if="configInfoData.sip" :span="2">
+          <el-descriptions-item label="编号" >{{configInfoData.sip.id}}</el-descriptions-item>
+          <el-descriptions-item label="域">{{configInfoData.sip.domain}}</el-descriptions-item>
+          <el-descriptions-item label="IP">{{configInfoData.sip.ip}}</el-descriptions-item>
+          <el-descriptions-item label="端口">{{configInfoData.sip.port}}</el-descriptions-item>
+          <el-descriptions-item label="密码">
+            <el-tag size="small">{{configInfoData.sip.password}}</el-tag>
+          </el-descriptions-item>
+        </el-descriptions>
+        <el-descriptions title="版本信息"v-if="configInfoData.version">
+          <el-descriptions-item label="版本">{{configInfoData.version.version}}</el-descriptions-item>
+          <el-descriptions-item label="编译时间">{{configInfoData.version.BUILD_DATE}}</el-descriptions-item>
+          <el-descriptions-item label="GIT版本">{{configInfoData.version.GIT_Revision_SHORT}}</el-descriptions-item>
+          <el-descriptions-item label="GIT最后提交时间">{{configInfoData.version.GIT_DATE}}</el-descriptions-item>
+        </el-descriptions>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "configInfo",
+  props: {},
+  computed: {},
+  created() {},
+  data() {
+    return {
+      showDialog: false,
+      configInfoData: {
+        sip:{},
+
+      }
+    };
+  },
+  methods: {
+    openDialog: function (data) {
+      console.log(data)
+      this.showDialog = true;
+      this.configInfoData = data;
+    },
+    close: function () {
+      this.showDialog = false;
+    },
+  },
+};
+</script>

+ 42 - 0
web_src/src/components/service/UserService.js

@@ -0,0 +1,42 @@
+
+export default {
+
+  /**
+   * 存储用户信息
+   * @param username
+   * @param token
+   */
+  setUser(user){
+    localStorage.setItem("wvp-user", JSON.stringify(user));
+  },
+
+  /**
+   * 获取用户
+   */
+  getUser(){
+    return JSON.parse(localStorage.getItem("wvp-user"));
+  },
+
+
+  /**
+   * 获取登录token
+   */
+  getToken(){
+    return localStorage.getItem("wvp-token");
+  },
+
+  /**
+   * 清理用户信息
+   */
+  clearUserInfo(){
+    localStorage.removeItem("wvp-user");
+    localStorage.removeItem("wvp-token");
+  },
+  /**
+   * 更新token
+   * @param header
+   */
+  setToken(token) {
+    localStorage.setItem("wvp-token", token);
+  }
+}

BIN
web_src/web_src.7z