v1.1.0
@@ -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
@@ -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>
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -1,61 +1,191 @@
|
||||
# 数据源配置
|
||||
# 项目相关配置
|
||||
ruoyi:
|
||||
# 名称
|
||||
name: RuoYi-Wvp
|
||||
# 版本
|
||||
version: 3.8.9
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /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
|
||||
|
||||
@@ -1,24 +1,11 @@
|
||||
Application Version: ${ruoyi.version}
|
||||
Spring Boot Version: ${spring-boot.version}
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// _ooOoo_ //
|
||||
// o8888888o //
|
||||
// 88" . "88 //
|
||||
// (| ^_^ |) //
|
||||
// O\ = /O //
|
||||
// ____/`---'\____ //
|
||||
// .' \\| |// `. //
|
||||
// / \\||| : |||// \ //
|
||||
// / _||||| -:- |||||- \ //
|
||||
// | | \\\ - /// | | //
|
||||
// | \_| ''\---/'' | | //
|
||||
// \ .-\__ `-` ___/-. / //
|
||||
// ___`. .' /--.--\ `. . ___ //
|
||||
// ."" '< `.___\_<|>_/___.' >'"". //
|
||||
// | | : `- \`.;`\ _ /`;.`/ - ` : | | //
|
||||
// \ \ `-. \_ __\ /__ _/ .-` / / //
|
||||
// ========`-.____`-.___\_____/___.-`____.-'======== //
|
||||
// `=---=' //
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ //
|
||||
// 佛祖保佑 永不宕机 永无BUG //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
_
|
||||
(_)
|
||||
_ __ _ _ ___ _ _ _ ________ ____ ___ __
|
||||
| '__| | | |/ _ \| | | | |______\ \ /\ / /\ \ / / '_ \
|
||||
| | | |_| | (_) | |_| | | \ V V / \ V /| |_) |
|
||||
|_| \__,_|\___/ \__, |_| \_/\_/ \_/ | .__/
|
||||
__/ | | |
|
||||
|___/ |_|
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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>
|
||||
@@ -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
@@ -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>
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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()) {
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 17:11");
|
||||
result.put("StartUpTime","2020-09-02 17:11");
|
||||
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 17:11");
|
||||
// result.put("StartUpTime","2020-09-02 17:11");
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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, "分组id(deviceId)不需要存在");
|
||||
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();
|
||||
// }
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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: {}",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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()));
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,10 @@
|
||||
AND stream = #{stream}
|
||||
</if>
|
||||
<if test="endTimeStamp != null">
|
||||
AND end_time >= #{endTimeStamp}
|
||||
AND end_time <= #{endTimeStamp}
|
||||
</if>
|
||||
<if test="startTimeStamp != null">
|
||||
AND start_time <= #{startTimeStamp}
|
||||
AND start_time >= #{startTimeStamp}
|
||||
</if>
|
||||
<if test="callId != null">
|
||||
AND call_id = #{callId}
|
||||
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 130 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 23 KiB |