From 0c964e9e7094ea21efd0a8477722b75a0efbf0f5 Mon Sep 17 00:00:00 2001 From: 648540858 <648540858@qq.com> Date: Wed, 5 Jan 2022 15:23:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E7=BA=A7=E8=81=94=E5=B9=B3=E5=8F=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=99=9A=E6=8B=9F=E7=9B=AE=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- sql/dump-wvp-202201051515.sql | 539 ++++++++++++++++++ sql/mysql.sql | 12 + .../vmp/gb28181/bean/DeviceNotFoundEvent.java | 21 + .../iot/vmp/gb28181/bean/ParentPlatform.java | 13 + .../iot/vmp/gb28181/bean/PlatformCatalog.java | 71 +++ .../vmp/gb28181/bean/PlatformGbStream.java | 8 + .../iot/vmp/gb28181/event/SipSubscribe.java | 8 + .../transmit/SIPProcessorObserver.java | 3 +- .../request/impl/InviteRequestProcessor.java | 6 +- .../impl/message/MessageRequestProcessor.java | 14 +- .../cmd/CatalogNotifyMessageHandler.java | 43 +- .../query/cmd/CatalogQueryMessageHandler.java | 41 +- .../vmp/media/zlm/ZLMHttpHookListener.java | 7 +- .../iot/vmp/service/IGbStreamService.java | 2 +- .../vmp/service/impl/GbStreamServiceImpl.java | 4 +- .../service/impl/StreamProxyServiceImpl.java | 3 +- .../service/impl/StreamPushServiceImpl.java | 1 + .../iot/vmp/storager/IRedisCatchStorage.java | 2 + .../vmp/storager/IVideoManagerStorager.java | 27 +- .../vmp/storager/dao/DeviceChannelMapper.java | 3 +- .../iot/vmp/storager/dao/GbStreamMapper.java | 12 +- .../storager/dao/ParentPlatformMapper.java | 14 +- .../storager/dao/PlatformCatalogMapper.java | 42 ++ .../storager/dao/PlatformChannelMapper.java | 21 +- .../storager/dao/PlatformGbStreamMapper.java | 24 +- .../storager/impl/RedisCatchStorageImpl.java | 6 + .../impl/VideoManagerStoragerImpl.java | 95 ++- .../vmanager/gb28181/device/DeviceQuery.java | 15 +- .../gb28181/gbStream/GbStreamController.java | 2 +- .../gb28181/gbStream/bean/GbStreamParam.java | 10 + .../gb28181/platform/PlatformController.java | 201 ++++++- .../gb28181/platform/bean/ChannelReduce.java | 13 + .../platform/bean/UpdateChannelParam.java | 9 + src/main/resources/all-application.yml | 2 +- src/main/resources/application-dev.yml | 2 +- src/main/resources/application-docker.yml | 2 +- src/main/resources/wvp.sqlite | Bin 143360 -> 155648 bytes web_src/package-lock.json | 11 + web_src/package.json | 1 + web_src/src/components/ParentPlatformList.vue | 2 +- web_src/src/components/dialog/catalogEdit.vue | 101 ++++ .../src/components/dialog/chooseChannel.vue | 83 ++- .../dialog/chooseChannelForCatalog.vue | 311 ++++++++++ .../components/dialog/chooseChannelForGb.vue | 55 +- .../dialog/chooseChannelForStream.vue | 11 +- .../src/components/dialog/platformEdit.vue | 1 + web_src/src/main.js | 2 + web_src/static/css/iconfont.css | 26 +- web_src/static/css/iconfont.woff2 | Bin 51244 -> 51772 bytes 50 files changed, 1802 insertions(+), 104 deletions(-) create mode 100644 sql/dump-wvp-202201051515.sql create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java create mode 100644 src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java create mode 100644 src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java create mode 100644 web_src/src/components/dialog/catalogEdit.vue create mode 100644 web_src/src/components/dialog/chooseChannelForCatalog.vue diff --git a/README.md b/README.md index e7645c60..d3998740 100644 --- a/README.md +++ b/README.md @@ -95,15 +95,13 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git - [X] 平台状态查询 - [X] 平台信息查询 - [X] 平台远程启动 + - [X] 每个级联平台可自定义的虚拟目录 - [X] 添加RTSP视频 - [X] 添加接口鉴权 -- [ ] 添加ONVIF探测局域网内的设备 - [X] 添加RTMP视频 - [X] 云端录像(需要部署单独服务配合使用) - [X] 多流媒体节点,自动选择负载最低的节点使用。 - [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。 -- [ ] 添加系统配置 -- [ ] 添加用户管理 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 # docker快速体验 diff --git a/sql/dump-wvp-202201051515.sql b/sql/dump-wvp-202201051515.sql new file mode 100644 index 00000000..1b3b84f0 --- /dev/null +++ b/sql/dump-wvp-202201051515.sql @@ -0,0 +1,539 @@ +-- MySQL dump 10.13 Distrib 8.0.27, for Linux (x86_64) +-- +-- Host: localhost Database: wvp +-- ------------------------------------------------------ +-- Server version 8.0.27-0ubuntu0.20.04.1 + +/*!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` ( + `deviceId` varchar(50) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `manufacturer` varchar(255) DEFAULT NULL, + `model` varchar(255) DEFAULT NULL, + `firmware` varchar(255) DEFAULT NULL, + `transport` varchar(50) DEFAULT NULL, + `streamMode` varchar(50) DEFAULT NULL, + `online` varchar(50) DEFAULT NULL, + `registerTime` varchar(50) DEFAULT NULL, + `keepaliveTime` varchar(50) DEFAULT NULL, + `ip` varchar(50) NOT NULL, + `createTime` varchar(50) NOT NULL, + `updateTime` varchar(50) NOT NULL, + `port` int NOT NULL, + `expires` int NOT NULL, + `subscribeCycleForCatalog` int NOT NULL, + `hostAddress` varchar(50) NOT NULL, + `charset` varchar(50) NOT NULL, + PRIMARY KEY (`deviceId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `device` +-- + +LOCK TABLES `device` WRITE; +/*!40000 ALTER TABLE `device` DISABLE KEYS */; +INSERT INTO `device` VALUES ('34020000001320000005','IPC-HFW4433M-I2','Dahua','IPC-HFW4433M-I2','2.622.0000000.31.R,2017-12-14','UDP','UDP','1','2022-01-05 15:08:26','2022-01-05 15:15:26','192.168.1.100','2022-01-05 15:08:26','2022-01-05 15:15:26',5060,3600,0,'192.168.1.100:5060','gb2312'),('34020000002000000005','DH-NVR5864-I','Dahua','DH-NVR5864-I','4.001.0000000.3,2020-10-22','UDP','UDP','1','2022-01-05 14:07:36','2022-01-05 15:15:25','192.168.1.19','2022-01-05 15:08:25','2022-01-05 15:15:25',5060,3600,0,'192.168.1.19:5060','gb2312'),('44010000001110008008',NULL,'Mercury','MIPC368(P)W-4','1.0.1 Build 210304 Rel.60784n','UDP','UDP','1','2022-01-05 15:08:35','2022-01-05 15:14:35','192.168.1.17','2022-01-05 15:08:35','2022-01-05 15:14:35',5060,36000,0,'192.168.1.17:5060','gb2312'); +/*!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) NOT NULL, + `channelId` varchar(50) NOT NULL, + `alarmPriority` varchar(50) NOT NULL, + `alarmMethod` varchar(50) DEFAULT NULL, + `alarmTime` varchar(50) NOT NULL, + `alarmDescription` varchar(255) DEFAULT NULL, + `longitude` double DEFAULT NULL, + `latitude` double DEFAULT NULL, + `alarmType` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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` ( + `channelId` varchar(50) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `manufacture` varchar(50) DEFAULT NULL, + `model` varchar(50) DEFAULT NULL, + `owner` varchar(50) DEFAULT NULL, + `civilCode` varchar(50) DEFAULT NULL, + `block` varchar(50) DEFAULT NULL, + `address` varchar(50) DEFAULT NULL, + `parentId` varchar(50) DEFAULT NULL, + `safetyWay` int DEFAULT NULL, + `registerWay` int DEFAULT NULL, + `certNum` varchar(50) DEFAULT NULL, + `certifiable` int DEFAULT NULL, + `errCode` int DEFAULT NULL, + `endTime` varchar(50) DEFAULT NULL, + `secrecy` varchar(50) DEFAULT NULL, + `ipAddress` varchar(50) DEFAULT NULL, + `port` int DEFAULT NULL, + `password` varchar(255) DEFAULT NULL, + `PTZType` int DEFAULT NULL, + `status` int DEFAULT NULL, + `longitude` double DEFAULT NULL, + `latitude` double DEFAULT NULL, + `streamId` varchar(50) DEFAULT NULL, + `deviceId` varchar(50) NOT NULL, + `parental` varchar(50) DEFAULT NULL, + `hasAudio` bit(1) DEFAULT NULL, + `createTime` varchar(50) NOT NULL, + `updateTime` varchar(50) NOT NULL, + PRIMARY KEY (`channelId`,`deviceId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_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 */; +INSERT INTO `device_channel` VALUES ('34020000001310000001','IPC','Dahua','IPC-HFW4433M-I2','0','340200','','axy','34020000001320000005',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','34020000001320000005','0',NULL,'2022-01-05 15:11:21','2022-01-05 15:11:21'),('34020000001310000001','通道1','Dahua','DH-NVR5864-I','0','340200','','axy','34020000002000000005',0,1,'',0,0,NULL,'0','192.168.1.17',37777,'',0,1,0,0,'','34020000002000000005','0',NULL,'2022-01-05 15:11:25','2022-01-05 15:11:25'),('34020000001310000065','GB_Chn_065','Dahua','DH-NVR5864-I','0','340200','','axy','34020000002000000005',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','34020000002000000005','0',NULL,'2022-01-05 15:11:25','2022-01-05 15:11:25'),('34020000001320000001','IPCamera 01','Mercury','MIPC368(P)W-4','Owner','CivilCode','','Address','',0,1,'',0,0,NULL,'0','',0,'',0,1,0,0,'','44010000001110008008','0',NULL,'2022-01-05 15:11:26','2022-01-05 15:11:26'); +/*!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` ( + `deviceId` varchar(50) NOT NULL, + `channelId` varchar(50) NOT NULL, + `deviceName` varchar(255) DEFAULT NULL, + `time` varchar(50) 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) DEFAULT NULL, + `geodeticSystem` varchar(50) DEFAULT NULL, + `cnLng` varchar(50) DEFAULT NULL, + `cnLat` varchar(50) DEFAULT NULL, + PRIMARY KEY (`deviceId`,`time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_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` ( + `app` varchar(255) NOT NULL, + `stream` varchar(255) NOT NULL, + `gbId` varchar(50) NOT NULL, + `name` varchar(255) DEFAULT NULL, + `longitude` double DEFAULT NULL, + `latitude` double DEFAULT NULL, + `streamType` varchar(50) DEFAULT NULL, + `mediaServerId` varchar(50) DEFAULT NULL, + `status` int DEFAULT NULL, + PRIMARY KEY (`app`,`stream`,`gbId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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 */; +INSERT INTO `gb_stream` VALUES ('1000','10000001_52869999','77777777777777777777','shoulei1111',0,0,'push','XR1LEpKlfQtSg9Z1',1); +/*!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) NOT NULL, + `type` varchar(50) NOT NULL, + `uri` varchar(200) NOT NULL, + `address` varchar(50) NOT NULL, + `result` varchar(50) NOT NULL, + `timing` bigint NOT NULL, + `username` varchar(50) NOT NULL, + `createTime` varchar(50) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `log` +-- + +LOCK TABLES `log` WRITE; +/*!40000 ALTER TABLE `log` DISABLE KEYS */; +INSERT INTO `log` VALUES (1,'登录','GET','/api/user/login','127.0.0.1','200 OK',245,'admin','2022-01-05 15:09:06'),(2,'添加上级平台','POST','/api/platform/save','127.0.0.1','200 OK',88,'admin','2022-01-05 15:09:24'),(3,'[设备查询] 同步设备通道','POST','/api/device/query/devices/34020000001320000005/sync','127.0.0.1','200 OK',17,'admin','2022-01-05 15:11:21'),(4,'[设备查询] 同步设备通道','POST','/api/device/query/devices/34020000002000000005/sync','127.0.0.1','200 OK',4,'admin','2022-01-05 15:11:25'),(5,'[设备查询] 同步设备通道','POST','/api/device/query/devices/44010000001110008008/sync','127.0.0.1','200 OK',4,'admin','2022-01-05 15:11:26'),(6,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',52,'admin','2022-01-05 15:11:32'),(7,'从上级平台移除国标通道','DELETE','/api/platform/del_channel_for_gb','127.0.0.1','200 OK',35,'admin','2022-01-05 15:11:34'),(8,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',39,'admin','2022-01-05 15:11:35'),(9,'从上级平台移除国标通道','DELETE','/api/platform/del_channel_for_gb','127.0.0.1','200 OK',46,'admin','2022-01-05 15:14:00'),(10,'向上级平台添加国标通道','POST','/api/platform/update_channel_for_gb','127.0.0.1','200 OK',59,'admin','2022-01-05 15:14:01'),(11,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',12,'admin','2022-01-05 15:14:16'),(12,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',8,'admin','2022-01-05 15:14:17'),(13,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',6,'admin','2022-01-05 15:14:19'),(14,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',8,'admin','2022-01-05 15:14:19'),(15,'移除通道与国标的关联','DELETE','/api/gbStream/del','127.0.0.1','200 OK',11,'admin','2022-01-05 15:14:21'),(16,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',42,'admin','2022-01-05 15:14:24'),(17,'移除通道与国标的关联','DELETE','/api/gbStream/del','127.0.0.1','200 OK',43,'admin','2022-01-05 15:14:25'),(18,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',9,'admin','2022-01-05 15:14:27'),(19,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',9,'admin','2022-01-05 15:14:37'),(20,'添加通道与国标的关联','POST','/api/gbStream/add','127.0.0.1','200 OK',10,'admin','2022-01-05 15:14:38'); +/*!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) NOT NULL, + `ip` varchar(50) NOT NULL, + `hookIp` varchar(50) NOT NULL, + `sdpIp` varchar(50) NOT NULL, + `streamIp` varchar(50) 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) NOT NULL, + `streamNoneReaderDelayMS` int NOT NULL, + `rtpEnable` int NOT NULL, + `rtpPortRange` varchar(50) NOT NULL, + `sendRtpPortRange` varchar(50) NOT NULL, + `recordAssistPort` int NOT NULL, + `defaultServer` int NOT NULL, + `createTime` varchar(50) NOT NULL, + `updateTime` varchar(50) NOT NULL, + `hookAliveInterval` int NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `media_server_i` (`ip`,`httpPort`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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 */; +INSERT INTO `media_server` VALUES ('XR1LEpKlfQtSg9Z1','192.168.1.3','127.0.0.1','192.168.1.3','192.168.1.3',6080,0,10935,0,10000,10554,0,1,'035c73f7-bb6b-4889-a715-d9eb2d1925cc',100000,1,'30000,30500','30000,30500',18081,1,'2022-01-05 15:08:27','2022-01-05 15:08:27',10); +/*!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) DEFAULT NULL, + `serverGBId` varchar(50) NOT NULL, + `serverGBDomain` varchar(50) DEFAULT NULL, + `serverIP` varchar(50) DEFAULT NULL, + `serverPort` int DEFAULT NULL, + `deviceGBId` varchar(50) NOT NULL, + `deviceIp` varchar(50) DEFAULT NULL, + `devicePort` varchar(50) DEFAULT NULL, + `username` varchar(255) DEFAULT NULL, + `password` varchar(50) DEFAULT NULL, + `expires` varchar(50) DEFAULT NULL, + `keepTimeout` varchar(50) DEFAULT NULL, + `transport` varchar(50) DEFAULT NULL, + `characterSet` varchar(50) DEFAULT NULL, + `catalogId` varchar(50) NOT NULL, + `ptz` int DEFAULT NULL, + `rtcp` int DEFAULT NULL, + `status` bit(1) DEFAULT NULL, + `shareAllLiveStream` int DEFAULT NULL, + PRIMARY KEY (`id`,`serverGBId`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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 */; +INSERT INTO `parent_platform` VALUES (1,1,'1112','1111111111111','1111111111','11.11.11.11',111111,'34020000002110000015','192.168.1.3','5060','34020000002110000015','12345678','300','60','UDP','GB2312','1111111111111',1,0,_binary '\0',1); +/*!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) NOT NULL, + `platformId` varchar(50) NOT NULL, + `name` varchar(255) NOT NULL, + `parentId` varchar(50) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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 */; +INSERT INTO `platform_catalog` VALUES ('1111111111','1111111111111','11122','1111111111111'); +/*!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` ( + `channelId` varchar(50) NOT NULL, + `deviceId` varchar(50) NOT NULL, + `platformId` varchar(50) NOT NULL, + `deviceAndChannelId` varchar(50) NOT NULL, + `catalogId` varchar(50) NOT NULL, + PRIMARY KEY (`deviceAndChannelId`,`platformId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_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 */; +INSERT INTO `platform_gb_channel` VALUES ('34020000001310000001','34020000001320000005','1111111111111','34020000001320000005_34020000001310000001','1111111111'),('34020000001310000001','34020000002000000005','1111111111111','34020000002000000005_34020000001310000001','1111111111'),('34020000001310000065','34020000002000000005','1111111111111','34020000002000000005_34020000001310000065','1111111111'),('34020000001320000001','44010000001110008008','1111111111111','44010000001110008008_34020000001320000001','1111111111'); +/*!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` ( + `platformId` varchar(50) NOT NULL, + `app` varchar(255) NOT NULL, + `stream` varchar(255) NOT NULL, + `catalogId` varchar(50) NOT NULL, + PRIMARY KEY (`platformId`,`app`,`stream`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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 */; +INSERT INTO `platform_gb_stream` VALUES ('1111111111111','1000','10000001_52869999','1111111111'); +/*!40000 ALTER TABLE `platform_gb_stream` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `role` +-- + +DROP TABLE IF EXISTS `role`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `role` ( + `id` int NOT NULL AUTO_INCREMENT, + `name` text NOT NULL, + `authority` text NOT NULL, + `createTime` varchar(50) NOT NULL, + `updateTime` varchar(50) NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Dumping data for table `role` +-- + +LOCK TABLES `role` WRITE; +/*!40000 ALTER TABLE `role` DISABLE KEYS */; +INSERT INTO `role` VALUES (1,'admin','0','2021-04-13 14:14:57','2021-04-13 14:14:57'); +/*!40000 ALTER TABLE `role` 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` ( + `type` varchar(50) NOT NULL, + `app` varchar(255) NOT NULL, + `stream` varchar(255) NOT NULL, + `url` varchar(255) DEFAULT NULL, + `src_url` varchar(255) DEFAULT NULL, + `dst_url` varchar(255) DEFAULT NULL, + `timeout_ms` int DEFAULT NULL, + `ffmpeg_cmd_key` varchar(255) DEFAULT NULL, + `rtp_type` varchar(50) DEFAULT NULL, + `mediaServerId` varchar(50) DEFAULT NULL, + `enable_hls` bit(1) DEFAULT NULL, + `enable_mp4` bit(1) DEFAULT NULL, + `enable` bit(1) NOT NULL, + `enable_remove_none_reader` bit(1) NOT NULL, + `createTime` varchar(50) NOT NULL, + PRIMARY KEY (`app`,`stream`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_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` ( + `app` varchar(255) NOT NULL, + `stream` varchar(255) NOT NULL, + `totalReaderCount` varchar(50) DEFAULT NULL, + `originType` int DEFAULT NULL, + `originTypeStr` varchar(50) DEFAULT NULL, + `createStamp` int DEFAULT NULL, + `aliveSecond` int DEFAULT NULL, + `mediaServerId` varchar(50) DEFAULT NULL, + PRIMARY KEY (`app`,`stream`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_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 */; +INSERT INTO `stream_push` VALUES ('1000','10000001_52869999','0',2,'rtsp_push',1641366850,0,'XR1LEpKlfQtSg9Z1'); +/*!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) NOT NULL, + `password` varchar(255) NOT NULL, + `roleId` int NOT NULL, + `createTime` varchar(50) NOT NULL, + `updateTime` varchar(50) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `user_username_uindex` (`username`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!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'); +/*!40000 ALTER TABLE `user` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Dumping routines for database 'wvp' +-- +/*!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-01-05 15:15:35 diff --git a/sql/mysql.sql b/sql/mysql.sql index 57243420..8cbd4934 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -171,6 +171,7 @@ create table parent_platform keepTimeout varchar(50) null, transport varchar(50) null, characterSet varchar(50) null, + catalogId varchar(50) not null, ptz int null, rtcp int null, status bit null, @@ -178,12 +179,22 @@ create table parent_platform primary key (id, serverGBId) ); + +create table platform_catalog +( + id varchar(50) primary key, + platformId varchar(50) not null, + name varchar(255) not null, + parentId varchar(50) +); + create table platform_gb_channel ( channelId varchar(50) not null, deviceId varchar(50) not null, platformId varchar(50) not null, deviceAndChannelId varchar(50) not null, + catalogId varchar(50) not null, primary key (deviceAndChannelId, platformId) ); @@ -192,6 +203,7 @@ create table platform_gb_stream platformId varchar(50) not null, app varchar(255) not null, stream varchar(255) not null, + catalogId varchar(50) not null, primary key (platformId, app, stream) ); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java new file mode 100644 index 00000000..4e55011f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceNotFoundEvent.java @@ -0,0 +1,21 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import javax.sip.Dialog; +import java.util.EventObject; + +public class DeviceNotFoundEvent extends EventObject { + /** + * Constructs a prototypical Event. + * + * @param dialog + * @throws IllegalArgumentException if source is null. + */ + public DeviceNotFoundEvent(Dialog dialog) { + super(dialog); + } + + + public Dialog getDialog() { + return (Dialog)super.getSource(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java index fabae8a1..0c061450 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java @@ -109,6 +109,11 @@ public class ParentPlatform { */ private boolean shareAllLiveStream; + /** + * 默认目录Id,自动添加的通道多放在这个目录下 + */ + private String catalogId; + public Integer getId() { return id; } @@ -277,4 +282,12 @@ public class ParentPlatform { public void setShareAllLiveStream(boolean shareAllLiveStream) { this.shareAllLiveStream = shareAllLiveStream; } + + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java new file mode 100644 index 00000000..065971dd --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java @@ -0,0 +1,71 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +public class PlatformCatalog { + private String id; + private String name; + private String platformId; + private String parentId; + private int childrenCount; // 子节点数 + private int type; // 0 目录, 1 国标通道, 2 直播流 + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPlatformId() { + return platformId; + } + + public void setPlatformId(String platformId) { + this.platformId = platformId; + } + + public String getParentId() { + return parentId; + } + + public void setParentId(String parentId) { + this.parentId = parentId; + } + + public int getChildrenCount() { + return childrenCount; + } + + public void setChildrenCount(int childrenCount) { + this.childrenCount = childrenCount; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public void setTypeForCatalog() { + this.type = 0; + } + + public void setTypeForGb() { + this.type = 1; + } + + public void setTypeForStream() { + this.type = 2; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java index a4f7730d..1ab38148 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java @@ -4,6 +4,7 @@ public class PlatformGbStream { private String app; private String stream; private String platformId; + private String catalogId; public String getApp() { return app; @@ -29,4 +30,11 @@ public class PlatformGbStream { this.platformId = platformId; } + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java index f341548e..a00ac630 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.event; +import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.annotation.Scheduled; @@ -91,6 +92,13 @@ public class SipSubscribe { this.statusCode = -1024; this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId(); this.dialog = dialogTerminatedEvent.getDialog(); + }else if (event instanceof DeviceNotFoundEvent) { + DeviceNotFoundEvent deviceNotFoundEvent = (DeviceNotFoundEvent)event; + this.type = "deviceNotFoundEvent"; + this.msg = "设备未找到"; + this.statusCode = -1024; + this.callId = deviceNotFoundEvent.getDialog().getCallId().getCallId(); + this.dialog = deviceNotFoundEvent.getDialog(); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java index 116236f5..be369aed 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java @@ -94,7 +94,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { logger.debug(responseEvent.getResponse().toString()); int status = response.getStatusCode(); if (((status >= 200) && (status < 300)) || status == 401) { // Success! -// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt); CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME); String method = cseqHeader.getMethod(); ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method); @@ -108,6 +107,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); subscribe.response(eventResult); + sipSubscribe.removeOkSubscribe(callIdHeader.getCallId()); } } } @@ -122,6 +122,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { if (subscribe != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent); subscribe.response(eventResult); + sipSubscribe.removeErrorSubscribe(callIdHeader.getCallId()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index aee414f5..203d58b9 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -107,6 +107,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements // 查询平台下是否有该通道 DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId); List gbStreams = storager.queryStreamInParentPlatform(requesterId, channelId); + PlatformCatalog catalog = storager.getCatalog(channelId); GbStream gbStream = gbStreams.size() > 0? gbStreams.get(0):null; MediaServerItem mediaServerItem = null; // 不是通道可能是直播流 @@ -132,7 +133,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements return; } responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中 - }else { + }else if (catalog != null) { + responseAck(evt, Response.BAD_REQUEST, "catalog channel can not play"); // 目录不支持点播 + return; + } else { logger.info("通道不存在,返回404"); responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在 return; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java index 0aab8716..bd053446 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java @@ -1,7 +1,9 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceNotFoundEvent; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; @@ -19,6 +21,7 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; +import javax.sip.header.CallIdHeader; import javax.sip.message.Response; import java.text.ParseException; import java.util.Map; @@ -39,6 +42,9 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement @Autowired private IVideoManagerStorager storage; + @Autowired + private SipSubscribe sipSubscribe; + @Autowired private IRedisCatchStorage redisCatchStorage; @@ -56,6 +62,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement public void process(RequestEvent evt) { logger.debug("接收到消息:" + evt.getRequest()); String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); + CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); // 查询设备是否存在 Device device = redisCatchStorage.getDevice(deviceId); // 查询上级平台是否存在 @@ -63,7 +70,12 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement try { if (device == null && parentPlatform == null) { // 不存在则回复404 - responseAck(evt, Response.NOT_FOUND, "device id not found"); + responseAck(evt, Response.NOT_FOUND, "device "+ deviceId +" not found"); + logger.warn("[设备未找到 ]: {}", deviceId); + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){ + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(new DeviceNotFoundEvent(evt.getDialog())); + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult); + }; }else { Element rootElement = getRootElement(evt); String name = rootElement.getName(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java index c6c1ab9c..0b1a5722 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java @@ -1,10 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.GbStream; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -71,11 +68,41 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple // 查询关联的直播通道 List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); int size = channelReduces.size() + gbStreams.size(); + // 回复目录信息 + List catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId()); + if (catalogs.size() > 0) { + for (PlatformCatalog catalog : catalogs) { + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setChannelId(catalog.getId()); + deviceChannel.setName(catalog.getName()); + deviceChannel.setLongitude(0.0); + deviceChannel.setLatitude(0.0); + deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); + deviceChannel.setManufacture("wvp-pro"); + deviceChannel.setStatus(1); + deviceChannel.setParental(1); + deviceChannel.setParentId(catalog.getParentId()); + deviceChannel.setRegisterWay(1); + deviceChannel.setCivilCode(config.getDomain()); + deviceChannel.setModel("live"); + deviceChannel.setOwner("wvp-pro"); + deviceChannel.setSecrecy("0"); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); + } + } // 回复级联的通道 if (channelReduces.size() > 0) { for (ChannelReduce channelReduce : channelReduces) { DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + // TODO 目前暂时认为这里只用通道没有目录 + deviceChannel.setParental(0); + deviceChannel.setParentId(channelReduce.getCatalogId()); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); } } // 回复直播的通道 @@ -89,16 +116,16 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); deviceChannel.setManufacture("wvp-pro"); deviceChannel.setStatus(gbStream.isStatus()?1:0); - // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setParentId(gbStream.getCatalogId()); deviceChannel.setRegisterWay(1); deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setModel("live"); deviceChannel.setOwner("wvp-pro"); deviceChannel.setParental(0); deviceChannel.setSecrecy("0"); - deviceChannel.setSecrecy("0"); - cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); } } if (size == 0) { @@ -111,6 +138,8 @@ public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent imple e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java index 98ed2dc4..6ca608c3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java @@ -1,10 +1,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; import com.genersoft.iot.vmp.conf.SipConfig; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.GbStream; -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform; @@ -73,12 +70,41 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem List channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId()); // 查询关联的直播通道 List gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId()); - int size = channelReduces.size() + gbStreams.size(); + // 回复目录信息 + List catalogs = storager.queryCatalogInPlatform(parentPlatform.getServerGBId()); + int size = catalogs.size() + channelReduces.size() + gbStreams.size(); + if (catalogs.size() > 0) { + for (PlatformCatalog catalog : catalogs) { + DeviceChannel deviceChannel = new DeviceChannel(); + deviceChannel.setChannelId(catalog.getId()); + deviceChannel.setName(catalog.getName()); + deviceChannel.setLongitude(0.0); + deviceChannel.setLatitude(0.0); + deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); + deviceChannel.setManufacture("wvp-pro"); + deviceChannel.setStatus(1); + deviceChannel.setParental(1); + deviceChannel.setParentId(catalog.getParentId()); + deviceChannel.setRegisterWay(1); + deviceChannel.setCivilCode(config.getDomain()); + deviceChannel.setModel("live"); + deviceChannel.setOwner("wvp-pro"); + deviceChannel.setSecrecy("0"); + cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); + } + } // 回复级联的通道 if (channelReduces.size() > 0) { for (ChannelReduce channelReduce : channelReduces) { DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId()); + // TODO 目前暂时认为这里只用通道没有目录 + deviceChannel.setParental(0); + deviceChannel.setParentId(channelReduce.getCatalogId()); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); + // 防止发送过快 + Thread.sleep(10); } } // 回复直播的通道 @@ -92,14 +118,13 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem deviceChannel.setDeviceId(parentPlatform.getDeviceGBId()); deviceChannel.setManufacture("wvp-pro"); deviceChannel.setStatus(gbStream.isStatus()?1:0); - // deviceChannel.setParentId(parentPlatform.getDeviceGBId()); + deviceChannel.setParentId(gbStream.getCatalogId()); deviceChannel.setRegisterWay(1); deviceChannel.setCivilCode(config.getDomain()); deviceChannel.setModel("live"); deviceChannel.setOwner("wvp-pro"); deviceChannel.setParental(0); deviceChannel.setSecrecy("0"); - deviceChannel.setSecrecy("0"); cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size); } @@ -114,6 +139,8 @@ public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implem e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java index b6af955a..118b2afb 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.UUID; import com.alibaba.fastjson.JSON; -import com.alibaba.fastjson.JSONArray; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.MediaConfig; import com.genersoft.iot.vmp.conf.UserSetup; @@ -302,7 +301,7 @@ public class ZLMHttpHookListener { @ResponseBody @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8") public ResponseEntity onStreamChanged(@RequestBody MediaItem item){ - + if (logger.isDebugEnabled()) { logger.debug("[ ZLM HOOK ]on_stream_changed API调用,参数:" + JSONObject.toJSONString(item)); } @@ -322,10 +321,8 @@ public class ZLMHttpHookListener { String schema = item.getSchema(); List tracks = item.getTracks(); boolean regist = item.isRegist(); - if (tracks != null) { - logger.info("[stream: " + streamId + "] on_stream_changed->>" + schema); - } if ("rtmp".equals(schema)){ + logger.info("on_stream_changed:注册->{}, app->{}, stream->{}", regist, app, streamId); if (regist) { mediaServerService.addCount(mediaServerId); }else { diff --git a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java index 49ba7b7f..9c5c32f1 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java @@ -30,7 +30,7 @@ public interface IGbStreamService { * 保存国标关联 * @param gbStreams */ - boolean addPlatformInfo(List gbStreams, String platformId); + boolean addPlatformInfo(List gbStreams, String platformId, String catalogId); /** * 移除国标关联 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java index 5002d29d..21c666fd 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java @@ -47,13 +47,15 @@ public class GbStreamServiceImpl implements IGbStreamService { @Override - public boolean addPlatformInfo(List gbStreams, String platformId) { + public boolean addPlatformInfo(List gbStreams, String platformId, String catalogId) { // 放在事务内执行 boolean result = false; TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition); try { for (GbStream gbStream : gbStreams) { + gbStream.setCatalogId(catalogId); gbStream.setPlatformId(platformId); + // TODO 修改为批量提交 platformGbStreamMapper.add(gbStream); } dataSourceTransactionManager.commit(transactionStatus); //手动提交 diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java index a972585a..8ec9474b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java @@ -130,7 +130,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { if ( !StringUtils.isEmpty(param.getPlatformGbId()) && streamLive) { List gbStreams = new ArrayList<>(); gbStreams.add(param); - if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId())){ + if (gbStreamService.addPlatformInfo(gbStreams, param.getPlatformGbId(), param.getCatalogId())){ result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]成功"); }else { result.append(", 关联国标平台[ " + param.getPlatformGbId() + " ]失败"); @@ -141,6 +141,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { param.setPlatformId(parentPlatform.getServerGBId()); + param.setCatalogId(parentPlatform.getCatalogId()); String stream = param.getStream(); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(param.getApp(), stream, parentPlatform.getServerGBId()); if (streamProxyItems == null) { diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java index 5fef8cf5..2a707541 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java @@ -119,6 +119,7 @@ public class StreamPushServiceImpl implements IStreamPushService { List parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { + stream.setCatalogId(parentPlatform.getCatalogId()); stream.setPlatformId(parentPlatform.getServerGBId()); String streamId = stream.getStream(); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(stream.getApp(), streamId, parentPlatform.getServerGBId()); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 68a772ef..c890b05a 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -185,6 +185,8 @@ public interface IRedisCatchStorage { */ void updateDevice(Device device); + void removeDevice(String deviceId); + /** * 获取Device */ diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java index 9118d760..96a487c3 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java @@ -243,7 +243,7 @@ public interface IVideoManagerStorager { * @param channelReduces * @return */ - int updateChannelForGB(String platformId, List channelReduces); + int updateChannelForGB(String platformId, List channelReduces, String catalogId); /** * 移除上级平台的通道信息 @@ -256,6 +256,9 @@ public interface IVideoManagerStorager { DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); + List queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); + List queryStreamInParentPlatformAndCatalog(String platformId, String catalogId); + Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); @@ -431,4 +434,26 @@ public interface IVideoManagerStorager { * @param deviceChannelList */ boolean resetChannels(String deviceId, List deviceChannelList); + + /** + * 获取目录信息 + * @param platformId + * @param parentId + * @return + */ + List getChildrenCatalogByPlatform(String platformId, String parentId); + + int addCatalog(PlatformCatalog platformCatalog); + + PlatformCatalog getCatalog(String id); + + int delCatalog(String id); + + int updateCatalog(PlatformCatalog platformCatalog); + + int setDefaultCatalog(String platformId, String catalogId); + + List queryCatalogInPlatform(String serverGBId); + + int delRelation(PlatformCatalog platformCatalog); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java index 8377ccbf..3a4f466e 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java @@ -91,7 +91,8 @@ public interface DeviceChannelMapper { "SELECT * FROM ( "+ " SELECT dc.channelId, dc.deviceId, dc.name, de.manufacturer, de.hostAddress, " + "(SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount, " + - "(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId " + + "(SELECT pc.platformId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as platformId, " + + "(SELECT pc.catalogId FROM platform_gb_channel pc WHERE pc.deviceId=dc.deviceId AND pc.channelId = dc.channelId ) as catalogId " + "FROM device_channel dc " + "LEFT JOIN device de ON dc.deviceId = de.deviceId " + " WHERE 1=1 " + diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java index ffbca9c9..fa6b51c1 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java @@ -35,7 +35,7 @@ public interface GbStreamMapper { @Delete("DELETE FROM gb_stream WHERE app=#{app} AND stream=#{stream}") int del(String app, String stream); - @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream") + @Select("SELECT gs.*, pgs.platformId AS platformId, pgs.catalogId AS catalogId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream") List selectAll(); @Select("SELECT * FROM gb_stream WHERE app=#{app} AND stream=#{stream}") @@ -44,12 +44,12 @@ public interface GbStreamMapper { @Select("SELECT * FROM gb_stream WHERE gbId=#{gbId}") List selectByGBId(String gbId); - @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " + + @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " + "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " + "WHERE gs.gbId = '${gbId}' AND pgs.platformId = '${platformId}'") List queryStreamInPlatform(String platformId, String gbId); - @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs " + + @Select("SELECT gs.*, pgs.platformId as platformId, pgs.catalogId as catalogId FROM gb_stream gs " + "LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream " + "WHERE pgs.platformId = '${platformId}'") List queryGbStreamListInPlatform(String platformId); @@ -59,17 +59,11 @@ public interface GbStreamMapper { "WHERE app=#{app} AND stream=#{stream}") int setStatus(String app, String stream, boolean status); - @Select("SELECT gs.*, pgs.platformId FROM gb_stream gs LEFT JOIN platform_gb_stream pgs ON gs.app = pgs.app AND gs.stream = pgs.stream WHERE mediaServerId=#{mediaServerId} ") - List selectAllByMediaServerId(String mediaServerId); - @Update("UPDATE gb_stream " + "SET status=${status} " + "WHERE mediaServerId=#{mediaServerId} ") void updateStatusByMediaServerId(String mediaServerId, boolean status); - @Select("SELECT * FROM gb_stream WHERE mediaServerId=#{mediaServerId}") - void delByMediaServerId(String mediaServerId); - @Delete("DELETE FROM gb_stream WHERE streamType=#{type} AND gbId=NULL AND mediaServerId=#{mediaServerId}") void deleteWithoutGBId(String type, String mediaServerId); diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java index c92711ae..4f0cbeae 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java @@ -15,10 +15,10 @@ public interface ParentPlatformMapper { @Insert("INSERT INTO parent_platform (enable, name, serverGBId, serverGBDomain, serverIP, serverPort, deviceGBId, deviceIp, " + " devicePort, username, password, expires, keepTimeout, transport, characterSet, ptz, rtcp, " + - " status, shareAllLiveStream) " + + " status, shareAllLiveStream, catalogId) " + " VALUES (${enable}, '${name}', '${serverGBId}', '${serverGBDomain}', '${serverIP}', ${serverPort}, '${deviceGBId}', '${deviceIp}', " + " '${devicePort}', '${username}', '${password}', '${expires}', '${keepTimeout}', '${transport}', '${characterSet}', ${ptz}, ${rtcp}, " + - " ${status}, ${shareAllLiveStream})") + " ${status}, ${shareAllLiveStream}, #{catalogId})") int addParentPlatform(ParentPlatform parentPlatform); @Update("UPDATE parent_platform " + @@ -40,7 +40,8 @@ public interface ParentPlatformMapper { "ptz=#{ptz}, " + "rtcp=#{rtcp}, " + "status=#{status}, " + - "shareAllLiveStream=#{shareAllLiveStream} " + + "shareAllLiveStream=#{shareAllLiveStream}, " + + "catalogId=#{catalogId} " + "WHERE id=#{id}") int updateParentPlatform(ParentPlatform parentPlatform); @@ -74,4 +75,11 @@ public interface ParentPlatformMapper { @Select("SELECT * FROM parent_platform WHERE shareAllLiveStream=true") List selectAllAhareAllLiveStream(); + + @Update(value = {" "}) + int setDefaultCatalog(String platformId, String catalogId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java new file mode 100644 index 00000000..03c66d44 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java @@ -0,0 +1,42 @@ +package com.genersoft.iot.vmp.storager.dao; + +import com.genersoft.iot.vmp.gb28181.bean.GbStream; +import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; +import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream; +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; +import org.apache.ibatis.annotations.*; +import org.springframework.stereotype.Repository; + +import java.util.List; + + +@Mapper +@Repository +public interface PlatformCatalogMapper { + + @Insert("INSERT INTO platform_catalog (id, name, platformId, parentId) VALUES" + + "(#{id}, #{name}, #{platformId}, #{parentId})") + int add(PlatformCatalog platformCatalog); + + @Delete("DELETE FROM platform_catalog WHERE id=#{id}") + int del(String id); + + @Delete("DELETE FROM platform_catalog WHERE platformId=#{platformId}") + int delByPlatformId(String platformId); + + @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id AND platformId=#{platformId}) as childrenCount FROM platform_catalog pc WHERE parentId=#{parentId} AND platformId=#{platformId}") + List selectByParentId(String platformId, String parentId); + + @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.id=#{id}") + PlatformCatalog select(String id); + + @Update(value = {" "}) + int update(PlatformCatalog platformCatalog); + + @Select("SELECT *, (SELECT COUNT(1) from platform_catalog where parentId = pc.id) as childrenCount FROM platform_catalog pc WHERE pc.platformId=#{platformId}") + List selectByPlatForm(String platformId); +} diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java index c8130c34..da38cb00 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.storager.dao; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; +import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; @@ -25,9 +26,9 @@ public interface PlatformChannelMapper { List findChannelRelatedPlatform(String platformId, List deviceAndChannelIds); @Insert("") int addChannels(String platformId, List channelReducesToAdd); @@ -54,6 +55,22 @@ public interface PlatformChannelMapper { "platformId='${platformId}' AND channelId='${channelId}' ) AND channelId='${channelId}'") DeviceChannel queryChannelInParentPlatform(String platformId, String channelId); + + @Select("select dc.channelId as id, dc.name as name, pgc.platformId as platformId, pgc.catalogId as parentId, 0 as childrenCount, 1 as type " + + "from device_channel dc left join platform_gb_channel pgc on dc.deviceId = pgc.deviceId and dc.channelId = pgc.channelId " + + "where pgc.platformId=#{platformId} and pgc.catalogId=#{catalogId}") + List queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); + @Select("SELECT * FROM device WHERE deviceId = (SELECT deviceId FROM platform_gb_channel WHERE platformId='${platformId}' AND channelId='${channelId}')") Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId); + + @Delete("") + int delByCatalogId(String id); + + @Delete("") + int delByCatalogIdAndChannelIdAndPlatformId(PlatformCatalog platformCatalog); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java index a51eda2d..06486c92 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.storager.dao; +import com.genersoft.iot.vmp.gb28181.bean.GbStream; +import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; import com.genersoft.iot.vmp.gb28181.bean.PlatformGbStream; import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem; import org.apache.ibatis.annotations.*; @@ -12,8 +14,8 @@ import java.util.List; @Repository public interface PlatformGbStreamMapper { - @Insert("INSERT INTO platform_gb_stream (app, stream, platformId) VALUES" + - "('${app}', '${stream}', '${platformId}')") + @Insert("INSERT INTO platform_gb_stream (app, stream, platformId, catalogId) VALUES" + + "('${app}', '${stream}', '${platformId}', '${catalogId}')") int add(PlatformGbStream platformGbStream); @Delete("DELETE FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream}") @@ -27,4 +29,22 @@ public interface PlatformGbStreamMapper { @Select("SELECT * FROM platform_gb_stream WHERE app=#{app} AND stream=#{stream} AND platformId=#{serverGBId}") StreamProxyItem selectOne(String app, String stream, String serverGBId); + + @Select("select gs.* \n" + + "from gb_stream gs\n" + + " left join platform_gb_stream pgs\n" + + " on gs.app = pgs.app and gs.stream = pgs.stream\n" + + "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}") + List queryChannelInParentPlatformAndCatalog(String platformId, String catalogId); + + @Select("select gs.gbId as id, gs.name as name, pgs.platformId as platformId, pgs.catalogId as catalogId , 0 as childrenCount, 2 as type\n" + + "from gb_stream gs\n" + + " left join platform_gb_stream pgs\n" + + " on gs.app = pgs.app and gs.stream = pgs.stream\n" + + "where pgs.platformId=#{platformId} and pgs.catalogId=#{catalogId}") + List queryChannelInParentPlatformAndCatalogForCatlog(String platformId, String catalogId); + + @Delete("DELETE FROM platform_gb_stream WHERE catalogId=#{id}") + int delByCatalogId(String id); + } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java index 3ded4168..309db201 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -406,6 +406,12 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { redis.set(key, device); } + @Override + public void removeDevice(String deviceId) { + String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId; + redis.del(key); + } + @Override public Device getDevice(String deviceId) { String key = VideoManagerConstants.DEVICE_PREFIX + userSetup.getServerId() + "_" + deviceId; diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java index 1d8d83a7..7f0efcd3 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java @@ -71,6 +71,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { @Autowired private GbStreamMapper gbStreamMapper; + + @Autowired + private PlatformCatalogMapper catalogMapper; ; @Autowired @@ -449,6 +452,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { @Override public boolean addParentPlatform(ParentPlatform parentPlatform) { + if (parentPlatform.getCatalogId() == null) { + parentPlatform.setCatalogId(parentPlatform.getServerGBId()); + } int result = platformMapper.addParentPlatform(parentPlatform); return result > 0; } @@ -458,6 +464,9 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { int result = 0; ParentPlatformCatch parentPlatformCatch = redisCatchStorage.queryPlatformCatchInfo(parentPlatform.getServerGBId()); // .getDeviceGBId()); if (parentPlatform.getId() == null ) { + if (parentPlatform.getCatalogId() == null) { + parentPlatform.setCatalogId(parentPlatform.getServerGBId()); + } result = platformMapper.addParentPlatform(parentPlatform); if (parentPlatformCatch == null) { parentPlatformCatch = new ParentPlatformCatch(); @@ -480,8 +489,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { // 共享所有视频流,需要将现有视频流添加到此平台 List gbStreams = gbStreamMapper.selectAll(); if (gbStreams.size() > 0) { + for (GbStream gbStream : gbStreams) { + gbStream.setCatalogId(parentPlatform.getCatalogId()); + } if (parentPlatform.isShareAllLiveStream()) { - gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId()); + gbStreamService.addPlatformInfo(gbStreams, parentPlatform.getServerGBId(), parentPlatform.getCatalogId()); }else { gbStreamService.delPlatformInfo(gbStreams); } @@ -536,10 +548,11 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { } @Override - public int updateChannelForGB(String platformId, List channelReduces) { + public int updateChannelForGB(String platformId, List channelReduces, String catalogId) { Map deviceAndChannels = new HashMap<>(); for (ChannelReduce channelReduce : channelReduces) { + channelReduce.setCatalogId(catalogId); deviceAndChannels.put(channelReduce.getDeviceId() + "_" + channelReduce.getChannelId(), channelReduce); } List deviceAndChannelList = new ArrayList<>(deviceAndChannels.keySet()); @@ -576,6 +589,18 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { return channel; } + @Override + public List queryChannelInParentPlatformAndCatalog(String platformId, String catalogId) { + List catalogs = platformChannelMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId); + return catalogs; + } + + @Override + public List queryStreamInParentPlatformAndCatalog(String platformId, String catalogId) { + List catalogs = platformGbStreamMapper.queryChannelInParentPlatformAndCatalogForCatlog(platformId, catalogId); + return catalogs; + } + @Override public Device queryVideoDeviceByPlatformIdAndChannelId(String platformId, String channelId) { Device device = platformChannelMapper.queryVideoDeviceByPlatformIdAndChannelId(platformId, channelId); @@ -739,6 +764,7 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { List parentPlatforms = parentPlatformMapper.selectAllAhareAllLiveStream(); if (parentPlatforms.size() > 0) { for (ParentPlatform parentPlatform : parentPlatforms) { + streamPushItem.setCatalogId(parentPlatform.getCatalogId()); streamPushItem.setPlatformId(parentPlatform.getServerGBId()); String stream = streamPushItem.getStream(); StreamProxyItem streamProxyItems = platformGbStreamMapper.selectOne(streamPushItem.getApp(), stream, parentPlatform.getServerGBId()); @@ -804,4 +830,69 @@ public class VideoManagerStoragerImpl implements IVideoManagerStorager { return streamProxyMapper.selectOne(app, streamId); } + @Override + public List getChildrenCatalogByPlatform(String platformId, String parentId) { + return catalogMapper.selectByParentId(platformId, parentId); + } + + @Override + public int addCatalog(PlatformCatalog platformCatalog) { + return catalogMapper.add(platformCatalog); + } + + @Override + public PlatformCatalog getCatalog(String id) { + return catalogMapper.select(id); + } + + @Override + public int delCatalog(String id) { + PlatformCatalog platformCatalog = catalogMapper.select(id); + if (platformCatalog.getChildrenCount() > 0) { + List platformCatalogList = catalogMapper.selectByParentId(platformCatalog.getPlatformId(), platformCatalog.getId()); + for (PlatformCatalog catalog : platformCatalogList) { + if (catalog.getChildrenCount() == 0) { + catalogMapper.del(catalog.getId()); + platformGbStreamMapper.delByCatalogId(catalog.getId()); + platformChannelMapper.delByCatalogId(catalog.getId()); + }else { + delCatalog(catalog.getId()); + } + } + } + int delresult = catalogMapper.del(id); + int delStreamresult = platformGbStreamMapper.delByCatalogId(id); + int delChanneresult = platformChannelMapper.delByCatalogId(id); + return delresult + delChanneresult + delStreamresult; + } + + @Override + public int updateCatalog(PlatformCatalog platformCatalog) { + return catalogMapper.update(platformCatalog); + } + + @Override + public int setDefaultCatalog(String platformId, String catalogId) { + return platformMapper.setDefaultCatalog(platformId, catalogId); + } + + @Override + public List queryCatalogInPlatform(String platformId) { + return catalogMapper.selectByPlatForm(platformId); + } + + @Override + public int delRelation(PlatformCatalog platformCatalog) { + if (platformCatalog.getType() == 1) { + return platformChannelMapper.delByCatalogIdAndChannelIdAndPlatformId(platformCatalog); + }else if (platformCatalog.getType() == 2) { + List gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformCatalog.getPlatformId(), platformCatalog.getParentId()); + for (GbStream gbStream : gbStreams) { + if (gbStream.getGbId().equals(platformCatalog.getId())) { + return platformGbStreamMapper.delByAppAndStream(gbStream.getApp(), gbStream.getStream()); + } + } + } + return 0; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java index 729eca28..959ac212 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java @@ -152,12 +152,16 @@ public class DeviceQuery { String uuid = UUID.randomUUID().toString(); DeferredResult> result = new DeferredResult>(15*1000L); result.onTimeout(()->{ - logger.warn(String.format("设备通道信息同步超时")); + logger.warn("设备[{}]通道信息同步超时", deviceId); // 释放rtpserver RequestMessage msg = new RequestMessage(); msg.setKey(key); msg.setId(uuid); - msg.setData("Timeout"); + WVPResult wvpResult = new WVPResult<>(); + wvpResult.setCode(-1); + wvpResult.setData(device); + wvpResult.setMsg("更新超时"); + msg.setData(wvpResult); resultHolder.invokeAllResult(msg); }); // 等待其他相同请求返回时一起返回 @@ -168,7 +172,11 @@ public class DeviceQuery { RequestMessage msg = new RequestMessage(); msg.setKey(key); msg.setId(uuid); - msg.setData(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg)); + WVPResult wvpResult = new WVPResult<>(); + wvpResult.setCode(-1); + wvpResult.setData(device); + wvpResult.setMsg(String.format("同步通道失败,错误码: %s, %s", event.statusCode, event.msg)); + msg.setData(wvpResult); resultHolder.invokeAllResult(msg); }); @@ -199,6 +207,7 @@ public class DeviceQuery { boolean isSuccess = storager.delete(deviceId); if (isSuccess) { redisCatchStorage.clearCatchByDeviceId(deviceId); + redisCatchStorage.removeDevice(deviceId); JSONObject json = new JSONObject(); json.put("deviceId", deviceId); return new ResponseEntity<>(json.toString(),HttpStatus.OK); diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java index fcfc8471..69492a79 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java @@ -82,7 +82,7 @@ public class GbStreamController { @PostMapping(value = "/add") @ResponseBody public Object add(@RequestBody GbStreamParam gbStreamParam){ - if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId())) { + if (gbStreamService.addPlatformInfo(gbStreamParam.getGbStreams(), gbStreamParam.getPlatformId(), gbStreamParam.getCatalogId())) { return "success"; }else { return "fail"; diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java index 40456a85..a377c1c2 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java @@ -8,12 +8,22 @@ public class GbStreamParam { private String platformId; + private String catalogId; + private List gbStreams; public String getPlatformId() { return platformId; } + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } + public void setPlatformId(String platformId) { this.platformId = platformId; } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java index 5af08375..0dc172f5 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java @@ -1,10 +1,15 @@ package com.genersoft.iot.vmp.vmanager.gb28181.platform; +import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.genersoft.iot.vmp.gb28181.bean.CatalogData; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; +import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.IVideoManagerStorager; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam; import com.github.pagehelper.PageInfo; @@ -21,6 +26,8 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import com.genersoft.iot.vmp.conf.SipConfig; +import java.util.List; + /** * 级联平台管理 */ @@ -253,7 +260,7 @@ public class PlatformController { if (logger.isDebugEnabled()) { logger.debug("给上级平台添加国标通道API调用"); } - int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces()); + int result = storager.updateChannelForGB(param.getPlatformId(), param.getChannelReduces(), param.getCatalogId()); return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK); } @@ -279,5 +286,197 @@ public class PlatformController { return new ResponseEntity<>(String.valueOf(result > 0), HttpStatus.OK); } + /** + * 获取目录 + * @param platformId 平台ID + * @param parentId 目录父ID + * @return + */ + @ApiOperation("获取目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "platformId", value = "平台ID", dataTypeClass = String.class, required = true), + @ApiImplicitParam(name = "parentId", value = "目录父ID", dataTypeClass = String.class, required = true), + }) + @GetMapping("/catalog") + @ResponseBody + public ResponseEntity>> getCatalogByPlatform(String platformId, String parentId){ + + if (logger.isDebugEnabled()) { + logger.debug("查询目录,platformId: {}, parentId: {}", platformId, parentId); + } + List platformCatalogList = storager.getChildrenCatalogByPlatform(platformId, parentId); + // 查询下属的国标通道 + List catalogsForChannel = storager.queryChannelInParentPlatformAndCatalog(platformId, parentId); + List catalogsForStream = storager.queryStreamInParentPlatformAndCatalog(platformId, parentId); + platformCatalogList.addAll(catalogsForChannel); + platformCatalogList.addAll(catalogsForStream); + WVPResult> result = new WVPResult<>(); + result.setCode(0); + result.setMsg("success"); + result.setData(platformCatalogList); + return new ResponseEntity<>(result, HttpStatus.OK); + } + + /** + * 添加目录 + * @param platformCatalog 目录 + * @return + */ + @ApiOperation("添加目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true), + }) + @PostMapping("/catalog/add") + @ResponseBody + public ResponseEntity>> addCatalog(@RequestBody PlatformCatalog platformCatalog){ + + if (logger.isDebugEnabled()) { + logger.debug("添加目录,{}", JSON.toJSONString(platformCatalog)); + } + PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId()); + WVPResult> result = new WVPResult<>(); + + + if (platformCatalogInStore != null) { + result.setCode(-1); + result.setMsg( platformCatalog.getId() + " already exists"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + int addResult = storager.addCatalog(platformCatalog); + if (addResult > 0) { + result.setCode(0); + result.setMsg("success"); + return new ResponseEntity<>(result, HttpStatus.OK); + }else { + result.setCode(-500); + result.setMsg("save error"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + } + + /** + * 编辑目录 + * @param platformCatalog 目录 + * @return + */ + @ApiOperation("编辑目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "platformCatalog", value = "目录信息", dataTypeClass = PlatformCatalog.class, required = true), + }) + @PostMapping("/catalog/edit") + @ResponseBody + public ResponseEntity>> editCatalog(@RequestBody PlatformCatalog platformCatalog){ + + if (logger.isDebugEnabled()) { + logger.debug("编辑目录,{}", JSON.toJSONString(platformCatalog)); + } + PlatformCatalog platformCatalogInStore = storager.getCatalog(platformCatalog.getId()); + WVPResult> result = new WVPResult<>(); + result.setCode(0); + + if (platformCatalogInStore == null) { + result.setMsg( platformCatalog.getId() + " not exists"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + int addResult = storager.updateCatalog(platformCatalog); + if (addResult > 0) { + result.setMsg("success"); + return new ResponseEntity<>(result, HttpStatus.OK); + }else { + result.setMsg("save error"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + } + + /** + * 删除目录 + * @param id 目录Id + * @return + */ + @ApiOperation("删除目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "id", value = "目录Id", dataTypeClass = String.class, required = true), + }) + @DeleteMapping("/catalog/del") + @ResponseBody + public ResponseEntity>> delCatalog(String id){ + + if (logger.isDebugEnabled()) { + logger.debug("删除目录,{}", id); + } + int delResult = storager.delCatalog(id); + WVPResult> result = new WVPResult<>(); + result.setCode(0); + + if (delResult > 0) { + result.setMsg("success"); + return new ResponseEntity<>(result, HttpStatus.OK); + }else { + result.setMsg("save error"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + } + + /** + * 删除关联 + * @param platformCatalog 关联的信息 + * @return + */ + @ApiOperation("删除关联") + @ApiImplicitParams({ + @ApiImplicitParam(name = "platformCatalog", value = "关联的信息", dataTypeClass = PlatformCatalog.class, required = true), + }) + @DeleteMapping("/catalog/relation/del") + @ResponseBody + public ResponseEntity>> delRelation(@RequestBody PlatformCatalog platformCatalog){ + + if (logger.isDebugEnabled()) { + logger.debug("删除关联,{}", JSON.toJSONString(platformCatalog)); + } + int delResult = storager.delRelation(platformCatalog); + WVPResult> result = new WVPResult<>(); + result.setCode(0); + + if (delResult > 0) { + result.setMsg("success"); + return new ResponseEntity<>(result, HttpStatus.OK); + }else { + result.setMsg("save error"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + } + + + /** + * 修改默认目录 + * @param platformId 平台Id + * @param catalogId 目录Id + * @return + */ + @ApiOperation("修改默认目录") + @ApiImplicitParams({ + @ApiImplicitParam(name = "platformId", value = "平台Id", dataTypeClass = String.class, required = true), + @ApiImplicitParam(name = "catalogId", value = "目录Id", dataTypeClass = String.class, required = true), + }) + @PostMapping("/catalog/default/update") + @ResponseBody + public ResponseEntity> setDefaultCatalog(String platformId, String catalogId){ + + if (logger.isDebugEnabled()) { + logger.debug("修改默认目录,{},{}", platformId, catalogId); + } + int updateResult = storager.setDefaultCatalog(platformId, catalogId); + WVPResult result = new WVPResult<>(); + result.setCode(0); + + if (updateResult > 0) { + result.setMsg("success"); + return new ResponseEntity<>(result, HttpStatus.OK); + }else { + result.setMsg("save error"); + return new ResponseEntity<>(result, HttpStatus.OK); + } + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java index d4ef0bcb..fc13e052 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java @@ -40,6 +40,11 @@ public class ChannelReduce { */ private String platformId; + /** + * 目录Id + */ + private String catalogId; + public String getChannelId() { return channelId; @@ -96,4 +101,12 @@ public class ChannelReduce { public void setPlatformId(String platformId) { this.platformId = platformId; } + + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java index 445b08b7..5b97f184 100644 --- a/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java +++ b/src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java @@ -4,6 +4,7 @@ import java.util.List; public class UpdateChannelParam { private String platformId; + private String catalogId; private List channelReduces; public String getPlatformId() { @@ -21,4 +22,12 @@ public class UpdateChannelParam { public void setChannelReduces(List channelReduces) { this.channelReduces = channelReduces; } + + public String getCatalogId() { + return catalogId; + } + + public void setCatalogId(String catalogId) { + this.catalogId = catalogId; + } } diff --git a/src/main/resources/all-application.yml b/src/main/resources/all-application.yml index a9d7a080..c0b2919b 100644 --- a/src/main/resources/all-application.yml +++ b/src/main/resources/all-application.yml @@ -27,7 +27,7 @@ spring: datasource: # 使用mysql 打开23-28行注释, 删除29-36行 # name: wvp - # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true # username: # password: # type: com.alibaba.druid.pool.DruidDataSource diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index 066702a0..02461612 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -15,7 +15,7 @@ spring: datasource: # 使用mysql 打开23-28行注释, 删除29-36行 # name: wvp - # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true # username: # password: # type: com.alibaba.druid.pool.DruidDataSource diff --git a/src/main/resources/application-docker.yml b/src/main/resources/application-docker.yml index 7eefe888..9e48bc58 100644 --- a/src/main/resources/application-docker.yml +++ b/src/main/resources/application-docker.yml @@ -15,7 +15,7 @@ spring: datasource: # 使用mysql 打开23-28行注释, 删除29-36行 # name: wvp - # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true + # url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&allowMultiQueries=true # username: # password: # type: com.alibaba.druid.pool.DruidDataSource diff --git a/src/main/resources/wvp.sqlite b/src/main/resources/wvp.sqlite index e6140f4e2fc2b4588c18105072cac0e99e82f108..37eefca6296fde6def7f6ff51df23d08db590f00 100644 GIT binary patch delta 2141 zcmZ`)YiQe66xOjM+mh_aPU9+Z(^hfP*PIlRY?P3;S=*S-NtU{;LpLaM6h}?m`Bg_L zSs>&!x{VE1R|Wkj8~YWul|72bycM>!Fxam_$0&3#_8|K)_G3`k5=Nojy?WVkQyE{~ zd(OG%e&>GY94-9jUbw|v4%X9K2!hy+{yh3S2!fm~ws&ns(*1*%X)NN`&`9j!AMk58 zlqDX^0{x{2yi@d}DaqfZ`E~v-zsld_KP>shA|K~}A-eD$f(RQgW8_zfZSK5Okh4l6 zpO%z!xk4r}K9Nu|c^5|pm_jZs>z4IiGF)p|TJK|GpWgyXEK#4L!M*T^rvaJQmHZ3; z@GG~#cO}o2=+S@qkk>OyaP&2T|JbwU`H~B>YwT^OLSJKFVy?KB@vr3fc}a&Oi{9rQ z$x{LacS|-17{N%U_&k%nT*NN-J;+%te4IQ#fv6lkO1jdt^aCLq_Q7fwyvsG?u<} z_MA%yhtW!#3_|NXckEQ;NIW9Oj~pF}h@l#aLhN2vM30zqq$&iN{C*^KLD_BqNyAU=+Ed9H zwd}N4hQQ;}D=iw+E(}2ftuM6VAOz>f<%_ALjEe=?FP=qgES^C_ zZ!auuPKnu@Ywy7n*Tz~QXmfr*d=fz&j}i2I$|*>_K%}zc^32qQbV`vE(sUn^nk+Rx zktP4339Tgv2f4PT=f+$@cQ?FxKx=7&@Im$o88tDMKqZ&W%4sX7%w<(-qdW?Fs@5V- zESzkd-Hnii_Cphh^(M3`Yiz8(;r40|o1i67_mDVyrqd2?aKdW%dRFl*#upLg-^T1Q zuf6S#LuUb2hSvhy_aHIy@= zG^t^$eGn=Ld@SuAmJCwJw+IZAC_#h-eX{I9As=e)qE1L?hTpRD+4=qE`}?vpG|LUG zSnuU!u|EL-#WXT#AOM&EDO2`Q>J5A{Q3UZ0eF6vG;f<+*I5w5WB0U|69c*@qco`tP z2=F#u#7~nmA-V`=DOL#a3YHAU!S(k>J7|6`2|5zn0j?$CnqR}@iHn1j@-(=FIR6d5 zn6$cBe8sk!5baC0!8=@`$L&DAVu!CVTg=YotX5!^Wm)-m>|%6-%$`=uB}GaNMV5cR z$np`zEBhscJcoUqAf_$fuwBOZCX)EP_?4UO42i62LP|(&(!bt_)yMYQ|Oo6^l9n#8R1XT zeVQ_cVU&aLVKpID2L;p$M9>ZJv&^l`m;5zDKT_#0=i#p&_DTV48O2o)#Rp@?9aK2wYGwU|(4Y!$#P#*D8fC$*>(!@GoxCM`4d z;z#%qWfw6dgpASu{3sB>G_crBGpw8W0H&F7q@(i~*xvDP_z^xwSQ3_OaR6*1wm2a{ zR>%Skgwz_F^>6|j*N?*ih#JbZC|_@UX@o@#vxGj +
+ +
+ + + + + + + + +
+ 确认 + 取消 +
+ +
+
+
+
+
+ + + diff --git a/web_src/src/components/dialog/chooseChannel.vue b/web_src/src/components/dialog/chooseChannel.vue index 87fc62e4..85755e84 100644 --- a/web_src/src/components/dialog/chooseChannel.vue +++ b/web_src/src/components/dialog/chooseChannel.vue @@ -1,25 +1,40 @@ @@ -27,12 +42,14 @@ + + diff --git a/web_src/src/components/dialog/chooseChannelForGb.vue b/web_src/src/components/dialog/chooseChannelForGb.vue index f5c66d26..4b2be34b 100644 --- a/web_src/src/components/dialog/chooseChannelForGb.vue +++ b/web_src/src/components/dialog/chooseChannelForGb.vue @@ -21,9 +21,9 @@ - 全部共享 + 全部共享 - + @@ -49,7 +49,6 @@ diff --git a/web_src/src/components/dialog/chooseChannelForStream.vue b/web_src/src/components/dialog/chooseChannelForStream.vue index 8fa5d468..341c22f7 100644 --- a/web_src/src/components/dialog/chooseChannelForStream.vue +++ b/web_src/src/components/dialog/chooseChannelForStream.vue @@ -27,7 +27,6 @@ diff --git a/web_src/src/components/dialog/platformEdit.vue b/web_src/src/components/dialog/platformEdit.vue index fad0444e..62a6957f 100644 --- a/web_src/src/components/dialog/platformEdit.vue +++ b/web_src/src/components/dialog/platformEdit.vue @@ -196,6 +196,7 @@ export default { this.platform.transport = platform.transport; this.platform.characterSet = platform.characterSet; this.platform.shareAllLiveStream = platform.shareAllLiveStream; + this.platform.catalogId = platform.catalogId; this.onSubmit_text = "保存"; } this.showDialog = true; diff --git a/web_src/src/main.js b/web_src/src/main.js index ffd7fde5..d534d5f4 100644 --- a/web_src/src/main.js +++ b/web_src/src/main.js @@ -12,6 +12,7 @@ import VueClipboard from 'vue-clipboard2'; import { Notification } from 'element-ui'; import Fingerprint2 from 'fingerprintjs2'; import VueClipboards from 'vue-clipboards'; +import Contextmenu from "vue-contextmenujs" // 生成唯一ID @@ -37,6 +38,7 @@ Vue.use(VueCookies); Vue.use(VueClipboards); Vue.prototype.$axios = axios; Vue.prototype.$notify = Notification; +Vue.use(Contextmenu); axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : ""; diff --git a/web_src/static/css/iconfont.css b/web_src/static/css/iconfont.css index 4c7b6082..b13982d7 100644 --- a/web_src/static/css/iconfont.css +++ b/web_src/static/css/iconfont.css @@ -1,8 +1,8 @@ @font-face { font-family: "iconfont"; /* Project id 1291092 */ - src: url('iconfont.woff2?t=1637741914969') format('woff2'), - url('iconfont.woff?t=1637741914969') format('woff'), - url('iconfont.ttf?t=1637741914969') format('truetype'); + src: url('iconfont.woff2?t=1640922722742') format('woff2'), + url('iconfont.woff?t=1640922722742') format('woff'), + url('iconfont.ttf?t=1640922722742') format('truetype'); } .iconfont { @@ -13,6 +13,22 @@ -moz-osx-font-smoothing: grayscale; } +.icon-wxbzhuye:before { + content: "\e7d1"; +} + +.icon-mulu:before { + content: "\e7d2"; +} + +.icon-zhibo:before { + content: "\e8c1"; +} + +.icon-shexiangtou:before { + content: "\e7d3"; +} + .icon-suoxiao:before { content: "\e79a"; } @@ -49,7 +65,7 @@ content: "\e7a2"; } -.icon-kuaijin:before { +.icon-houtui:before { content: "\e7a3"; } @@ -57,7 +73,7 @@ content: "\e7a4"; } -.icon-kuaitui:before { +.icon-kuaijin:before { content: "\e7a5"; } diff --git a/web_src/static/css/iconfont.woff2 b/web_src/static/css/iconfont.woff2 index dea67281f7e96cd028de2b84d340fc82fcf74a25..8b2d4006650e9946084a437a62fd60ae9abca8fc 100644 GIT binary patch literal 51772 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 F005%GvBCfV literal 51244 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