This commit is contained in:
Orange
2025-04-24 16:56:49 +08:00
parent 4784f24b79
commit d301e237fc
42 changed files with 447 additions and 3470 deletions

View File

@@ -119,6 +119,10 @@ ruoyi-wvp是基于ruoyi-vue和wvp框架的全部开源的GB/T 28181-2016标准
<img width="200" src="https://gdhxkj.oss-cn-guangzhou.aliyuncs.com/2025/04/17/4601cea6e8cc4df18124bfc1af715dc7.png"/>
</p>
## 付费社群
<img src="https://gdhxkj.oss-cn-guangzhou.aliyuncs.com/2025/04/21/d96d8285328e4ecdbd459018d5ab55c5.jpg"/>
## 特别致谢
- 感谢作者[夏楚](https://github.com/xia-chu) 开源了这么棒流媒体服务框架。

23
pom.xml
View File

@@ -35,12 +35,19 @@
<logback.version>1.2.13</logback.version>
<spring-security.version>5.7.12</spring-security.version>
<spring-framework.version>5.3.39</spring-framework.version>
<hutool.version>5.8.20</hutool.version>
</properties>
<!-- 依赖声明 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<!-- 覆盖SpringFramework的依赖配置-->
<dependency>
<groupId>org.springframework</groupId>
@@ -222,6 +229,13 @@
<version>${ruoyi.version}</version>
</dependency>
<!-- isup模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-isup</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- onvif模块-->
<dependency>
<groupId>com.ruoyi</groupId>
@@ -229,6 +243,13 @@
<version>${ruoyi.version}</version>
</dependency>
<!-- rtsp模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-rtsp</artifactId>
<version>${ruoyi.version}</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
@@ -251,10 +272,12 @@
<module>ruoyi-framework</module>
<module>ruoyi-system</module>
<module>ruoyi-wvp</module>
<module>ruoyi-isup</module>
<module>ruoyi-quartz</module>
<module>ruoyi-generator</module>
<module>ruoyi-common</module>
<module>ruoyi-onvif</module>
<module>ruoyi-rtsp</module>
</modules>
<packaging>pom</packaging>

View File

@@ -37,16 +37,16 @@ public class RuoYiApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
// System.setProperty("spring.devtools.restart.enabled", "false");
SpringApplication.run(RuoYiApplication.class, args);
System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙ \n" +
" .-------. ____ __ \n" +
" | _ _ \\ \\ \\ / / \n" +
" | ( ' ) | \\ _. / ' \n" +
" |(_ o _) / _( )_ .' \n" +
" | (_,_).' __ ___(_ o _)' \n" +
" | |\\ \\ | || |(_,_)' \n" +
" | | \\ `' /| `-' / \n" +
" | | \\ / \\ / \n" +
" ''-' `'-' `-..-' ");
System.out.println("(♥◠‿◠)ノ゙ ruoyi-wvp启动成功 ლ(´ڡ`ლ)゙ \n" +
"\n" +
" _ \n" +
" (_) \n" +
" _ __ _ _ ___ _ _ _ ________ ____ ___ __ \n" +
" | '__| | | |/ _ \\| | | | |______\\ \\ /\\ / /\\ \\ / / '_ \\ \n" +
" | | | |_| | (_) | |_| | | \\ V V / \\ V /| |_) |\n" +
" |_| \\__,_|\\___/ \\__, |_| \\_/\\_/ \\_/ | .__/ \n" +
" __/ | | | \n" +
" |___/ |_| \n");
}
@Override

View File

@@ -2,6 +2,8 @@ package com.ruoyi.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.annotation.Anonymous;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
@@ -24,7 +26,7 @@ import com.ruoyi.system.service.ISysConfigService;
/**
* 参数配置 信息操作处理
*
*
* @author ruoyi
*/
@RestController
@@ -69,6 +71,7 @@ public class SysConfigController extends BaseController
/**
* 根据参数键名查询参数值
*/
@Anonymous
@GetMapping(value = "/configKey/{configKey}")
public AjaxResult getConfigKey(@PathVariable String configKey)
{

View File

@@ -1,12 +1,6 @@
package com.ruoyi.web.controller.system;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysMenu;
@@ -17,16 +11,24 @@ import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Set;
/**
* 登录验证
*
*
* @author ruoyi
*/
@RestController
public class SysLoginController
{
public class SysLoginController {
@Autowired
private SysLoginService loginService;
@@ -39,15 +41,26 @@ public class SysLoginController
@Autowired
private TokenService tokenService;
@Autowired
private RuoYiConfig ruoYiConfig;
@Autowired
private ISysConfigService configService;
/**
* 登录方法
*
*
* @param loginBody 登录信息
* @return 结果
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody)
{
public AjaxResult login(@RequestBody LoginBody loginBody) {
if(Boolean.parseBoolean(configService.selectConfigByKey("sys_public_demonstrate")) && !Constants.SUPER_ADMIN.equals(loginBody.getUsername())) {
if (!ruoYiConfig.getPublicCode().equals(loginBody.getPublicCode())) {
return AjaxResult.error("公众号code错误请关注ruoyi-wvp公众号获取正确的公众号code");
}
}
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
@@ -58,20 +71,18 @@ public class SysLoginController
/**
* 获取用户信息
*
*
* @return 用户信息
*/
@GetMapping("getInfo")
public AjaxResult getInfo()
{
public AjaxResult getInfo() {
LoginUser loginUser = SecurityUtils.getLoginUser();
SysUser user = loginUser.getUser();
// 角色集合
Set<String> roles = permissionService.getRolePermission(user);
// 权限集合
Set<String> permissions = permissionService.getMenuPermission(user);
if (!loginUser.getPermissions().equals(permissions))
{
if (!loginUser.getPermissions().equals(permissions)) {
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
@@ -84,12 +95,11 @@ public class SysLoginController
/**
* 获取路由信息
*
*
* @return 路由信息
*/
@GetMapping("getRouters")
public AjaxResult getRouters()
{
public AjaxResult getRouters() {
Long userId = SecurityUtils.getUserId();
List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
return AjaxResult.success(menuService.buildMenus(menus));

View File

@@ -1,61 +1,191 @@
# 数据源配置
# 项目相关配置
ruoyi:
# 名称
name: RuoYi-Wvp
# 版本
version: 3.8.9
# 版权年份
copyrightYear: 2025
# 文件路径 示例( Windows配置D:/ruoyi/uploadPathLinux配置 /home/ruoyi/uploadPath
profile: D:/ruoyi/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8080
# [可选] HTTPS配置 默认不开启
ssl:
# [可选] 是否开启HTTPS访问
enabled: false
# [可选] 证书文件路径放置在resource/目录下即可修改xxx为文件名
key-store: classpath:test.monitor.89iot.cn.jks
# [可选] 证书密码
key-store-password: gpf64qmw
# [可选] 证书类型, 默认为jks根据实际修改
key-store-type: JKS
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数默认为100
accept-count: 1000
threads:
# tomcat最大线程数默认为200
max: 800
# Tomcat启动初始化的线程数默认值10
min-spare: 100
# 日志配置
logging:
level:
com.ruoyi: debug
org.springframework: warn
# 用户配置
user:
password:
# 密码最大错误次数
maxRetryCount: 5
# 密码锁定时间默认10分钟
lockTime: 10
# Spring配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.cj.jdbc.Driver
druid:
# 主库数据源
master:
url: jdbc:mysql://127.0.0.1:3306/ry-wvp?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowMultiQueries=true
username: root
password: root
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: true
wall:
config:
multi-statement-allow: true
mvc:
pathmatch:
matching-strategy: ant_path_matcher
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
# 文件上传
servlet:
multipart:
# 单个文件大小
max-file-size: 10MB
# 设置总上传的文件大小
max-request-size: 20MB
# 服务模块
devtools:
restart:
# 热部署开关
enabled: true
# redis 配置
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 8
# 密码
password:
# password: 123456
# 连接超时时间
timeout: 10s
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 0
# 连接池中的最大空闲连接
max-idle: 8
# 连接池的最大数据库连接数
max-active: 8
# #连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期默认30分钟
expireTime: 30
# MyBatis配置
mybatis:
# 搜索指定包别名
typeAliasesPackage: com.ruoyi.**.domain
# 配置mapper的扫描找到所有的mapper.xml映射文件
mapperLocations: classpath*:mapper/**/*Mapper.xml
# 加载全局的配置文件
configLocation: classpath:mybatis/mybatis-config.xml
# PageHelper分页插件
pagehelper:
helperDialect: mysql
supportMethodsArguments: true
params: count=countSql
# Swagger配置
swagger:
# 是否开启swagger
enabled: true
# 请求前缀
pathMapping: /dev-api
# 防止XSS攻击
xss:
# 过滤开关
enabled: true
# 排除链接(多个用逗号分隔)
excludes: /system/notice
# 匹配链接
urlPatterns: /system/*,/monitor/*,/tool/*
# 作为28181服务器的配置
sip:
# [可选] 28181服务监听的端口
port: 8116
# 根据国标6.1.2中规定domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码由省级、市级、区级、基层编号组成参照GB/T 2260-2007
# 后两位为行业编码定义参照附录D.3
# 3701020049标识山东济南历下区 信息行业接入
# [可选]
domain: 4101050000
# [可选]
id: 41010500002000000001
# [可选] 默认设备认证密码,后续扩展使用设备单独密码, 移除密码将不进行校验
password: 12345678
# 是否存储alarm信息
alarm: false
##zlm 默认服务器配置
media:
id: zlmediakit-local
# [必须修改] zlm服务器的内网IP
ip: 127.0.0.1
# [必须修改] zlm服务器的http.port
http-port: 8092
# [必选选] zlm服务器的hook.admin_params=secret
secret: TWSYFgYJOQWB4ftgeYut8DW4wbs7pQnj
# 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分 点播超时建议使用多端口测试
rtp:
# [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
enable: true
# [可选] 在此范围内选择端口用于媒体流传输, 必须提前在zlm上配置该属性不然自动配置此属性可能不成功
port-range: 40000,40300 # 端口范围
# [可选] 国标级联在此范围内选择端口发送媒体流,
send-port-range: 40000,40300 # 端口范围
# [根据业务需求配置]
user-settings:
# 点播/录像回放 等待超时时间,单位:毫秒
play-timeout: 180000
# [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true
auto-apply-play: true
# 推流直播是否录制
record-push-live: false
# 国标是否录制
record-sip: false
# 国标点播 按需拉流, true有人观看拉流无人观看释放 false拉起后不自动释放
stream-on-demand: true

View File

@@ -1,24 +1,11 @@
Application Version: ${ruoyi.version}
Spring Boot Version: ${spring-boot.version}
////////////////////////////////////////////////////////////////////
// _ooOoo_ //
// o8888888o //
// 88" . "88 //
// (| ^_^ |) //
// O\ = /O //
// ____/`---'\____ //
// .' \\| |// `. //
// / \\||| : |||// \ //
// / _||||| -:- |||||- \ //
// | | \\\ - /// | | //
// | \_| ''\---/'' | | //
// \ .-\__ `-` ___/-. / //
// ___`. .' /--.--\ `. . ___ //
// ."" '< `.___\_<|>_/___.' >'"". //
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
// \ \ `-. \_ __\ /__ _/ .-` / / //
// ========`-.____`-.___\_____/___.-`____.-'======== //
// `=---=' //
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
// 佛祖保佑 永不宕机 永无BUG //
////////////////////////////////////////////////////////////////////
_
(_)
_ __ _ _ ___ _ _ _ ________ ____ ___ __
| '__| | | |/ _ \| | | | |______\ \ /\ / /\ \ / / '_ \
| | | |_| | (_) | |_| | | \ V V / \ V /| |_) |
|_| \__,_|\___/ \__, |_| \_/\_/ \_/ | .__/
__/ | | |
|___/ |_|

View File

@@ -118,6 +118,11 @@
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -5,7 +5,7 @@ import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
*
* @author ruoyi
*/
@Component
@@ -30,6 +30,8 @@ public class RuoYiConfig
/** 验证码类型 */
private static String captchaType;
private String publicCode;
public String getName()
{
return name;
@@ -84,6 +86,14 @@ public class RuoYiConfig
return captchaType;
}
public String getPublicCode() {
return publicCode;
}
public void setPublicCode(String publicCode) {
this.publicCode = publicCode;
}
public void setCaptchaType(String captchaType) {
RuoYiConfig.captchaType = captchaType;
}

View File

@@ -2,7 +2,7 @@ package com.ruoyi.common.core.domain.model;
/**
* 用户登录对象
*
*
* @author ruoyi
*/
public class LoginBody
@@ -27,6 +27,11 @@ public class LoginBody
*/
private String uuid;
/**
* 公众号code
*/
private String publicCode;
public String getUsername()
{
return username;
@@ -66,4 +71,12 @@ public class LoginBody
{
this.uuid = uuid;
}
public String getPublicCode() {
return publicCode;
}
public void setPublicCode(String publicCode) {
this.publicCode = publicCode;
}
}

View File

@@ -65,12 +65,24 @@
<artifactId>ruoyi-wvp</artifactId>
</dependency>
<!-- isup模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-isup</artifactId>
</dependency>
<!-- onvif模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-onvif</artifactId>
</dependency>
<!-- rtsp模块-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-rtsp</artifactId>
</dependency>
</dependencies>
</project>

24
ruoyi-isup/pom.xml Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.8.9</version>
</parent>
<artifactId>ruoyi-isup</artifactId>
<description>
isup模块
</description>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -17,13 +17,4 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- 通用工具-->
<dependency>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi-common</artifactId>
</dependency>
</dependencies>
</project>

20
ruoyi-rtsp/pom.xml Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.ruoyi</groupId>
<artifactId>ruoyi</artifactId>
<version>3.8.9</version>
</parent>
<artifactId>ruoyi-rtsp</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

View File

@@ -9,7 +9,6 @@ import com.ruoyi.wvp.gb28181.service.ICloudRecordService;
import com.ruoyi.wvp.media.bean.MediaServer;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.bean.CloudRecordItem;
import com.ruoyi.wvp.service.bean.DownloadFileInfo;
import com.ruoyi.wvp.utils.DateUtil;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.cloudRecord.bean.CloudRecordUrl;
@@ -47,15 +46,19 @@ public class CloudRecordController extends BaseController {
@Autowired
private IMediaServerService mediaServerService;
/**
* 查询云端录像
*
* @param app 应用名
* @param stream 流ID
* @param year 年,置空则查询当年
* @param month 月,置空则查询当月
* @param mediaServerId 流媒体ID置空则查询全部
* @return
*/
@ResponseBody
@GetMapping("/date/list")
@Parameter(name = "app", description = "应用名", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@Parameter(name = "year", description = "年,置空则查询当年", required = false)
@Parameter(name = "month", description = "月,置空则查询当月", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID置空则查询全部", required = false)
public List<String> openRtpServer(@RequestParam(required = true) String app, @RequestParam(required = true) String stream, @RequestParam(required = false) Integer year, @RequestParam(required = false) Integer month, @RequestParam(required = false) String mediaServerId
public AjaxResult openRtpServer(@RequestParam(required = true) String app, @RequestParam(required = true) String stream, @RequestParam(required = false) Integer year, @RequestParam(required = false) Integer month, @RequestParam(required = false) String mediaServerId
) {
log.info("[云端录像] 查询存在云端录像的日期 app->{}, stream->{}, mediaServerId->{}, year->{}, month->{}", app, stream, mediaServerId, year, month);
@@ -78,10 +81,10 @@ public class CloudRecordController extends BaseController {
mediaServers = mediaServerService.getAllOnlineList();
}
if (mediaServers.isEmpty()) {
return new ArrayList<>();
return success(new ArrayList<>());
}
return cloudRecordService.getDateList(app, stream, year, month, mediaServers);
return success(cloudRecordService.getDateList(app, stream, year, month, mediaServers));
}
/**

View File

@@ -1,4 +1,4 @@
package com.ruoyi.wvp.gb28181.controller;
package com.ruoyi.wvp.controller;
import com.ruoyi.wvp.common.StreamInfo;
import com.ruoyi.wvp.conf.UserSetting;
@@ -18,12 +18,11 @@ import com.ruoyi.wvp.utils.DateUtil;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -60,12 +59,18 @@ public class GBRecordController {
@Autowired
private UserSetting userSetting;
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@GetMapping("/query/{deviceId}/{channelId}")
public DeferredResult<WVPResult<RecordInfo>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){
/**
* 录像信息查询
*
* @param deviceId 设备国标编号
* @param channelId 通道国标编号
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
@PreAuthorize("@ss.hasPermi('gb:record:query')")
@GetMapping("/query")
public DeferredResult<WVPResult<RecordInfo>> recordinfo( String deviceId, String channelId, String startTime, String endTime, String type){
if (log.isDebugEnabled()) {
log.debug(String.format("录像信息查询 API调用deviceId%s startTime%s endTime%s",deviceId, startTime, endTime));
@@ -87,7 +92,7 @@ public class GBRecordController {
msg.setId(uuid);
msg.setKey(key);
try {
cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> {
cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, type, null, (eventResult -> {
WVPResult<RecordInfo> wvpResult = new WVPResult<>();
wvpResult.setCode(ErrorCode.ERROR100.getCode());
wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg);
@@ -113,13 +118,20 @@ public class GBRecordController {
}
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@Parameter(name = "downloadSpeed", description = "下载倍速", required = true)
@GetMapping("/download/start/{deviceId}/{channelId}")
public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
/**
* 录像下载
*
* @param request
* @param deviceId 设备国标编号
* @param channelId 通道国标编号
* @param startTime 开始时间
* @param endTime 结束时间
* @param downloadSpeed 下载倍速
* @return
*/
@PreAuthorize("@ss.hasPermi('gb:record:download')")
@GetMapping("/download/start")
public DeferredResult<WVPResult<StreamContent>> download(HttpServletRequest request, String deviceId, String channelId,
String startTime, String endTime, String downloadSpeed) {
if (log.isDebugEnabled()) {

View File

@@ -170,12 +170,12 @@ public class WvpServerController extends BaseController {
@Parameter(name = "mediaServerId", description = "流媒体ID", required = true)
@GetMapping(value = "/media_server/media_info")
@ResponseBody
public MediaInfo getMediaInfo(String app, String stream, String mediaServerId) {
public AjaxResult getMediaInfo(String app, String stream, String mediaServerId) {
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体不存在");
}
return mediaServerService.getMediaInfo(mediaServer, app, stream);
return success(mediaServerService.getMediaInfo(mediaServer, app, stream));
}

View File

@@ -1,104 +0,0 @@
package com.ruoyi.wvp.gb28181;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.wvp.conf.SipConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* API兼容系统接口
*/
@Controller
@Slf4j
@RequestMapping(value = "/api/v1")
public class ApiController {
@Autowired
private SipConfig sipConfig;
@GetMapping("/getserverinfo")
private JSONObject getserverinfo(){
JSONObject result = new JSONObject();
result.put("Authorization","ceshi");
result.put("Hardware","");
result.put("InterfaceVersion","2.5.5");
result.put("IsDemo","");
result.put("Hardware","false");
result.put("APIAuth","false");
result.put("RemainDays","永久");
result.put("RunningTime","");
result.put("ServerTime","2020-09-02 1711");
result.put("StartUpTime","2020-09-02 1711");
result.put("Server","");
result.put("SIPSerial", sipConfig.getId());
result.put("SIPRealm", sipConfig.getDomain());
result.put("SIPHost", sipConfig.getShowIp());
result.put("SIPPort", sipConfig.getPort());
result.put("ChannelCount","1000");
result.put("VersionType","");
result.put("LogoMiniText","");
result.put("LogoText","");
result.put("CopyrightText","");
return result;
}
@GetMapping(value = "/userinfo")
private JSONObject userinfo(){
// JSONObject result = new JSONObject();
// result.put("ID","ceshi");
// result.put("Hardware","");
// result.put("InterfaceVersion","2.5.5");
// result.put("IsDemo","");
// result.put("Hardware","false");
// result.put("APIAuth","false");
// result.put("RemainDays","永久");
// result.put("RunningTime","");
// result.put("ServerTime","2020-09-02 1711");
// result.put("StartUpTime","2020-09-02 1711");
// result.put("Server","");
// result.put("SIPSerial", sipConfig.getId());
// result.put("SIPRealm", sipConfig.getDomain());
// result.put("SIPHost", sipConfig.getIp());
// result.put("SIPPort", sipConfig.getPort());
// result.put("ChannelCount","1000");
// result.put("VersionType","");
// result.put("LogoMiniText","");
// result.put("LogoText","");
// result.put("CopyrightText","");
return null;
}
/**
* 系统接口 - 登录
* @param username 用户名
* @param password 密码(经过md5加密,32位长度,不带中划线,不区分大小写)
* @return
*/
@GetMapping(value = "/login")
@ResponseBody
private JSONObject login(String username,String password ){
if (log.isDebugEnabled()) {
log.debug(String.format("模拟接口> 登录 API调用username%s password%s ",
username, password));
}
JSONObject result = new JSONObject();
result.put("CookieToken","ynBDDiKMg");
result.put("URLToken","MOBkORkqnrnoVGcKIAHXppgfkNWRdV7utZSkDrI448Q.oxNjAxNTM4NDk3LCJwIjoiZGJjODg5NzliNzVj" +
"Nzc2YmU5MzBjM2JjNjg1ZWFiNGI5ZjhhN2Y0N2RlZjg3NWUyOTJkY2VkYjkwYmEwMTA0NyIsInQiOjE2MDA5MzM2OTcsInUiOiI" +
"4ODlkZDYyM2ViIn0eyJlIj.GciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhb");
result.put("TokenTimeout",604800);
result.put("AuthToken","MOBkORkqnrnoVGcKIAHXppgfkNWRdV7utZSkDrI448Q.oxNjAxNTM4NDk3LCJwIjoiZGJjODg5NzliNzVj" +
"Nzc2YmU5MzBjM2JjNjg1ZWFiNGI5ZjhhN2Y0N2RlZjg3NWUyOTJkY2VkYjkwYmEwMTA0NyIsInQiOjE2MDA5MzM2OTcsInUiOiI" +
"4ODlkZDYyM2ViIn0eyJlIj.GciOiJIUzI1NiIsInR5cCI6IkpXVCJ9eyJhb");
result.put("Token","ynBDDiKMg");
return result;
}
}

View File

@@ -2,13 +2,15 @@ package com.ruoyi.wvp.gb28181.bean;
import lombok.Data;
import java.io.Serializable;
/**
* 平台信息
*
* @author lin
*/
@Data
public class Platform {
public class Platform implements Serializable {
/**
* 国标-数据库自增ID

View File

@@ -1,323 +0,0 @@
package com.ruoyi.wvp.gb28181.controller;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.wvp.common.StreamInfo;
import com.ruoyi.wvp.conf.UserSetting;
import com.ruoyi.wvp.gb28181.bean.CommonGBChannel;
import com.ruoyi.wvp.gb28181.controller.bean.ChannelToGroupByGbDeviceParam;
import com.ruoyi.wvp.gb28181.controller.bean.ChannelToGroupParam;
import com.ruoyi.wvp.gb28181.controller.bean.ChannelToRegionByGbDeviceParam;
import com.ruoyi.wvp.gb28181.controller.bean.ChannelToRegionParam;
import com.ruoyi.wvp.gb28181.service.IGbChannelPlayService;
import com.ruoyi.wvp.gb28181.service.IGbChannelService;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.bean.ErrorCallback;
import com.ruoyi.wvp.service.bean.InviteErrorCode;
import com.ruoyi.wvp.storager.IRedisCatchStorage;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
@Tag(name = "全局通道管理")
@RestController
@Slf4j
@RequestMapping(value = "/api/common/channel")
public class CommonChannelController extends BaseController {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IGbChannelService channelService;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private IGbChannelPlayService channelPlayService;
@Autowired
private UserSetting userSetting;
/**
* 获取通道信息
*
* @param id 通道的数据库自增Id
* @return
*/
@GetMapping(value = "/one/{id}")
public AjaxResult getOne(@PathVariable int id) {
return success(channelService.getOne(id));
}
/**
* 获取通道信息
*
* @return
*/
@GetMapping("/industry/list")
public AjaxResult getIndustryCodeList() {
return success(channelService.getIndustryCodeList());
}
/**
* 获取通道类型列表
*
* @return
*/
@GetMapping("/type/list")
public AjaxResult getDeviceTypeList() {
return success(channelService.getDeviceTypeList());
}
/**
* 获取网络标识列表
*
* @return
*/
@GetMapping("/network/identification/list")
public AjaxResult getNetworkIdentificationTypeList() {
return success(channelService.getNetworkIdentificationTypeList());
}
/**
* 修改通道信息
*
* @param channel
*/
@PostMapping("/update")
public AjaxResult update(@RequestBody CommonGBChannel channel) {
channelService.update(channel);
return success();
}
/**
* 重置通道
*
* @param id
*/
@PostMapping("/reset/{id}")
public AjaxResult reset(@PathVariable Integer id) {
channelService.reset(id);
return success();
}
/**
* 新增通道
*
* @param channel 通道
* @return
*/
@PostMapping("/add")
public AjaxResult add(@RequestBody CommonGBChannel channel) {
channelService.add(channel);
return success(channel);
}
@Parameter(name = "page", description = "当前页", required = true)
@Parameter(name = "count", description = "每页查询数量", required = true)
@Parameter(name = "query", description = "查询内容")
@Parameter(name = "online", description = "是否在线")
@Parameter(name = "hasRecordPlan", description = "是否已设置录制计划")
@Parameter(name = "channelType", description = "通道类型, 0国标设备1推流设备2拉流代理")
@GetMapping("/list")
public PageInfo<CommonGBChannel> queryList(int page, int count,
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Boolean hasRecordPlan,
@RequestParam(required = false) Integer channelType) {
if (ObjectUtils.isEmpty(query)) {
query = null;
}
return channelService.queryList(page, count, query, online, hasRecordPlan, channelType);
}
/**
* 获取通道列表
*
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param query 查询内容
* @param online 是否在线
* @param channelType 通道类型, 0国标设备1推流设备2拉流代理
* @param civilCode 行政区划
* @return
*/
@GetMapping("/civilcode/list")
public TableDataInfo queryListByCivilCode(int pageNum, int pageSize,
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Integer channelType,
@RequestParam(required = false) String civilCode) {
startPage();
if (ObjectUtils.isEmpty(query)) {
query = null;
}
List<CommonGBChannel> list = channelService.queryListByCivilCode(pageNum, pageSize, query, online, channelType, civilCode);
return getDataTable(list);
}
/**
* 根据ParentId获取通道列表
*
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param query 查询内容
* @param online 是否在线
* @param channelType 通道类型, 0国标设备1推流设备2拉流代理
* @param groupDeviceId 业务分组下的父节点ID
* @return
*/
@GetMapping("/parent/list")
public TableDataInfo queryListByParentId(int pageNum, int pageSize,
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Integer channelType,
@RequestParam(required = false) String groupDeviceId) {
startPage();
if (ObjectUtils.isEmpty(query)) {
query = null;
}
List<CommonGBChannel> list = channelService.queryListByParentId(pageNum, pageSize, query, online, channelType, groupDeviceId);
return getDataTable(list);
}
/**
* 添加通道
*
* @param param
*/
@PostMapping("/region/add")
public AjaxResult addChannelToRegion(@RequestBody ChannelToRegionParam param) {
Assert.notEmpty(param.getChannelIds(), "通道ID不可为空");
Assert.hasLength(param.getCivilCode(), "未添加行政区划");
channelService.addChannelToRegion(param.getCivilCode(), param.getChannelIds());
return success();
}
/**
* 删除通道
*
* @param param
*/
@PostMapping("/region/delete")
public AjaxResult deleteChannelToRegion(@RequestBody ChannelToRegionParam param) {
Assert.isTrue(!param.getChannelIds().isEmpty() || !ObjectUtils.isEmpty(param.getCivilCode()), "参数异常");
channelService.deleteChannelToRegion(param.getCivilCode(), param.getChannelIds());
return success();
}
@PostMapping("/region/device/add")
public void addChannelToRegionByGbDevice(@RequestBody ChannelToRegionByGbDeviceParam param) {
Assert.notEmpty(param.getDeviceIds(), "参数异常");
Assert.hasLength(param.getCivilCode(), "未添加行政区划");
channelService.addChannelToRegionByGbDevice(param.getCivilCode(), param.getDeviceIds());
}
@PostMapping("/region/device/delete")
public void deleteChannelToRegionByGbDevice(@RequestBody ChannelToRegionByGbDeviceParam param) {
Assert.notEmpty(param.getDeviceIds(), "参数异常");
channelService.deleteChannelToRegionByGbDevice(param.getDeviceIds());
}
/**
* 添加通道信息
*
* @param param
*/
@PostMapping("/group/add")
public AjaxResult addChannelToGroup(@RequestBody ChannelToGroupParam param) {
Assert.notEmpty(param.getChannelIds(), "通道ID不可为空");
Assert.hasLength(param.getParentId(), "未添加上级分组编号");
Assert.hasLength(param.getBusinessGroup(), "未添加业务分组");
channelService.addChannelToGroup(param.getParentId(), param.getBusinessGroup(), param.getChannelIds());
return success();
}
/**
* 删除通道
*
* @param param
*/
@PostMapping("/group/delete")
public AjaxResult deleteChannelToGroup(@RequestBody ChannelToGroupParam param) {
Assert.isTrue(!param.getChannelIds().isEmpty()
|| (!ObjectUtils.isEmpty(param.getParentId()) && !ObjectUtils.isEmpty(param.getBusinessGroup())),
"参数异常");
channelService.deleteChannelToGroup(param.getParentId(), param.getBusinessGroup(), param.getChannelIds());
return success();
}
@PostMapping("/group/device/add")
public void addChannelToGroupByGbDevice(@RequestBody ChannelToGroupByGbDeviceParam param) {
Assert.notEmpty(param.getDeviceIds(), "参数异常");
Assert.hasLength(param.getParentId(), "未添加上级分组编号");
Assert.hasLength(param.getBusinessGroup(), "未添加业务分组");
channelService.addChannelToGroupByGbDevice(param.getParentId(), param.getBusinessGroup(), param.getDeviceIds());
}
@PostMapping("/group/device/delete")
public void deleteChannelToGroupByGbDevice(@RequestBody ChannelToGroupByGbDeviceParam param) {
Assert.notEmpty(param.getDeviceIds(), "参数异常");
channelService.deleteChannelToGroupByGbDevice(param.getDeviceIds());
}
@GetMapping("/play")
public DeferredResult<WVPResult<StreamContent>> deleteChannelToGroupByGbDevice(HttpServletRequest request, Integer channelId) {
Assert.notNull(channelId, "参数异常");
CommonGBChannel channel = channelService.getOne(channelId);
Assert.notNull(channel, "通道不存在");
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
WVPResult<StreamContent> wvpResult = WVPResult.success();
if (streamInfo != null) {
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo = streamInfo.clone();//深拷贝
String host;
try {
URL url = new URL(request.getRequestURL().toString());
host = url.getHost();
} catch (MalformedURLException e) {
host = request.getLocalAddr();
}
streamInfo.channgeStreamIp(host);
}
if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
&& !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
}
wvpResult.setData(new StreamContent(streamInfo));
} else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
result.setResult(wvpResult);
} else {
result.setResult(WVPResult.fail(code, msg));
}
};
channelPlayService.play(channel, null, userSetting.getRecordSip(), callback);
return result;
}
}

View File

@@ -1,152 +0,0 @@
/**
* 设备设置命令API接口
*
* @author lawrencehj
* @date 2021年2月2日
*/
package com.ruoyi.wvp.gb28181.controller;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Device;
import com.ruoyi.wvp.gb28181.service.IDeviceService;
import com.ruoyi.wvp.gb28181.transmit.callback.DeferredResultHolder;
import com.ruoyi.wvp.gb28181.transmit.callback.RequestMessage;
import com.ruoyi.wvp.gb28181.transmit.cmd.impl.SIPCommander;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.UUID;
@Slf4j
@Tag(name = "国标设备配置")
@RestController
@RequestMapping("/api/device/config")
public class DeviceConfig extends BaseController {
@Autowired
private IDeviceService deviceService;
@Autowired
private SIPCommander cmder;
@Autowired
private DeferredResultHolder resultHolder;
/**
* 看守位控制命令API接口
*
* @param deviceId 设备ID
* @param channelId 通道ID
* @param name 名称
* @param expiration 到期时间
* @param heartBeatInterval 心跳间隔
* @param heartBeatCount 心跳计数
* @return
*/
@GetMapping("/basicParam/{deviceId}")
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "name", description = "名称")
@Parameter(name = "expiration", description = "到期时间")
@Parameter(name = "heartBeatInterval", description = "心跳间隔")
@Parameter(name = "heartBeatCount", description = "心跳计数")
public DeferredResult<String> homePositionApi(@PathVariable String deviceId,
@RequestParam(required = false) String channelId,
@RequestParam(required = false) String name,
@RequestParam(required = false) String expiration,
@RequestParam(required = false) String heartBeatInterval,
@RequestParam(required = false) String heartBeatCount) {
if (log.isDebugEnabled()) {
log.debug("报警复位API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
String uuid = UUID.randomUUID().toString();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + deviceId + channelId;
try {
cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(String.format("设备配置操作失败,错误码: %s, %s", event.statusCode, event.msg));
resultHolder.invokeResult(msg);
});
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 设备配置: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
DeferredResult<String> result = new DeferredResult<String>(3 * 1000L);
result.onTimeout(() -> {
log.warn(String.format("设备配置操作超时, 设备未返回应答指令"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("Status", "Timeout");
json.put("Description", "设备配置操作超时, 设备未返回应答指令");
msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令");
resultHolder.invokeResult(msg);
});
resultHolder.put(key, uuid, result);
return result;
}
/**
* 设备配置查询请求API接口
*
* @param deviceId 设备ID
* @param configType 配置类型
* @param channelId 通道ID
* @return
*/
@GetMapping("/query/{deviceId}/{configType}")
public DeferredResult<String> configDownloadApi(@PathVariable String deviceId,
@PathVariable String configType,
@RequestParam(required = false) String channelId) {
if (log.isDebugEnabled()) {
log.debug("设备状态查询API调用");
}
String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : deviceId + channelId);
String uuid = UUID.randomUUID().toString();
Device device = deviceService.getDeviceByDeviceId(deviceId);
try {
cmder.deviceConfigQuery(device, channelId, configType, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(String.format("获取设备配置失败,错误码: %s, %s", event.statusCode, event.msg));
resultHolder.invokeResult(msg);
});
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 获取设备配置: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
DeferredResult<String> result = new DeferredResult<String>(3 * 1000L);
result.onTimeout(() -> {
log.warn(String.format("获取设备配置超时"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData("Timeout. Device did not response to this command.");
resultHolder.invokeResult(msg);
});
resultHolder.put(key, uuid, result);
return result;
}
}

View File

@@ -1,385 +0,0 @@
/**
* 设备控制命令API接口
*
* @author lawrencehj
* @date 2021年2月1日
*/
package com.ruoyi.wvp.gb28181.controller;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Device;
import com.ruoyi.wvp.gb28181.service.IDeviceService;
import com.ruoyi.wvp.gb28181.transmit.callback.DeferredResultHolder;
import com.ruoyi.wvp.gb28181.transmit.callback.RequestMessage;
import com.ruoyi.wvp.gb28181.transmit.cmd.ISIPCommander;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.sip.InvalidArgumentException;
import javax.sip.SipException;
import java.text.ParseException;
import java.util.UUID;
@Tag(name = "国标设备控制")
@Slf4j
@RestController
@RequestMapping("/api/device/control")
public class DeviceControl extends BaseController {
@Autowired
private IDeviceService deviceService;
@Autowired
private ISIPCommander cmder;
@Autowired
private DeferredResultHolder resultHolder;
/**
* 远程启动控制命令API接口
*
* @param deviceId 设备ID
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@GetMapping("/teleboot/{deviceId}")
public void teleBootApi(@PathVariable String deviceId) {
if (log.isDebugEnabled()) {
log.debug("设备远程启动API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
try {
cmder.teleBootCmd(device);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 远程启动: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
}
/**
* 录像控制命令API接口
*
* @param deviceId 设备国标编号
* @param recordCmdStr Record手动录像StopRecord停止手动录像
* @param channelId 通道编码(可选) 通道国标编号
*/
@GetMapping("/record/{deviceId}/{recordCmdStr}")
public AjaxResult recordApi(
@PathVariable String deviceId,
@PathVariable String recordCmdStr,
String channelId) {
if (log.isDebugEnabled()) {
log.debug("开始/停止录像API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
String uuid = UUID.randomUUID().toString();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId;
DeferredResult<ResponseEntity<WVPResult<String>>> result = new DeferredResult<>(3 * 1000L);
result.onTimeout(() -> {
log.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setId(uuid);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答"));
resultHolder.invokeAllResult(msg);
});
if (resultHolder.exist(key, null)) {
return success(result);
}
resultHolder.put(key, uuid, result);
try {
cmder.recordCmd(device, channelId, recordCmdStr, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("开始/停止录像操作失败,错误码: %s, %s", event.statusCode, event.msg)));
resultHolder.invokeAllResult(msg);
}, null);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 开始/停止录像: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
return success(result);
}
/**
* 报警布防/撤防命令API接口
*
* @param deviceId 设备ID
* @param guardCmdStr SetGuard布防ResetGuard撤防
*/
@GetMapping("/guard/{deviceId}/{guardCmdStr}")
public AjaxResult guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) {
if (log.isDebugEnabled()) {
log.debug("布防/撤防API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + deviceId;
String uuid = UUID.randomUUID().toString();
try {
cmder.guardCmd(device, guardCmdStr, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("布防/撤防操作失败,错误码: %s, %s", event.statusCode, event.msg)));
resultHolder.invokeResult(msg);
}, null);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage());
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>(3 * 1000L);
resultHolder.put(key, uuid, result);
result.onTimeout(() -> {
log.warn(String.format("布防/撤防操作超时, 设备未返回应答指令"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setId(uuid);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答"));
resultHolder.invokeResult(msg);
});
return success(result);
}
/**
* 报警复位API接口
*
* @param deviceId 设备ID
* @param alarmMethod 报警方式(可选)
* @param alarmType 报警类型(可选)
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "alarmMethod", description = "报警方式")
@Parameter(name = "alarmType", description = "报警类型")
@GetMapping("/reset_alarm/{deviceId}")
public DeferredResult<ResponseEntity<WVPResult<String>>> resetAlarmApi(@PathVariable String deviceId, String channelId,
@RequestParam(required = false) String alarmMethod,
@RequestParam(required = false) String alarmType) {
if (log.isDebugEnabled()) {
log.debug("报警复位API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
String uuid = UUID.randomUUID().toString();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId;
try {
cmder.alarmCmd(device, alarmMethod, alarmType, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("操作失败,错误码: %s, %s", event.statusCode, event.msg)));
resultHolder.invokeResult(msg);
}, null);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 报警复位: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
DeferredResult<ResponseEntity<WVPResult<String>>> result = new DeferredResult<>(3 * 1000L);
result.onTimeout(() -> {
log.warn(String.format("报警复位操作超时, 设备未返回应答指令"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答"));
resultHolder.invokeResult(msg);
});
resultHolder.put(key, uuid, result);
return result;
}
/**
* 强制关键帧API接口
*
* @param deviceId 设备ID
* @param channelId 通道ID
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号")
@GetMapping("/i_frame/{deviceId}")
public JSONObject iFrame(@PathVariable String deviceId,
@RequestParam(required = false) String channelId) {
if (log.isDebugEnabled()) {
log.debug("强制关键帧API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
try {
cmder.iFrameCmd(device, channelId);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 强制关键帧: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
JSONObject json = new JSONObject();
json.put("DeviceID", deviceId);
json.put("ChannelID", channelId);
json.put("Result", "OK");
return json;
}
/**
* 看守位控制命令API接口
*
* @param deviceId 设备ID
* @param enabled 看守位使能1:开启,0:关闭
* @param resetTime 自动归位时间间隔(可选)
* @param presetIndex 调用预置位编号(可选)
* @param channelId 通道编码(可选)
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "enabled", description = "是否开启看守位", required = true)
@Parameter(name = "presetIndex", description = "调用预置位编号")
@Parameter(name = "resetTime", description = "自动归位时间间隔 单位:秒")
@GetMapping("/home_position")
public DeferredResult<WVPResult<String>> homePositionApi(String deviceId, String channelId, Boolean enabled,
@RequestParam(required = false) Integer resetTime,
@RequestParam(required = false) Integer presetIndex) {
if (log.isDebugEnabled()) {
log.debug("报警复位API调用");
}
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId);
String uuid = UUID.randomUUID().toString();
Device device = deviceService.getDeviceByDeviceId(deviceId);
try {
cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> {
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("操作失败,错误码: %s, %s", event.statusCode, event.msg)));
resultHolder.invokeResult(msg);
}, null);
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 看守位控制: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
DeferredResult<WVPResult<String>> result = new DeferredResult<>(3 * 1000L);
result.onTimeout(() -> {
log.warn(String.format("看守位控制操作超时, 设备未返回应答指令"));
// 释放rtpserver
RequestMessage msg = new RequestMessage();
msg.setId(uuid);
msg.setKey(key);
msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); //("看守位控制操作超时, 设备未返回应答指令");
resultHolder.invokeResult(msg);
});
resultHolder.put(key, uuid, result);
return result;
}
/**
* 拉框放大
*
* @param deviceId 设备id
* @param channelId 通道id
* @param length 播放窗口长度像素值
* @param width 播放窗口宽度像素值
* @param midpointx 拉框中心的横轴坐标像素值
* @param midpointy 拉框中心的纵轴坐标像素值
* @param lengthx 拉框长度像素值
* @param lengthy 拉框宽度像素值
* @return
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "length", description = "播放窗口长度像素值", required = true)
@Parameter(name = "midpointx", description = "拉框中心的横轴坐标像素值", required = true)
@Parameter(name = "midpointy", description = "拉框中心的纵轴坐标像素值", required = true)
@Parameter(name = "lengthx", description = "拉框长度像素值", required = true)
@Parameter(name = "lengthy", description = "lengthy", required = true)
@GetMapping("drag_zoom/zoom_in")
public void dragZoomIn(@RequestParam String deviceId,
@RequestParam(required = false) String channelId,
@RequestParam int length,
@RequestParam int width,
@RequestParam int midpointx,
@RequestParam int midpointy,
@RequestParam int lengthx,
@RequestParam int lengthy) throws RuntimeException {
if (log.isDebugEnabled()) {
log.debug(String.format("设备拉框放大 API调用deviceId%s channelId%s length%d width%d midpointx%d midpointy%d lengthx%d lengthy%d", deviceId, channelId, length, width, midpointx, midpointy, lengthx, lengthy));
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<DragZoomIn>\r\n");
cmdXml.append("<Length>" + length + "</Length>\r\n");
cmdXml.append("<Width>" + width + "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx + "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy + "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx + "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy + "</LengthY>\r\n");
cmdXml.append("</DragZoomIn>\r\n");
try {
cmder.dragZoomCmd(device, channelId, cmdXml.toString());
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 拉框放大: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
}
/**
* 拉框缩小
*
* @param deviceId 设备id
* @param channelId 通道id
* @param length 播放窗口长度像素值
* @param width 播放窗口宽度像素值
* @param midpointx 拉框中心的横轴坐标像素值
* @param midpointy 拉框中心的纵轴坐标像素值
* @param lengthx 拉框长度像素值
* @param lengthy 拉框宽度像素值
* @return
*/
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号")
@Parameter(name = "length", description = "播放窗口长度像素值", required = true)
@Parameter(name = "width", description = "拉框中心的横轴坐标像素值", required = true)
@Parameter(name = "midpointx", description = "拉框中心的横轴坐标像素值", required = true)
@Parameter(name = "midpointy", description = "拉框中心的纵轴坐标像素值", required = true)
@Parameter(name = "lengthx", description = "拉框长度像素值", required = true)
@Parameter(name = "lengthy", description = "拉框宽度像素值", required = true)
@GetMapping("/drag_zoom/zoom_out")
public void dragZoomOut(@RequestParam String deviceId,
@RequestParam(required = false) String channelId,
@RequestParam int length,
@RequestParam int width,
@RequestParam int midpointx,
@RequestParam int midpointy,
@RequestParam int lengthx,
@RequestParam int lengthy) {
if (log.isDebugEnabled()) {
log.debug(String.format("设备拉框缩小 API调用deviceId%s channelId%s length%d width%d midpointx%d midpointy%d lengthx%d lengthy%d", deviceId, channelId, length, width, midpointx, midpointy, lengthx, lengthy));
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<DragZoomOut>\r\n");
cmdXml.append("<Length>" + length + "</Length>\r\n");
cmdXml.append("<Width>" + width + "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx + "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy + "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx + "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy + "</LengthY>\r\n");
cmdXml.append("</DragZoomOut>\r\n");
try {
cmder.dragZoomCmd(device, channelId, cmdXml.toString());
} catch (InvalidArgumentException | SipException | ParseException e) {
log.error("[命令发送失败] 拉框缩小: {}", e.getMessage());
throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage());
}
}
}

View File

@@ -1,115 +0,0 @@
package com.ruoyi.wvp.gb28181.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Group;
import com.ruoyi.wvp.gb28181.service.IGroupService;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@Tag(name = "分组管理")
@RestController
@RequestMapping("/api/group")
public class GroupController extends BaseController {
@Autowired
private IGroupService groupService;
/**
* 添加分组
*
* @param group
*/
@ResponseBody
@PostMapping("/add")
public AjaxResult add(@RequestBody Group group) {
groupService.add(group);
return success();
}
/**
* 查询分组树
*
* @param query 要搜索的内容
* @param parent 所属分组编号
* @param hasChannel 是否包含通道
* @return
*/
@ResponseBody
@GetMapping("/tree/list")
public AjaxResult queryForTree(
@RequestParam(required = false) String query,
@RequestParam(required = false) Integer parent,
@RequestParam(required = false) Boolean hasChannel
) {
if (ObjectUtils.isEmpty(query)) {
query = null;
}
return success(groupService.queryForTree(query, parent, hasChannel));
}
/**
* 更新分组
*
* @param group
*/
@ResponseBody
@PostMapping("/update")
public AjaxResult update(@RequestBody Group group) {
groupService.update(group);
return success();
}
/**
* 删除分组
*
* @param id 分组id
*/
@ResponseBody
@DeleteMapping("/delete/{id}")
public AjaxResult delete(@PathVariable Integer id) {
Assert.notNull(id, "分组iddeviceId不需要存在");
boolean result = groupService.delete(id);
if (!result) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "移除失败");
}
return success();
}
@Operation(summary = "获取所属的行政区划下的行政区划")
@Parameter(name = "deviceId", description = "当前的行政区划", required = false)
@ResponseBody
@GetMapping("/path")
public List<Group> getPath(String deviceId, String businessGroup) {
return groupService.getPath(deviceId, businessGroup);
}
// @Operation(summary = "根据分组Id查询分组")
// @Parameter(name = "groupDeviceId", description = "分组节点编号", required = true)
// @ResponseBody
// @GetMapping("/one")
// public Group queryGroupByDeviceId(
// @RequestParam(required = true) String deviceId
// ){
// Assert.hasLength(deviceId, "");
// return groupService.queryGroupByDeviceId(deviceId);
// }
// @Operation(summary = "从通道中同步分组")
// @ResponseBody
// @GetMapping("/sync")
// public void sync(){
// groupService.syncFromChannel();
// }
}

View File

@@ -1,321 +0,0 @@
package com.ruoyi.wvp.gb28181.controller;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.conf.SipConfig;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Platform;
import com.ruoyi.wvp.gb28181.bean.PlatformChannel;
import com.ruoyi.wvp.gb28181.bean.SubscribeHolder;
import com.ruoyi.wvp.gb28181.controller.bean.UpdateChannelParam;
import com.ruoyi.wvp.gb28181.service.IPlatformChannelService;
import com.ruoyi.wvp.gb28181.service.IPlatformService;
import com.ruoyi.wvp.utils.DateUtil;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
/**
* 级联平台管理
*/
@Tag(name = "级联平台管理")
@Slf4j
@RestController
@RequestMapping("/api/platform")
public class PlatformController extends BaseController {
@Autowired
private IPlatformChannelService platformChannelService;
@Autowired
private SubscribeHolder subscribeHolder;
@Autowired
private SipConfig sipConfig;
@Autowired
private IPlatformService platformService;
/**
* 获取上级平台信息
*
* @return
*/
@GetMapping("/server_config")
public AjaxResult serverConfig() {
JSONObject result = new JSONObject();
result.put("deviceIp", sipConfig.getShowIp());
result.put("devicePort", sipConfig.getPort());
result.put("username", sipConfig.getId());
result.put("password", sipConfig.getPassword());
return success(result);
}
@Parameter(name = "id", description = "平台国标编号", required = true)
@GetMapping("/info/{id}")
public Platform getPlatform(@PathVariable String id) {
Platform parentPlatform = platformService.queryPlatformByServerGBId(id);
if (parentPlatform != null) {
return parentPlatform;
} else {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未查询到此平台");
}
}
/**
* 获取上级平台列表
*
* @param page 当前页
* @param count 每页数量
* @param query 查询内容
* @return
*/
@GetMapping("/query")
public AjaxResult platforms(int page, int count,
@RequestParam(required = false) String query) {
PageInfo<Platform> parentPlatformPageInfo = platformService.queryPlatformList(page, count, query);
if (parentPlatformPageInfo != null && !parentPlatformPageInfo.getList().isEmpty()) {
for (Platform platform : parentPlatformPageInfo.getList()) {
platform.setMobilePositionSubscribe(subscribeHolder.getMobilePositionSubscribe(platform.getServerGBId()) != null);
platform.setCatalogSubscribe(subscribeHolder.getCatalogSubscribe(platform.getServerGBId()) != null);
}
}
return success(parentPlatformPageInfo);
}
/**
* 添加上级平台信息
*
* @param platform
*/
@PostMapping("/add")
@ResponseBody
public AjaxResult add(@RequestBody Platform platform) {
if (log.isDebugEnabled()) {
log.debug("保存上级平台信息API调用");
}
Assert.notNull(platform.getName(), "平台名称不可为空");
Assert.notNull(platform.getServerGBId(), "上级平台国标编号不可为空");
Assert.notNull(platform.getServerIp(), "上级平台IP不可为空");
Assert.isTrue(platform.getServerPort() > 0 && platform.getServerPort() < 65535, "上级平台端口异常");
Assert.notNull(platform.getDeviceGBId(), "本平台国标编号不可为空");
if (ObjectUtils.isEmpty(platform.getServerGBDomain())) {
platform.setServerGBDomain(platform.getServerGBId().substring(0, 6));
}
if (platform.getExpires() <= 0) {
platform.setExpires(3600);
}
if (platform.getKeepTimeout() <= 0) {
platform.setKeepTimeout(60);
}
if (ObjectUtils.isEmpty(platform.getTransport())) {
platform.setTransport("UDP");
}
if (ObjectUtils.isEmpty(platform.getCharacterSet())) {
platform.setCharacterSet("GB2312");
}
Platform parentPlatformOld = platformService.queryPlatformByServerGBId(platform.getServerGBId());
if (parentPlatformOld != null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "平台 " + platform.getServerGBId() + " 已存在");
}
platform.setCreateTime(DateUtil.getNow());
platform.setUpdateTime(DateUtil.getNow());
boolean updateResult = platformService.add(platform);
if (!updateResult) {
throw new ControllerException(ErrorCode.ERROR100);
}
return success();
}
/**
* 更新上级平台信息
*
* @param parentPlatform
*/
@PostMapping("/update")
@ResponseBody
public AjaxResult updatePlatform(@RequestBody Platform parentPlatform) {
if (log.isDebugEnabled()) {
log.debug("保存上级平台信息API调用");
}
if (ObjectUtils.isEmpty(parentPlatform.getName())
|| ObjectUtils.isEmpty(parentPlatform.getServerGBId())
|| ObjectUtils.isEmpty(parentPlatform.getServerGBDomain())
|| ObjectUtils.isEmpty(parentPlatform.getServerIp())
|| ObjectUtils.isEmpty(parentPlatform.getServerPort())
|| ObjectUtils.isEmpty(parentPlatform.getDeviceGBId())
|| ObjectUtils.isEmpty(parentPlatform.getExpires())
|| ObjectUtils.isEmpty(parentPlatform.getKeepTimeout())
|| ObjectUtils.isEmpty(parentPlatform.getTransport())
|| ObjectUtils.isEmpty(parentPlatform.getCharacterSet())
) {
throw new ControllerException(ErrorCode.ERROR400);
}
platformService.update(parentPlatform);
return success();
}
/**
* 删除上级平台信息
*
* @param id 上级平台ID
* @return
*/
@DeleteMapping("/delete/{id}")
@ResponseBody
public AjaxResult deletePlatform(@PathVariable Integer id) {
if (log.isDebugEnabled()) {
log.debug("删除上级平台API调用");
}
DeferredResult<Object> deferredResult = new DeferredResult<>();
platformService.delete(id, (object) -> {
deferredResult.setResult(WVPResult.success());
});
return success(deferredResult);
}
/**
* 判断上级平台是否存在
*
* @param serverGBId 上级平台的国标编号
* @return
*/
@GetMapping("/exit/{serverGBId}")
@ResponseBody
public AjaxResult exitPlatform(@PathVariable String serverGBId) {
Platform platform = platformService.queryPlatformByServerGBId(serverGBId);
return success(platform != null);
}
/**
* 查询上级平台列表
*
* @param page 当前页
* @param count 每页条数
* @param platformId 上级平台的数据ID
* @param query 通道类型, 0国标设备1推流设备2拉流代理
* @param channelType 查询内容
* @param online 是否在线
* @param hasShare 是否已经共享
* @return
*/
@GetMapping("/channel/list")
@ResponseBody
public AjaxResult queryChannelList(int page, int count,
@RequestParam(required = false) Integer platformId,
@RequestParam(required = false) String query,
@RequestParam(required = false) Integer channelType,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Boolean hasShare) {
Assert.notNull(platformId, "上级平台的数据ID不可为NULL");
if (ObjectUtils.isEmpty(query)) {
query = null;
}
return success(platformChannelService.queryChannelList(page, count, query, channelType, online, platformId, hasShare));
}
@PostMapping("/channel/add")
@ResponseBody
public AjaxResult addChannel(@RequestBody UpdateChannelParam param) {
if (log.isDebugEnabled()) {
log.debug("给上级平台添加国标通道API调用");
}
int result = 0;
if (param.getChannelIds() == null || param.getChannelIds().isEmpty()) {
if (param.isAll()) {
log.info("[国标级联]添加所有通道到上级平台, {}", param.getPlatformId());
result = platformChannelService.addAllChannel(param.getPlatformId());
}
} else {
result = platformChannelService.addChannels(param.getPlatformId(), param.getChannelIds());
}
if (result <= 0) {
throw new ControllerException(ErrorCode.ERROR100);
}
return success();
}
@DeleteMapping("/channel/remove")
@ResponseBody
public AjaxResult delChannelForGB(@RequestBody UpdateChannelParam param) {
if (log.isDebugEnabled()) {
log.debug("给上级平台删除国标通道API调用");
}
int result = 0;
if (param.getChannelIds() == null || param.getChannelIds().isEmpty()) {
if (param.isAll()) {
log.info("[国标级联]移除所有通道,上级平台, {}", param.getPlatformId());
result = platformChannelService.removeAllChannel(param.getPlatformId());
}
} else {
result = platformChannelService.removeChannels(param.getPlatformId(), param.getChannelIds());
}
if (result <= 0) {
throw new ControllerException(ErrorCode.ERROR100);
}
return success();
}
/**
* 上级平台推送通道
*
* @param id 平台ID
*/
@GetMapping("/channel/push//{id}")
@ResponseBody
public AjaxResult pushChannel(@PathVariable Integer id) {
Assert.notNull(id, "平台ID不可为空");
platformChannelService.pushChannel(id);
return success();
}
@PostMapping("/channel/device/add")
@ResponseBody
public AjaxResult addChannelByDevice(@RequestBody UpdateChannelParam param) {
Assert.notNull(param.getPlatformId(), "平台ID不可为空");
Assert.notNull(param.getDeviceIds(), "设备ID不可为空");
Assert.notEmpty(param.getDeviceIds(), "设备ID不可为空");
platformChannelService.addChannelByDevice(param.getPlatformId(), param.getDeviceIds());
return success();
}
@PostMapping("/channel/device/remove")
@ResponseBody
public AjaxResult removeChannelByDevice(@RequestBody UpdateChannelParam param) {
Assert.notNull(param.getPlatformId(), "平台ID不可为空");
Assert.notNull(param.getDeviceIds(), "设备ID不可为空");
Assert.notEmpty(param.getDeviceIds(), "设备ID不可为空");
platformChannelService.removeChannelByDevice(param.getPlatformId(), param.getDeviceIds());
return success();
}
@PostMapping("/channel/custom/update")
@ResponseBody
public void updateCustomChannel(@RequestBody PlatformChannel channel) {
Assert.isTrue(channel.getId() > 0, "共享通道ID必须存在");
platformChannelService.updateCustomChannel(channel);
}
}

View File

@@ -1,286 +0,0 @@
package com.ruoyi.wvp.gb28181.controller;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.common.InviteSessionType;
import com.ruoyi.wvp.common.StreamInfo;
import com.ruoyi.wvp.conf.UserSetting;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Device;
import com.ruoyi.wvp.gb28181.bean.DeviceChannel;
import com.ruoyi.wvp.gb28181.bean.SsrcTransaction;
import com.ruoyi.wvp.gb28181.service.IDeviceChannelService;
import com.ruoyi.wvp.gb28181.service.IDeviceService;
import com.ruoyi.wvp.gb28181.service.IInviteStreamService;
import com.ruoyi.wvp.gb28181.service.IPlayService;
import com.ruoyi.wvp.gb28181.session.SipInviteSessionManager;
import com.ruoyi.wvp.gb28181.transmit.callback.DeferredResultHolder;
import com.ruoyi.wvp.gb28181.transmit.callback.RequestMessage;
import com.ruoyi.wvp.media.bean.MediaServer;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.bean.InviteErrorCode;
import com.ruoyi.wvp.utils.DateUtil;
import com.ruoyi.wvp.vmanager.bean.AudioBroadcastResult;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.UUID;
/**
* @author lin
*/
@Tag(name = "国标设备点播")
@Slf4j
@RestController
@RequestMapping("/api/play")
public class PlayController extends BaseController {
@Autowired
private SipInviteSessionManager sessionManager;
@Autowired
private IInviteStreamService inviteStreamService;
@Autowired
private DeferredResultHolder resultHolder;
@Autowired
private IPlayService playService;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private UserSetting userSetting;
@Autowired
private IDeviceService deviceService;
@Autowired
private IDeviceChannelService deviceChannelService;
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@GetMapping("/start/{deviceId}/{channelId}")
public DeferredResult<WVPResult<StreamContent>> play(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId) {
log.info("[开始点播] deviceId{}, channelId{}, ", deviceId, channelId);
Assert.notNull(deviceId, "设备国标编号不可为NULL");
Assert.notNull(channelId, "通道国标编号不可为NULL");
// 获取可用的zlm
Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在");
DeviceChannel channel = deviceChannelService.getOne(deviceId, channelId);
Assert.notNull(channel, "通道不存在");
MediaServer newMediaServerItem = playService.getNewMediaServerItem(device);
RequestMessage requestMessage = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
requestMessage.setKey(key);
String uuid = UUID.randomUUID().toString();
requestMessage.setId(uuid);
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
result.onTimeout(() -> {
log.info("[点播等待超时] deviceId{}, channelId{}, ", deviceId, channelId);
// 释放rtpserver
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
wvpResult.setCode(ErrorCode.ERROR100.getCode());
wvpResult.setMsg("点播超时");
requestMessage.setData(wvpResult);
resultHolder.invokeAllResult(requestMessage);
inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId());
deviceChannelService.stopPlay(channel.getId());
});
// 录像查询以channelId作为deviceId查询
resultHolder.put(key, uuid, result);
playService.play(newMediaServerItem, deviceId, channelId, null, (code, msg, streamInfo) -> {
WVPResult<StreamContent> wvpResult = new WVPResult<>();
if (code == InviteErrorCode.SUCCESS.getCode()) {
wvpResult.setCode(ErrorCode.SUCCESS.getCode());
wvpResult.setMsg(ErrorCode.SUCCESS.getMsg());
if (streamInfo != null) {
if (userSetting.getUseSourceIpAsStreamIp()) {
streamInfo = streamInfo.clone();//深拷贝
String host;
try {
URL url = new URL(request.getRequestURL().toString());
host = url.getHost();
} catch (MalformedURLException e) {
host = request.getLocalAddr();
}
streamInfo.channgeStreamIp(host);
}
if (!ObjectUtils.isEmpty(newMediaServerItem.getTranscodeSuffix()) && !"null".equalsIgnoreCase(newMediaServerItem.getTranscodeSuffix())) {
streamInfo.setStream(streamInfo.getStream() + "_" + newMediaServerItem.getTranscodeSuffix());
}
wvpResult.setData(new StreamContent(streamInfo));
} else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
} else {
wvpResult.setCode(code);
wvpResult.setMsg(msg);
}
requestMessage.setData(wvpResult);
// 此处必须释放所有请求
resultHolder.invokeAllResult(requestMessage);
});
return result;
}
/**
* 停止点播
*
* @param deviceId 设备国标编号
* @param channelId 通道国标编号
* @return
*/
@GetMapping("/stop/{deviceId}/{channelId}")
public AjaxResult playStop(@PathVariable String deviceId, @PathVariable String channelId) {
log.debug(String.format("设备预览/回放停止API调用streamId%s_%s", deviceId, channelId));
if (deviceId == null || channelId == null) {
throw new ControllerException(ErrorCode.ERROR400);
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
DeviceChannel channel = deviceChannelService.getOneForSource(deviceId, channelId);
Assert.notNull(device, "设备不存在");
Assert.notNull(channel, "通道不存在");
String streamId = String.format("%s_%s", device.getDeviceId(), channel.getDeviceId());
playService.stop(InviteSessionType.PLAY, device, channel, streamId);
return success();
}
/**
* 结束转码
*/
@Parameter(name = "key", description = "视频流key", required = true)
@Parameter(name = "mediaServerId", description = "流媒体服务ID", required = true)
@PostMapping("/convertStop/{key}")
public void playConvertStop(@PathVariable String key, String mediaServerId) {
if (mediaServerId == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "流媒体:" + mediaServerId + "不存在");
}
MediaServer mediaInfo = mediaServerService.getOne(mediaServerId);
if (mediaInfo == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "使用的流媒体已经停止运行");
} else {
Boolean deleted = mediaServerService.delFFmpegSource(mediaInfo, key);
if (!deleted) {
throw new ControllerException(ErrorCode.ERROR100);
}
}
}
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "deviceId", description = "通道国标编号", required = true)
@Parameter(name = "timeout", description = "推流超时时间(秒)", required = true)
@GetMapping("/broadcast/{deviceId}/{channelId}")
@PostMapping("/broadcast/{deviceId}/{channelId}")
public AudioBroadcastResult broadcastApi(@PathVariable String deviceId, @PathVariable String channelId, Integer timeout, Boolean broadcastMode) {
if (log.isDebugEnabled()) {
log.debug("语音广播API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
if (device == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId);
}
DeviceChannel channel = deviceChannelService.getOne(deviceId, channelId);
if (channel == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelId);
}
return playService.audioBroadcast(device, channel, broadcastMode);
}
@Operation(summary = "停止语音广播")
@Parameter(name = "deviceId", description = "设备Id", required = true)
@Parameter(name = "channelId", description = "通道Id", required = true)
@GetMapping("/broadcast/stop/{deviceId}/{channelId}")
@PostMapping("/broadcast/stop/{deviceId}/{channelId}")
public void stopBroadcast(@PathVariable String deviceId, @PathVariable String channelId) {
if (log.isDebugEnabled()) {
log.debug("停止语音广播API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在");
DeviceChannel channel = deviceChannelService.getOne(deviceId, channelId);
Assert.notNull(channel, "通道不存在");
playService.stopAudioBroadcast(device, channel);
}
@GetMapping("/ssrc")
public JSONObject getSSRC() {
if (log.isDebugEnabled()) {
log.debug("获取所有的ssrc");
}
JSONArray objects = new JSONArray();
List<SsrcTransaction> allSsrc = sessionManager.getAll();
for (SsrcTransaction transaction : allSsrc) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("deviceId", transaction.getDeviceId());
jsonObject.put("channelId", transaction.getChannelId());
jsonObject.put("ssrc", transaction.getSsrc());
jsonObject.put("streamId", transaction.getStream());
objects.add(jsonObject);
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("data", objects);
jsonObject.put("count", objects.size());
return jsonObject;
}
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@GetMapping("/snap")
public DeferredResult<String> getSnap(String deviceId, String channelId) {
if (log.isDebugEnabled()) {
log.debug("获取截图: {}/{}", deviceId, channelId);
}
DeferredResult<String> result = new DeferredResult<>(3 * 1000L);
String key = DeferredResultHolder.CALLBACK_CMD_SNAP + deviceId;
String uuid = UUID.randomUUID().toString();
resultHolder.put(key, uuid, result);
RequestMessage message = new RequestMessage();
message.setKey(key);
message.setId(uuid);
String fileName = deviceId + "_" + channelId + "_" + DateUtil.getNowForUrl() + ".jpg";
playService.getSnap(deviceId, channelId, fileName, (code, msg, data) -> {
if (code == InviteErrorCode.SUCCESS.getCode()) {
message.setData(data);
} else {
message.setData(WVPResult.fail(code, msg));
}
resultHolder.invokeResult(message);
});
return result;
}
}

View File

@@ -1,5 +1,7 @@
package com.ruoyi.wvp.gb28181.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.wvp.common.InviteInfo;
import com.ruoyi.wvp.common.InviteSessionType;
@@ -19,12 +21,11 @@ import com.ruoyi.wvp.service.bean.InviteErrorCode;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@@ -47,7 +48,7 @@ import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/api/playback")
public class PlaybackController {
public class PlaybackController extends BaseController {
@Autowired
private SIPCommander cmder;
@@ -70,12 +71,23 @@ public class PlaybackController {
@Autowired
private IDeviceChannelService channelService;
/**
* 开始回放
*
* @param request
* @param deviceId 设备国标编号
* @param channelId 通道国标编号
* @param startTime 开始时间
* @param endTime 结束时间
* @return
*/
@PreAuthorize("@ss.hasPermi('gb:playback:start')")
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "startTime", description = "开始时间", required = true)
@Parameter(name = "endTime", description = "结束时间", required = true)
@GetMapping("/start/{deviceId}/{channelId}")
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, @PathVariable String deviceId, @PathVariable String channelId,
@GetMapping("/start")
public DeferredResult<WVPResult<StreamContent>> start(HttpServletRequest request, String deviceId, String channelId,
String startTime, String endTime) {
if (log.isDebugEnabled()) {
@@ -136,11 +148,15 @@ public class PlaybackController {
}
@Parameter(name = "deviceId", description = "设备国标编号", required = true)
@Parameter(name = "channelId", description = "通道国标编号", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
/**
* 停止回放
*
* @param deviceId 设备国标编号
* @param channelId 通道国标编号
* @param stream 流ID
*/
@GetMapping("/stop/{deviceId}/{channelId}/{stream}")
public void playStop(
public AjaxResult playStop(
@PathVariable String deviceId,
@PathVariable String channelId,
@PathVariable String stream) {
@@ -156,6 +172,7 @@ public class PlaybackController {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "通道:" + deviceChannel + " 未找到");
}
playService.stop(InviteSessionType.PLAYBACK, device, deviceChannel, stream);
return success();
}

View File

@@ -2,6 +2,7 @@ package com.ruoyi.wvp.gb28181.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Device;
import com.ruoyi.wvp.gb28181.service.IDeviceService;
@@ -33,7 +34,7 @@ import java.util.UUID;
@Slf4j
@RestController
@RequestMapping("/api/front-end")
public class PtzController {
public class PtzController extends BaseController {
@Autowired
private SIPCommander cmder;

View File

@@ -1,150 +0,0 @@
package com.ruoyi.wvp.gb28181.controller;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.Region;
import com.ruoyi.wvp.gb28181.bean.RegionTree;
import com.ruoyi.wvp.gb28181.service.IRegionService;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Tag(name = "区域管理")
@RestController
@RequestMapping("/api/region")
public class RegionController extends BaseController {
private final static Logger logger = LoggerFactory.getLogger(RegionController.class);
@Autowired
private IRegionService regionService;
/**
* 添加区域
*
* @param region
*/
@ResponseBody
@PostMapping("/add")
public AjaxResult add(@RequestBody Region region) {
regionService.add(region);
return success();
}
@Operation(summary = "查询区域")
@Parameter(name = "query", description = "要搜索的内容", required = true)
@Parameter(name = "page", description = "当前页", required = true)
@Parameter(name = "count", description = "每页查询数量", required = true)
@ResponseBody
@GetMapping("/page/list")
public PageInfo<Region> query(
@RequestParam(required = false) String query,
@RequestParam(required = true) int page,
@RequestParam(required = true) int count
) {
return regionService.query(query, page, count);
}
/**
* 查询区域
*
* @param query 要搜索的内容
* @param parent 父节点
* @param hasChannel 是否包含通道
* @return
*/
@ResponseBody
@GetMapping("/tree/list")
public AjaxResult queryForTree(
@RequestParam(required = false) String query,
@RequestParam(required = false) Integer parent,
@RequestParam(required = false) Boolean hasChannel
) {
if (ObjectUtils.isEmpty(query)) {
query = null;
}
return success(regionService.queryForTree(query, parent, hasChannel));
}
/**
* 更新区域
*
* @param region
*/
@ResponseBody
@PostMapping("/update")
public AjaxResult update(@RequestBody Region region) {
regionService.update(region);
return success();
}
/**
* 删除区域
*
* @param id 区域ID
*/
@ResponseBody
@DeleteMapping("/delete/{id}")
public AjaxResult delete(@PathVariable Integer id) {
Assert.notNull(id, "区域ID需要存在");
boolean result = regionService.deleteByDeviceId(id);
if (!result) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "移除失败");
}
return success();
}
@Operation(summary = "根据区域Id查询区域")
@Parameter(name = "regionDeviceId", description = "行政区划节点编号", required = true)
@ResponseBody
@GetMapping("/one")
public Region queryRegionByDeviceId(
@RequestParam(required = true) String regionDeviceId
) {
if (ObjectUtils.isEmpty(regionDeviceId.trim())) {
throw new ControllerException(ErrorCode.ERROR400);
}
return regionService.queryRegionByDeviceId(regionDeviceId);
}
/**
* 获取所属的行政区划下的行政区划
*
* @param parent
* @return
*/
@ResponseBody
@GetMapping("/base/child/list")
public AjaxResult getAllChild(@RequestParam(required = false) String parent) {
if (ObjectUtils.isEmpty(parent)) {
parent = null;
}
return success(regionService.getAllChild(parent));
}
@Operation(summary = "获取所属的行政区划下的行政区划")
@Parameter(name = "deviceId", description = "当前的行政区划", required = false)
@ResponseBody
@GetMapping("/path")
public List<Region> getPath(String deviceId) {
return regionService.getPath(deviceId);
}
@Operation(summary = "从通道中同步行政区划")
@ResponseBody
@GetMapping("/sync")
public void sync() {
regionService.syncFromChannel();
}
}

View File

@@ -18,18 +18,25 @@ import java.util.concurrent.ConcurrentHashMap;
public class RecordEndEventListener implements ApplicationListener<RecordEndEvent> {
private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
/**
* 事件处理接口
*/
public interface RecordEndEventHandler{
void handler(RecordInfo recordInfo);
}
/**
* 事件触发
*
* @param event
*/
@Override
public void onApplicationEvent(RecordEndEvent event) {
String deviceId = event.getRecordInfo().getDeviceId();
String channelId = event.getRecordInfo().getChannelId();
int count = event.getRecordInfo().getCount();
int sumNum = event.getRecordInfo().getSumNum();
log.info("录像查询事件触发deviceId{}, channelId: {}, 录像数量{}/{}条", event.getRecordInfo().getDeviceId(),
event.getRecordInfo().getChannelId(), count,sumNum);
if (!handlerMap.isEmpty()) {
RecordEndEventHandler handler = handlerMap.get(deviceId + channelId);
log.info("录像查询事件触发, 发送订阅deviceId{}, channelId: {}",

View File

@@ -2,6 +2,7 @@ package com.ruoyi.wvp.gb28181.service.impl;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.wvp.common.InviteInfo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

View File

@@ -1019,8 +1019,6 @@ public class SIPCommander implements ISIPCommander {
}
recordInfoXml.append("</Query>\r\n");
Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));

View File

@@ -20,6 +20,7 @@ import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
@@ -31,6 +32,7 @@ import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
@@ -82,6 +84,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
// 查询设备是否存在
Device device = redisCatchStorage.getDevice(deviceId);
// 查询上级平台是否存在
String cacheKey = "platform:" + deviceId;
Platform parentPlatform = platformService.queryPlatformByServerGBId(deviceId);
try {
if (device != null && parentPlatform != null) {

View File

@@ -1,223 +0,0 @@
package com.ruoyi.wvp.streamProxy.controller;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.wvp.common.StreamInfo;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.media.bean.MediaServer;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.streamProxy.bean.StreamProxy;
import com.ruoyi.wvp.streamProxy.bean.StreamProxyParam;
import com.ruoyi.wvp.streamProxy.service.IStreamProxyPlayService;
import com.ruoyi.wvp.streamProxy.service.IStreamProxyService;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@SuppressWarnings("rawtypes")
/**
* 拉流代理接口
*/
@Tag(name = "拉流代理", description = "")
@RestController
@Slf4j
@RequestMapping(value = "/api/proxy")
public class StreamProxyController extends BaseController {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private IStreamProxyService streamProxyService;
@Autowired
private IStreamProxyPlayService streamProxyPlayService;
/**
* 分页获取代理
*
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param query 查询内容
* @param pulling 是否正在拉流
* @param mediaServerId 流媒体ID
* @return
*/
@GetMapping(value = "/list")
@ResponseBody
public TableDataInfo list(@RequestParam(required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean pulling,
@RequestParam(required = false) String mediaServerId) {
if (ObjectUtils.isEmpty(mediaServerId)) {
mediaServerId = null;
}
if (ObjectUtils.isEmpty(query)) {
query = null;
}
startPage();
List<StreamProxy> list = streamProxyService.getAll(pageNum, pageSize, query, pulling, mediaServerId);
return getDataTable(list);
}
@Parameter(name = "app", description = "应用名")
@Parameter(name = "stream", description = "流Id")
@GetMapping(value = "/one")
@ResponseBody
public StreamProxy one(String app, String stream) {
return streamProxyService.getStreamProxyByAppAndStream(app, stream);
}
@PostMapping(value = "/save")
@ResponseBody
public StreamContent save(@RequestBody StreamProxyParam param) {
log.info("添加代理: " + JSONObject.toJSONString(param));
if (ObjectUtils.isEmpty(param.getMediaServerId())) {
param.setMediaServerId("auto");
}
if (ObjectUtils.isEmpty(param.getType())) {
param.setType("default");
}
StreamInfo streamInfo = streamProxyService.save(param);
if (param.isEnable()) {
if (streamInfo == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg());
} else {
return new StreamContent(streamInfo);
}
} else {
return null;
}
}
/**
* 新增拉流代理
*
* @param param
* @return
*/
@PostMapping(value = "/add")
@ResponseBody
public AjaxResult add(@RequestBody StreamProxy param) {
log.info("添加代理: " + JSONObject.toJSONString(param));
if (ObjectUtils.isEmpty(param.getRelatesMediaServerId())) {
param.setRelatesMediaServerId(null);
}
if (ObjectUtils.isEmpty(param.getType())) {
param.setType("default");
}
if (ObjectUtils.isEmpty(param.getGbId())) {
param.setGbDeviceId(null);
}
streamProxyService.add(param);
return success(param);
}
/**
* 更新拉流代理
*
* @param param
* @return
*/
@PostMapping(value = "/update")
@ResponseBody
public AjaxResult update(@RequestBody StreamProxy param) {
log.info("更新代理: " + JSONObject.toJSONString(param));
if (param.getId() == 0) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "缺少代理信息的ID");
}
if (ObjectUtils.isEmpty(param.getRelatesMediaServerId())) {
param.setRelatesMediaServerId(null);
}
if (ObjectUtils.isEmpty(param.getGbId())) {
param.setGbDeviceId(null);
}
streamProxyService.update(param);
return success(param);
}
/**
* 获取ffmpeg.cmd模板
*
* @param mediaServerId 流媒体ID
* @return
*/
@GetMapping(value = "/ffmpeg_cmd/list")
@ResponseBody
public AjaxResult getFFmpegCMDs(@RequestParam String mediaServerId) {
log.debug("获取节点[ {} ]ffmpeg.cmd模板", mediaServerId);
MediaServer mediaServerItem = mediaServerService.getOne(mediaServerId);
if (mediaServerItem == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体: " + mediaServerId + "未找到");
}
return success(streamProxyService.getFFmpegCMDs(mediaServerItem));
}
@DeleteMapping(value = "/del")
@ResponseBody
@Parameter(name = "app", description = "应用名", required = true)
@Parameter(name = "stream", description = "流id", required = true)
public void del(@RequestParam String app, @RequestParam String stream) {
log.info("移除代理: " + app + "/" + stream);
if (app == null || stream == null) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), app == null ? "app不能为null" : "stream不能为null");
} else {
streamProxyService.delteByAppAndStream(app, stream);
}
}
/**
* 删除拉流代理
*
* @param id
*/
@DeleteMapping(value = "/delete/{id}")
@ResponseBody
public AjaxResult delte(@PathVariable int id) {
log.info("移除代理: {}", id);
streamProxyService.delete(id);
return success();
}
@GetMapping(value = "/start")
@ResponseBody
@Parameter(name = "id", description = "代理Id", required = true)
public StreamContent start(int id) {
log.info("播放代理: {}", id);
StreamInfo streamInfo = streamProxyPlayService.start(id, null, null);
if (streamInfo == null) {
throw new RuntimeException(ErrorCode.ERROR400.getMsg());
} else {
return new StreamContent(streamInfo);
}
}
/**
* 停止拉流代理
*
* @param id 代理Id
*/
@PostMapping(value = "/stop/{id}")
@ResponseBody
public AjaxResult stop(@PathVariable int id) {
log.info("停用代理: {}", id);
streamProxyPlayService.stop(id);
return success();
}
}

View File

@@ -1,270 +0,0 @@
package com.ruoyi.wvp.streamPush.controller;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.wvp.common.enums.ChannelDataType;
import com.ruoyi.wvp.conf.UserSetting;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.transmit.callback.DeferredResultHolder;
import com.ruoyi.wvp.gb28181.transmit.callback.RequestMessage;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.IMediaService;
import com.ruoyi.wvp.streamPush.bean.BatchRemoveParam;
import com.ruoyi.wvp.streamPush.bean.StreamPush;
import com.ruoyi.wvp.streamPush.bean.StreamPushExcelDto;
import com.ruoyi.wvp.streamPush.enent.StreamPushUploadFileHandler;
import com.ruoyi.wvp.streamPush.service.IStreamPushPlayService;
import com.ruoyi.wvp.streamPush.service.IStreamPushService;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.StreamContent;
import com.ruoyi.wvp.vmanager.bean.WVPResult;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@Tag(name = "推流信息管理")
@RestController
@Slf4j
@RequestMapping(value = "/api/push")
public class StreamPushController extends BaseController {
@Autowired
private IStreamPushService streamPushService;
@Autowired
private IStreamPushPlayService streamPushPlayService;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private DeferredResultHolder resultHolder;
@Autowired
private IMediaService mediaService;
@Autowired
private UserSetting userSetting;
/**
* 获取推流列表
*
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param query 查询内容
* @param pushing 是否正在推流
* @param mediaServerId 流媒体ID
* @return
*/
@GetMapping(value = "/list")
@ResponseBody
public TableDataInfo list(@RequestParam(required = false) Integer pageNum,
@RequestParam(required = false) Integer pageSize,
@RequestParam(required = false) String query,
@RequestParam(required = false) Boolean pushing,
@RequestParam(required = false) String mediaServerId) {
if (ObjectUtils.isEmpty(query)) {
query = null;
}
if (ObjectUtils.isEmpty(mediaServerId)) {
mediaServerId = null;
}
startPage();
List<StreamPush> list = streamPushService.getPushList(pageNum, pageSize, query, pushing, mediaServerId);
return getDataTable(list);
}
/**
* 删除推流
*
* @param id 应用名
*/
@PostMapping(value = "/remove/{id}")
@ResponseBody
public AjaxResult delete(@PathVariable int id) {
streamPushService.delete(id);
return success();
}
@PostMapping(value = "upload")
@ResponseBody
public DeferredResult<ResponseEntity<WVPResult<Object>>> uploadChannelFile(@RequestParam(value = "file") MultipartFile file) {
// 最多处理文件一个小时
DeferredResult<ResponseEntity<WVPResult<Object>>> result = new DeferredResult<>(60 * 60 * 1000L);
// 录像查询以channelId作为deviceId查询
String key = DeferredResultHolder.UPLOAD_FILE_CHANNEL;
String uuid = UUID.randomUUID().toString();
log.info("通道导入文件类型: {}", file.getContentType());
if (file.isEmpty()) {
log.warn("通道导入文件为空");
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("文件为空");
result.setResult(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(wvpResult));
return result;
}
if (file.getContentType() == null) {
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("无法识别文件类型");
result.setResult(ResponseEntity.status(HttpStatus.BAD_REQUEST).body(wvpResult));
return result;
}
// 同时只处理一个文件
if (resultHolder.exist(key, null)) {
log.warn("已有导入任务正在执行");
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("已有导入任务正在执行");
result.setResult(ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(wvpResult));
return result;
}
resultHolder.put(key, uuid, result);
result.onTimeout(() -> {
log.warn("通道导入超时,可能文件过大");
RequestMessage msg = new RequestMessage();
msg.setKey(key);
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("导入超时,可能文件过大");
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg);
});
//获取文件流
InputStream inputStream = null;
try {
String name = file.getName();
inputStream = file.getInputStream();
} catch (IOException e) {
log.error("未处理的异常 ", e);
}
try {
//传入参数
ExcelReader excelReader = EasyExcel.read(inputStream, StreamPushExcelDto.class,
new StreamPushUploadFileHandler(streamPushService, mediaServerService.getDefaultMediaServer().getId(), (errorStreams, errorGBs) -> {
log.info("通道导入成功存在重复App+Stream为{}个存在国标ID为{}个", errorStreams.size(), errorGBs.size());
RequestMessage msg = new RequestMessage();
msg.setKey(key);
WVPResult<Map<String, List<String>>> wvpResult = new WVPResult<>();
if (errorStreams.isEmpty() && errorGBs.isEmpty()) {
wvpResult.setCode(0);
wvpResult.setMsg("成功");
} else {
wvpResult.setCode(1);
wvpResult.setMsg("导入成功。但是存在重复数据");
Map<String, List<String>> errorData = new HashMap<>();
errorData.put("gbId", errorGBs);
errorData.put("stream", errorStreams);
wvpResult.setData(errorData);
}
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg);
})).build();
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
excelReader.finish();
} catch (Exception e) {
log.warn("通道导入失败:", e);
RequestMessage msg = new RequestMessage();
msg.setKey(key);
WVPResult<Object> wvpResult = new WVPResult<>();
wvpResult.setCode(-1);
wvpResult.setMsg("通道导入失败: " + e.getMessage());
msg.setData(wvpResult);
resultHolder.invokeAllResult(msg);
}
return result;
}
/**
* 添加推流信息
*
* @param stream 推流信息
* @return
*/
@PostMapping(value = "/add")
@ResponseBody
public AjaxResult add(@RequestBody StreamPush stream) {
if (ObjectUtils.isEmpty(stream.getGbId())) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "国标ID不可为空");
}
if (ObjectUtils.isEmpty(stream.getApp()) && ObjectUtils.isEmpty(stream.getStream())) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "app或stream不可为空");
}
stream.setGbStatus("OFF");
stream.setPushing(false);
if (!streamPushService.add(stream)) {
throw new ControllerException(ErrorCode.ERROR100);
}
stream.setDataType(ChannelDataType.STREAM_PUSH.value);
stream.setDataDeviceId(stream.getId());
return success(stream);
}
/**
* 更新推流信息
*
* @param stream
*/
@PostMapping(value = "/update")
@ResponseBody
public AjaxResult update(@RequestBody StreamPush stream) {
if (ObjectUtils.isEmpty(stream.getId())) {
throw new ControllerException(ErrorCode.ERROR400.getCode(), "ID不可为空");
}
if (!streamPushService.update(stream)) {
throw new ControllerException(ErrorCode.ERROR100);
}
return success();
}
@DeleteMapping(value = "/batchRemove")
@ResponseBody
public void batchStop(@RequestBody BatchRemoveParam ids) {
if (ids.getIds().isEmpty()) {
return;
}
streamPushService.batchRemove(ids.getIds());
}
@GetMapping(value = "/start")
@ResponseBody
public DeferredResult<WVPResult<StreamContent>> batchStop(Integer id) {
Assert.notNull(id, "推流ID不可为NULL");
DeferredResult<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
result.onTimeout(() -> {
WVPResult<StreamContent> fail = WVPResult.fail(ErrorCode.ERROR100.getCode(), "等待推流超时");
result.setResult(fail);
});
streamPushPlayService.start(id, (code, msg, streamInfo) -> {
if (code == 0 && streamInfo != null) {
WVPResult<StreamContent> success = WVPResult.success(new StreamContent(streamInfo));
result.setResult(success);
}
}, null, null);
return result;
}
}

View File

@@ -1,413 +0,0 @@
package com.ruoyi.wvp.vmanager.cloudRecord;
import com.alibaba.fastjson2.JSONArray;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.service.ICloudRecordService;
import com.ruoyi.wvp.media.bean.MediaServer;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.bean.CloudRecordItem;
import com.ruoyi.wvp.service.bean.DownloadFileInfo;
import com.ruoyi.wvp.utils.DateUtil;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.cloudRecord.bean.CloudRecordUrl;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@SuppressWarnings("rawtypes")
@Tag(name = "云端录像接口")
@Slf4j
@RestController
@RequestMapping("/api/cloud/record")
public class CloudRecordController extends BaseController {
@Autowired
private ICloudRecordService cloudRecordService;
@Autowired
private IMediaServerService mediaServerService;
@ResponseBody
@GetMapping("/date/list")
@Parameter(name = "app", description = "应用名", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@Parameter(name = "year", description = "年,置空则查询当年", required = false)
@Parameter(name = "month", description = "月,置空则查询当月", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID置空则查询全部", required = false)
public List<String> openRtpServer(@RequestParam(required = true) String app, @RequestParam(required = true) String stream, @RequestParam(required = false) Integer year, @RequestParam(required = false) Integer month, @RequestParam(required = false) String mediaServerId
) {
log.info("[云端录像] 查询存在云端录像的日期 app->{}, stream->{}, mediaServerId->{}, year->{}, month->{}", app, stream, mediaServerId, year, month);
Calendar calendar = Calendar.getInstance();
if (ObjectUtils.isEmpty(year)) {
year = calendar.get(Calendar.YEAR);
}
if (ObjectUtils.isEmpty(month)) {
month = calendar.get(Calendar.MONTH) + 1;
}
List<MediaServer> mediaServers;
if (!ObjectUtils.isEmpty(mediaServerId)) {
mediaServers = new ArrayList<>();
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
}
mediaServers.add(mediaServer);
} else {
mediaServers = mediaServerService.getAllOnlineList();
}
if (mediaServers.isEmpty()) {
return new ArrayList<>();
}
return cloudRecordService.getDateList(app, stream, year, month, mediaServers);
}
/**
* 查询云端录像
*
* @param query 检索内容
* @param app 应用名
* @param stream 流ID
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param startTime 开始时间(yyyy-MM-dd HH:mm:ss)
* @param endTime 结束时间(yyyy-MM-dd HH:mm:ss)
* @param mediaServerId 流媒体ID置空则查询全部流媒体
* @param callId 每次录像的唯一标识,置空则查询全部流媒体
* @return
*/
@ResponseBody
@GetMapping("/list")
public TableDataInfo openRtpServer(
@RequestParam(required = false) String query,
@RequestParam(required = false) String app,
@RequestParam(required = false) String stream,
@RequestParam int pageNum,
@RequestParam int pageSize,
@RequestParam(required = false) String startTime,
@RequestParam(required = false) String endTime,
@RequestParam(required = false) String mediaServerId,
@RequestParam(required = false) String callId
) {
log.info("[云端录像] 查询 app->{}, stream->{}, mediaServerId->{}, pageNum->{}, pageSize->{}, startTime->{}, endTime->{}, callId->{}",
app, stream, mediaServerId, pageNum, pageSize, startTime, endTime, callId);
List<MediaServer> mediaServers;
if (!ObjectUtils.isEmpty(mediaServerId)) {
mediaServers = new ArrayList<>();
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
}
mediaServers.add(mediaServer);
} else {
mediaServers = mediaServerService.getAllOnlineList();
}
if (mediaServers.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体");
}
if (query != null && ObjectUtils.isEmpty(query.trim())) {
query = null;
}
if (app != null && ObjectUtils.isEmpty(app.trim())) {
app = null;
}
if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
stream = null;
}
if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
startTime = null;
}
if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
endTime = null;
}
if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
callId = null;
}
startPage();
List<CloudRecordItem> list = cloudRecordService.getList(pageNum, pageSize, query, app, stream, startTime, endTime, mediaServers, callId);
return getDataTable(list);
}
@ResponseBody
@GetMapping("/task/add")
@Operation(summary = "添加合并任务")
@Parameter(name = "app", description = "应用名", required = false)
@Parameter(name = "stream", description = "流ID", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
@Parameter(name = "startTime", description = "鉴权ID", required = false)
@Parameter(name = "endTime", description = "鉴权ID", required = false)
@Parameter(name = "callId", description = "鉴权ID", required = false)
@Parameter(name = "remoteHost", description = "返回地址时的远程地址", required = false)
public String addTask(HttpServletRequest request, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String callId, @RequestParam(required = false) String remoteHost) {
MediaServer mediaServer;
if (mediaServerId == null) {
mediaServer = mediaServerService.getDefaultMediaServer();
} else {
mediaServer = mediaServerService.getOne(mediaServerId);
}
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体");
} else {
if (remoteHost == null) {
remoteHost = request.getScheme() + "://" + mediaServer.getIp() + ":" + mediaServer.getRecordAssistPort();
}
}
return cloudRecordService.addTask(app, stream, mediaServer, startTime, endTime, callId, remoteHost, mediaServerId != null);
}
@ResponseBody
@GetMapping("/task/list")
@Operation(summary = "查询合并任务")
@Parameter(name = "taskId", description = "任务Id", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
@Parameter(name = "isEnd", description = "是否结束", required = false)
public JSONArray queryTaskList(HttpServletRequest request, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam(required = false) String callId, @RequestParam(required = false) String taskId, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) Boolean isEnd) {
if (ObjectUtils.isEmpty(mediaServerId)) {
mediaServerId = null;
}
return cloudRecordService.queryTask(app, stream, callId, taskId, mediaServerId, isEnd, request.getScheme());
}
@ResponseBody
@GetMapping("/collect/add")
@Operation(summary = "添加收藏")
@Parameter(name = "app", description = "应用名", required = false)
@Parameter(name = "stream", description = "流ID", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
@Parameter(name = "startTime", description = "鉴权ID", required = false)
@Parameter(name = "endTime", description = "鉴权ID", required = false)
@Parameter(name = "callId", description = "鉴权ID", required = false)
@Parameter(name = "recordId", description = "录像记录的ID用于精准收藏一个视频文件", required = false)
public int addCollect(@RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String callId, @RequestParam(required = false) Integer recordId) {
log.info("[云端录像] 添加收藏app={}stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}", app, stream, mediaServerId, startTime, endTime, callId, recordId);
if (recordId != null) {
return cloudRecordService.changeCollectById(recordId, true);
} else {
return cloudRecordService.changeCollect(true, app, stream, mediaServerId, startTime, endTime, callId);
}
}
@ResponseBody
@GetMapping("/collect/delete")
@Operation(summary = "移除收藏")
@Parameter(name = "app", description = "应用名", required = false)
@Parameter(name = "stream", description = "流ID", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID", required = false)
@Parameter(name = "startTime", description = "鉴权ID", required = false)
@Parameter(name = "endTime", description = "鉴权ID", required = false)
@Parameter(name = "callId", description = "鉴权ID", required = false)
@Parameter(name = "recordId", description = "录像记录的ID用于精准精准移除一个视频文件的收藏", required = false)
public int deleteCollect(@RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String callId, @RequestParam(required = false) Integer recordId) {
log.info("[云端录像] 移除收藏app={}stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}", app, stream, mediaServerId, startTime, endTime, callId, recordId);
if (recordId != null) {
return cloudRecordService.changeCollectById(recordId, false);
} else {
return cloudRecordService.changeCollect(false, app, stream, mediaServerId, startTime, endTime, callId);
}
}
/**
* 获取播放地址
*
* @param recordId 录像记录的ID
* @return
*/
@ResponseBody
@GetMapping("/play/path")
public AjaxResult getPlayUrlPath(@RequestParam(required = true) Integer recordId) {
return success(cloudRecordService.getPlayUrlPath(recordId));
}
/************************* 以下这些接口只适合wvp和zlm部署在同一台服务器的情况且wvp只有一个zlm节点的情况 ***************************************/
/**
* 下载指定录像文件的压缩包
*
* @param query 检索内容
* @param app 应用名
* @param stream 流ID
* @param startTime 开始时间(yyyy-MM-dd HH:mm:ss)
* @param endTime 结束时间(yyyy-MM-dd HH:mm:ss)
* @param mediaServerId 流媒体ID置空则查询全部流媒体
* @param callId 每次录像的唯一标识,置空则查询全部流媒体
* @param ids 指定的Id
*/
@ResponseBody
@GetMapping("/zip")
public void downloadZipFile(HttpServletResponse response, @RequestParam(required = false) String query, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam(required = false) String startTime, @RequestParam(required = false) String endTime, @RequestParam(required = false) String mediaServerId, @RequestParam(required = false) String callId, @RequestParam(required = false) List<Integer> ids
) {
log.info("[下载指定录像文件的压缩包] 查询 app->{}, stream->{}, mediaServerId->{}, startTime->{}, endTime->{}, callId->{}", app, stream, mediaServerId, startTime, endTime, callId);
List<MediaServer> mediaServers;
if (!ObjectUtils.isEmpty(mediaServerId)) {
mediaServers = new ArrayList<>();
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
}
mediaServers.add(mediaServer);
} else {
mediaServers = mediaServerService.getAll();
}
if (mediaServers.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体");
}
if (query != null && ObjectUtils.isEmpty(query.trim())) {
query = null;
}
if (app != null && ObjectUtils.isEmpty(app.trim())) {
app = null;
}
if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
stream = null;
}
if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
startTime = null;
}
if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
endTime = null;
}
if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
callId = null;
}
if (stream != null && callId != null) {
response.addHeader("Content-Disposition", "attachment;filename=" + stream + "_" + callId + ".zip");
}
List<CloudRecordItem> cloudRecordItemList = cloudRecordService.getAllList(query, app, stream, startTime, endTime, mediaServers, callId, ids);
if (ObjectUtils.isEmpty(cloudRecordItemList)) {
return;
}
try {
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
zos.putNextEntry(new ZipEntry(DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime()) + ".mp4"));
File file = new File(cloudRecordItem.getFilePath());
if (!file.exists() || file.isDirectory()) {
continue;
}
FileInputStream fis = new FileInputStream(cloudRecordItem.getFilePath());
byte[] buf = new byte[2 * 1024];
int len;
while ((len = fis.read(buf)) != -1) {
zos.write(buf, 0, len);
}
zos.closeEntry();
fis.close();
}
zos.close();
} catch (IOException e) {
log.error("[下载指定录像文件的压缩包] 失败: 查询 app->{}, stream->{}, mediaServerId->{}, startTime->{}, endTime->{}, callId->{}", app, stream, mediaServerId, startTime, endTime, callId, e);
}
}
/**
* 查询云端录像列表
*
* @param query 检索内容
* @param app 应用名
* @param stream 流ID
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @param startTime 开始时间(yyyy-MM-dd HH:mm:ss)
* @param endTime 结束时间(yyyy-MM-dd HH:mm:ss)
* @param mediaServerId 流媒体ID置空则查询全部流媒体
* @param callId 每次录像的唯一标识,置空则查询全部流媒体
* @param remoteHost 拼接播放地址时使用的远程地址
*/
@ResponseBody
@GetMapping("/list-url")
public TableDataInfo getListWithUrl(
HttpServletRequest request,
@RequestParam(required = false) String query,
@RequestParam(required = false) String app,
@RequestParam(required = false) String stream,
@RequestParam int pageNum,
@RequestParam int pageSize,
@RequestParam(required = false) String startTime,
@RequestParam(required = false) String endTime,
@RequestParam(required = false) String mediaServerId,
@RequestParam(required = false) String callId,
@RequestParam(required = false) String remoteHost
) {
log.info("[云端录像] 查询URL app->{}, stream->{}, mediaServerId->{}, pageNum->{}, pageSize->{}, startTime->{}, endTime->{}, callId->{}",
app, stream, mediaServerId, pageNum, pageSize, startTime, endTime, callId);
List<MediaServer> mediaServers;
if (!ObjectUtils.isEmpty(mediaServerId)) {
mediaServers = new ArrayList<>();
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
}
mediaServers.add(mediaServer);
} else {
mediaServers = mediaServerService.getAll();
}
if (mediaServers.isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体");
}
if (query != null && ObjectUtils.isEmpty(query.trim())) {
query = null;
}
if (app != null && ObjectUtils.isEmpty(app.trim())) {
app = null;
}
if (stream != null && ObjectUtils.isEmpty(stream.trim())) {
stream = null;
}
if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) {
startTime = null;
}
if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) {
endTime = null;
}
if (callId != null && ObjectUtils.isEmpty(callId.trim())) {
callId = null;
}
MediaServer mediaServer = mediaServerService.getDefaultMediaServer();
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体节点");
}
if (remoteHost == null) {
remoteHost = request.getScheme() + "://" + request.getLocalAddr() + ":" + (request.getScheme().equals("https") ? mediaServer.getHttpSSlPort() : mediaServer.getHttpPort());
}
startPage();
List<CloudRecordItem> list = cloudRecordService.getList(pageNum, pageSize, query, app, stream, startTime, endTime, mediaServers, callId);
List<CloudRecordUrl> cloudRecordUrlList = new ArrayList<>(list.size());
if (!ObjectUtils.isEmpty(list)) {
for (CloudRecordItem cloudRecordItem : list) {
CloudRecordUrl cloudRecordUrl = new CloudRecordUrl();
cloudRecordUrl.setId(cloudRecordItem.getId());
cloudRecordUrl.setDownloadUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath() + "&save_name=" + cloudRecordItem.getStream() + "_" + cloudRecordItem.getCallId() + "_" + DateUtil.timestampMsToUrlToyyyy_MM_dd_HH_mm_ss(cloudRecordItem.getStartTime()));
cloudRecordUrl.setPlayUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath());
cloudRecordUrlList.add(cloudRecordUrl);
}
}
return getDataTable(cloudRecordUrlList);
}
}

View File

@@ -1,181 +0,0 @@
package com.ruoyi.wvp.vmanager.recordPlan;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.bean.CommonGBChannel;
import com.ruoyi.wvp.gb28181.service.IDeviceChannelService;
import com.ruoyi.wvp.service.IRecordPlanService;
import com.ruoyi.wvp.service.bean.RecordPlan;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.recordPlan.bean.RecordPlanParam;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@Tag(name = "录制计划")
@Slf4j
@RestController
@RequestMapping("/api/record/plan")
public class RecordPlanController extends BaseController {
@Autowired
private IRecordPlanService recordPlanService;
@Autowired
private IDeviceChannelService deviceChannelService;
/**
* 新增录制计划
*
* @param plan 计划
*/
@ResponseBody
@PostMapping("/add")
public AjaxResult add(@RequestBody RecordPlan plan) {
if (plan.getPlanItemList() == null || plan.getPlanItemList().isEmpty()) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "添加录制计划时,录制计划不可为空");
}
recordPlanService.add(plan);
return success();
}
/**
* 通道关联录制计划
*
* @param param
*/
@ResponseBody
@PostMapping("/link")
public AjaxResult link(@RequestBody RecordPlanParam param) {
if (param.getAllLink() != null) {
if (param.getAllLink()) {
recordPlanService.linkAll(param.getPlanId());
} else {
recordPlanService.cleanAll(param.getPlanId());
}
return success();
}
if (param.getChannelIds() == null && param.getDeviceDbIds() == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道ID和国标设备ID不可都为NULL");
}
List<Integer> channelIds = new ArrayList<>();
if (param.getChannelIds() != null) {
channelIds.addAll(param.getChannelIds());
} else {
List<Integer> chanelIdList = deviceChannelService.queryChaneIdListByDeviceDbIds(param.getDeviceDbIds());
if (chanelIdList != null && !chanelIdList.isEmpty()) {
channelIds = chanelIdList;
}
}
recordPlanService.link(channelIds, param.getPlanId());
return success();
}
/**
* 获取录制计划
*
* @param planId 计划ID
* @return
*/
@ResponseBody
@GetMapping("/get/{planId}")
public AjaxResult get(@PathVariable Integer planId) {
if (planId == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "计划ID不可为NULL");
}
return success(recordPlanService.get(planId));
}
/**
* 查询录制计划列表
*
* @param query 检索内容
* @param pageNum 当前页
* @param pageSize 每页查询数量
* @return
*/
@ResponseBody
@GetMapping("/query")
public TableDataInfo query(@RequestParam(required = false) String query, @RequestParam Integer pageNum, @RequestParam Integer pageSize) {
if (query != null && ObjectUtils.isEmpty(query.trim())) {
query = null;
}
startPage();
List<RecordPlan> list = recordPlanService.query(pageNum, pageSize, query);
return getDataTable(list);
}
/**
* 查询通道列表
*
* @param pageNum 当前页
* @param pageSize 每页条数
* @param planId 录制计划ID
* @param query 通道类型, 0国标设备1推流设备2拉流代理
* @param channelType 查询内容
* @param online 是否在线
* @param hasLink 是否已经关联
* @return
*/
@GetMapping("/channel/list")
@ResponseBody
public TableDataInfo queryChannelList(int pageNum, int pageSize,
@RequestParam(required = false) Integer planId,
@RequestParam(required = false) String query,
@RequestParam(required = false) Integer channelType,
@RequestParam(required = false) Boolean online,
@RequestParam(required = false) Boolean hasLink) {
Assert.notNull(planId, "录制计划ID不可为NULL");
if (org.springframework.util.ObjectUtils.isEmpty(query)) {
query = null;
}
startPage();
List<CommonGBChannel> list = recordPlanService.queryChannelList(pageNum, pageSize, query, channelType, online, planId, hasLink);
return getDataTable(list);
}
/**
* 更新录制计划
*
* @param plan 计划
*/
@ResponseBody
@PostMapping("/update")
public AjaxResult update(@RequestBody RecordPlan plan) {
if (plan == null || plan.getId() == 0) {
throw new ControllerException(ErrorCode.ERROR400);
}
recordPlanService.update(plan);
return success();
}
/**
* 删除录制计划
*
* @param planId 计划ID
*/
@ResponseBody
@DeleteMapping("/delete/{planId}")
public AjaxResult delete(@PathVariable Integer planId) {
if (planId == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "计划IDID不可为NULL");
}
recordPlanService.delete(planId);
return success();
}
}

View File

@@ -1,376 +0,0 @@
package com.ruoyi.wvp.vmanager.server;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.wvp.common.SystemAllInfo;
import com.ruoyi.wvp.common.VersionPo;
import com.ruoyi.wvp.common.enums.ChannelDataType;
import com.ruoyi.wvp.conf.SipConfig;
import com.ruoyi.wvp.conf.UserSetting;
import com.ruoyi.wvp.conf.VersionInfo;
import com.ruoyi.wvp.conf.exception.ControllerException;
import com.ruoyi.wvp.gb28181.service.IDeviceChannelService;
import com.ruoyi.wvp.gb28181.service.IDeviceService;
import com.ruoyi.wvp.media.bean.MediaInfo;
import com.ruoyi.wvp.media.bean.MediaServer;
import com.ruoyi.wvp.media.event.mediaServer.MediaServerChangeEvent;
import com.ruoyi.wvp.media.service.IMediaServerService;
import com.ruoyi.wvp.service.bean.MediaServerLoad;
import com.ruoyi.wvp.storager.IRedisCatchStorage;
import com.ruoyi.wvp.streamProxy.service.IStreamProxyService;
import com.ruoyi.wvp.streamPush.service.IStreamPushService;
import com.ruoyi.wvp.vmanager.bean.ErrorCode;
import com.ruoyi.wvp.vmanager.bean.ResourceBaseInfo;
import com.ruoyi.wvp.vmanager.bean.ResourceInfo;
import com.ruoyi.wvp.vmanager.bean.SystemConfigInfo;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.GlobalMemory;
import oshi.hardware.HardwareAbstractionLayer;
import oshi.hardware.NetworkIF;
import oshi.software.os.OperatingSystem;
import java.io.File;
import java.text.DecimalFormat;
import java.util.*;
@SuppressWarnings("rawtypes")
@Tag(name = "服务控制")
@RestController
@RequestMapping("/api/server")
public class WvpServerController extends BaseController {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private VersionInfo versionInfo;
@Autowired
private SipConfig sipConfig;
@Autowired
private UserSetting userSetting;
@Autowired
private IDeviceService deviceService;
@Autowired
private IDeviceChannelService channelService;
@Autowired
private IStreamPushService pushService;
@Autowired
private IStreamProxyService proxyService;
@Value("${server.port}")
private int serverPort;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
/**
* 获取流媒体服务列表
*
* @return
*/
@GetMapping(value = "/media_server/list")
@ResponseBody
public AjaxResult getMediaServerList() {
return success(mediaServerService.getAll());
}
/**
* 获取流媒体服务列表
*
* @return
*/
@GetMapping(value = "/media_server/online/list")
@ResponseBody
public AjaxResult getOnlineMediaServerList() {
return success(mediaServerService.getAllOnline());
}
@GetMapping(value = "/media_server/one/{id}")
@ResponseBody
@Parameter(name = "id", description = "流媒体服务ID", required = true)
public MediaServer getMediaServer(@PathVariable String id) {
return mediaServerService.getOne(id);
}
@Parameter(name = "ip", description = "流媒体服务IP", required = true)
@Parameter(name = "port", description = "流媒体服务HTT端口", required = true)
@Parameter(name = "secret", description = "流媒体服务secret", required = true)
@GetMapping(value = "/media_server/check")
@ResponseBody
public MediaServer checkMediaServer(@RequestParam String ip, @RequestParam int port, @RequestParam String secret, @RequestParam String type) {
return mediaServerService.checkMediaServer(ip, port, secret, type);
}
@Parameter(name = "ip", description = "流媒体服务IP", required = true)
@Parameter(name = "port", description = "流媒体服务HTT端口", required = true)
@GetMapping(value = "/media_server/record/check")
@ResponseBody
public void checkMediaRecordServer(@RequestParam String ip, @RequestParam int port) {
boolean checkResult = mediaServerService.checkMediaRecordServer(ip, port);
if (!checkResult) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接失败");
}
}
@Parameter(name = "mediaServerItem", description = "流媒体信息", required = true)
@PostMapping(value = "/media_server/save")
@ResponseBody
public void saveMediaServer(@RequestBody MediaServer mediaServer) {
MediaServer mediaServerItemInDatabase = mediaServerService.getOneFromDatabase(mediaServer.getId());
if (mediaServerItemInDatabase != null) {
mediaServerService.update(mediaServer);
} else {
mediaServerService.add(mediaServer);
// 发送事件
MediaServerChangeEvent event = new MediaServerChangeEvent(this);
event.setMediaServerItemList(mediaServer);
applicationEventPublisher.publishEvent(event);
}
}
@Parameter(name = "id", description = "流媒体ID", required = true)
@DeleteMapping(value = "/media_server/delete")
@ResponseBody
public void deleteMediaServer(@RequestParam String id) {
MediaServer mediaServer = mediaServerService.getOne(id);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体不存在");
}
mediaServerService.delete(mediaServer);
}
@Parameter(name = "app", description = "应用名", required = true)
@Parameter(name = "stream", description = "流ID", required = true)
@Parameter(name = "mediaServerId", description = "流媒体ID", required = true)
@GetMapping(value = "/media_server/media_info")
@ResponseBody
public MediaInfo getMediaInfo(String app, String stream, String mediaServerId) {
MediaServer mediaServer = mediaServerService.getOne(mediaServerId);
if (mediaServer == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "流媒体不存在");
}
return mediaServerService.getMediaInfo(mediaServer, app, stream);
}
@GetMapping(value = "/restart")
@ResponseBody
public void restart() {
// taskExecutor.execute(()-> {
// try {
// Thread.sleep(3000);
// SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
// SipStackImpl stack = (SipStackImpl) up.getSipStack();
// stack.stop();
// Iterator listener = stack.getListeningPoints();
// while (listener.hasNext()) {
// stack.deleteListeningPoint((ListeningPoint) listener.next());
// }
// Iterator providers = stack.getSipProviders();
// while (providers.hasNext()) {
// stack.deleteSipProvider((SipProvider) providers.next());
// }
// VManageBootstrap.restart();
// } catch (InterruptedException | ObjectInUseException e) {
// throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
// }
// });
}
/**
* 获取平台配置信息
*
* @return
*/
@GetMapping(value = "/system/configInfo")
@ResponseBody
public AjaxResult getConfigInfo() {
SystemConfigInfo systemConfigInfo = new SystemConfigInfo();
systemConfigInfo.setVersion(versionInfo.getVersion());
systemConfigInfo.setSip(sipConfig);
systemConfigInfo.setAddOn(userSetting);
systemConfigInfo.setServerPort(serverPort);
return success(systemConfigInfo);
}
@GetMapping(value = "/version")
@ResponseBody
public VersionPo VersionPogetVersion() {
return versionInfo.getVersion();
}
@GetMapping(value = "/config")
@Parameter(name = "type", description = "配置类型sip, base", required = true)
@ResponseBody
public JSONObject getVersion(String type) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("server.port", serverPort);
if (ObjectUtils.isEmpty(type)) {
jsonObject.put("sip", JSON.toJSON(sipConfig));
jsonObject.put("base", JSON.toJSON(userSetting));
} else {
switch (type) {
case "sip":
jsonObject.put("sip", sipConfig);
break;
case "base":
jsonObject.put("base", userSetting);
break;
default:
break;
}
}
return jsonObject;
}
@GetMapping(value = "/system/info")
@ResponseBody
public SystemAllInfo getSystemInfo() {
SystemAllInfo systemAllInfo = redisCatchStorage.getSystemInfo();
return systemAllInfo;
}
@GetMapping(value = "/media_server/load")
@ResponseBody
public List<MediaServerLoad> getMediaLoad() {
List<MediaServerLoad> result = new ArrayList<>();
List<MediaServer> allOnline = mediaServerService.getAllOnline();
if (allOnline.isEmpty()) {
return result;
} else {
for (MediaServer mediaServerItem : allOnline) {
result.add(mediaServerService.getLoad(mediaServerItem));
}
}
return result;
}
@GetMapping(value = "/resource/info")
@ResponseBody
public ResourceInfo getResourceInfo() {
ResourceInfo result = new ResourceInfo();
ResourceBaseInfo deviceInfo = deviceService.getOverview();
result.setDevice(deviceInfo);
ResourceBaseInfo channelInfo = channelService.getOverview();
result.setChannel(channelInfo);
ResourceBaseInfo pushInfo = pushService.getOverview();
result.setPush(pushInfo);
ResourceBaseInfo proxyInfo = proxyService.getOverview();
result.setProxy(proxyInfo);
return result;
}
@GetMapping(value = "/info")
@ResponseBody
public Map<String, Map<String, String>> getInfo() {
Map<String, Map<String, String>> result = new LinkedHashMap<>();
Map<String, String> hardwareMap = new LinkedHashMap<>();
result.put("硬件信息", hardwareMap);
SystemInfo systemInfo = new SystemInfo();
HardwareAbstractionLayer hardware = systemInfo.getHardware();
// 获取CPU信息
CentralProcessor.ProcessorIdentifier processorIdentifier = hardware.getProcessor().getProcessorIdentifier();
hardwareMap.put("CPU", processorIdentifier.getName());
// 获取内存
GlobalMemory memory = hardware.getMemory();
hardwareMap.put("内存", formatByte(memory.getTotal() - memory.getAvailable()) + "/" + formatByte(memory.getTotal()));
hardwareMap.put("制造商", systemInfo.getHardware().getComputerSystem().getManufacturer());
hardwareMap.put("产品名称", systemInfo.getHardware().getComputerSystem().getModel());
// 网卡
List<NetworkIF> networkIFs = hardware.getNetworkIFs();
StringBuilder ips = new StringBuilder();
for (int i = 0; i < networkIFs.size(); i++) {
NetworkIF networkIF = networkIFs.get(i);
String ipsStr = StringUtils.join(networkIF.getIPv4addr());
if (ObjectUtils.isEmpty(ipsStr)) {
continue;
}
ips.append(ipsStr);
if (i < networkIFs.size() - 1) {
ips.append(",");
}
}
hardwareMap.put("网卡", ips.toString());
Map<String, String> operatingSystemMap = new LinkedHashMap<>();
result.put("操作系统", operatingSystemMap);
OperatingSystem operatingSystem = systemInfo.getOperatingSystem();
operatingSystemMap.put("名称", operatingSystem.getFamily() + " " + operatingSystem.getVersionInfo().getVersion());
operatingSystemMap.put("类型", operatingSystem.getManufacturer());
Map<String, String> platformMap = new LinkedHashMap<>();
result.put("平台信息", platformMap);
VersionPo version = versionInfo.getVersion();
platformMap.put("版本", version.getVersion());
platformMap.put("构建日期", version.getBUILD_DATE());
platformMap.put("GIT分支", version.getGIT_BRANCH());
platformMap.put("GIT地址", version.getGIT_URL());
platformMap.put("GIT日期", version.getGIT_DATE());
platformMap.put("GIT版本", version.getGIT_Revision_SHORT());
platformMap.put("DOCKER环境", new File("/.dockerenv").exists() ? "" : "");
return result;
}
@GetMapping(value = "/channel/datatype")
@ResponseBody
public List<Map<String, Object>> getDataType() {
List<Map<String, Object>> result = new LinkedList<>();
for (ChannelDataType item : ChannelDataType.values()) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("key", item.desc);
map.put("value", item.value);
result.add(map);
}
return result;
}
/**
* 单位转换
*/
private static String formatByte(long byteNumber) {
//换算单位
double FORMAT = 1024.0;
double kbNumber = byteNumber / FORMAT;
if (kbNumber < FORMAT) {
return new DecimalFormat("#.##KB").format(kbNumber);
}
double mbNumber = kbNumber / FORMAT;
if (mbNumber < FORMAT) {
return new DecimalFormat("#.##MB").format(mbNumber);
}
double gbNumber = mbNumber / FORMAT;
if (gbNumber < FORMAT) {
return new DecimalFormat("#.##GB").format(gbNumber);
}
double tbNumber = gbNumber / FORMAT;
return new DecimalFormat("#.##TB").format(tbNumber);
}
}

View File

@@ -18,10 +18,10 @@
AND stream = #{stream}
</if>
<if test="endTimeStamp != null">
AND end_time >= #{endTimeStamp}
AND end_time &lt;= #{endTimeStamp}
</if>
<if test="startTimeStamp != null">
AND start_time &lt;= #{startTimeStamp}
AND start_time &gt;= #{startTimeStamp}
</if>
<if test="callId != null">
AND call_id = #{callId}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 23 KiB