Merge remote-tracking branch 'origin/master'
Some checks are pending
Gitea Actions Demo / Explore-Gitea-Actions (push) Waiting to run

This commit is contained in:
2025-07-22 11:40:20 +08:00
40 changed files with 711 additions and 154 deletions

View File

@@ -3,6 +3,7 @@ package org.dromara.sis.controller.zkmedia;
import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.sis.domain.enums.FactoryNoEnum;
import org.dromara.sis.sdk.zkmedia.MediaServerUtils;
import org.dromara.sis.sdk.zkmedia.ZLMediaKitService;
import org.dromara.sis.sdk.zkmedia.model.AddStreamProxy;
@@ -49,9 +50,9 @@ public class ZKLmediaController {
proxy.setApp("realtime");
String s = IdUtil.fastSimpleUUID();
proxy.setStream(s);
if ("DS1010".equals(data.getFactoryNo())) {
if (FactoryNoEnum.HIK.getCode().equals(data.getFactoryNo())) {
proxy.setUrl(String.format(HIK_REALTIME_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId()));
} else if ("DS1014".equals(data.getFactoryNo())) {
} else if (FactoryNoEnum.DAHUA.getCode().equals(data.getFactoryNo())) {
proxy.setUrl(String.format(DAHUA_REALTIME_RTSP_TEMPLATE, data.getAccount(), data.getPwd(), data.getVideoIp(), data.getVideoPort(), data.getChannelId()));
} else {
throw new RuntimeException("未知的设备类型!");

View File

@@ -0,0 +1,80 @@
package org.dromara.sis.controller.zkmedia;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.dromara.sis.sdk.zkmedia.MediaServerUtils;
import org.dromara.sis.sdk.zkmedia.model.*;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/index/hook")
public class ZkMediaHookController {
/**
* 服务器定时上报时间上报间隔可配置默认10s上报一次
*/
@ResponseBody
@PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
log.debug("ZLM心跳上报,params: {}", param);
return HookResult.SUCCESS();
}
/**
* rtsp/rtmp/rtp 推流鉴权事件。
*/
@ResponseBody
@PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
public HookResult onPublish(@RequestBody OnPushParam param) {
log.info("rtsp/rtmp/rtp 推流鉴权,params: {}", param);
return HookResult.SUCCESS();
}
/**
* 播放器鉴权事件rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。
*/
@ResponseBody
@PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
public HookResult onPlay(@RequestBody OnPlayHookParam param) {
Map<String, String> paramMap = MediaServerUtils.urlParamToMap(param.getParams());
// 对于播放流进行鉴权
log.info("播放器鉴权事件,params={}", JSONObject.toJSONString(param));
return HookResult.SUCCESS();
}
/**
* rtsp/rtmp流注册或注销时触发此事件此事件对回复不敏感。
*/
@ResponseBody
@PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {
log.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
return HookResult.SUCCESS();
}
/**
* 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。
*/
@ResponseBody
@PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
public HookResult onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {
log.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
// TODO 关闭无人观看的流
return HookResult.SUCCESS().setClose(true);
}
/**
* 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。
*/
@ResponseBody
@PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
public HookResult onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
log.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
return HookResult.SUCCESS();
}
}

View File

@@ -9,7 +9,8 @@ import lombok.Getter;
@Getter
public enum FactoryNoEnum {
HIK("DS1013");
HIK("DS1013"),
DAHUA("DS1014");
private final String code;

View File

@@ -116,6 +116,7 @@ public class HikApiService {
}
boolean logout = LoginService.logout(lHandel);
if (logout) {
log.info("设备[{}]注销完成", deviceIp);
CACHE.remove(deviceIp);
}
return logout;

View File

@@ -7,4 +7,6 @@ public class HikSdkConstans {
*/
public static final String DEFAULT_CHANNEL = "101";
public static final Integer DEFAULT_RTSP_PORT = 554;
}

View File

@@ -14,8 +14,13 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ZLMediaKit流媒体服务
*
* @author lxj
*/
@Slf4j
@Service("com.parkclouds.media.service.ZLMediaKitServiceImpl")
@Service
public class ZLMediaKitServiceImpl implements ZLMediaKitService {
@Resource
@@ -141,7 +146,7 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService {
commonParams.put("force", 1);
R<AddStreamProxyResp> result = HttpClientUtil.get(getRequestUrl("close_streams"), commonParams, AddStreamProxyResp.class);
if (result != null) {
String s =null;
String s = null;
if (result.getCode() == 0) {
s = "关闭流成功";
}
@@ -149,7 +154,7 @@ public class ZLMediaKitServiceImpl implements ZLMediaKitService {
if (result.getCode() == -1) {
s = "关闭流失败";
}
log.info("{},关闭流数量:{}",s,result.getData());
log.info("{},关闭流数量:{}", s, result.getData());
return s;
}
return null;

View File

@@ -11,7 +11,6 @@ public class AddStreamProxy {
@NotBlank
private String videoIp;
@NotNull
private Integer videoPort;
@NotBlank
@@ -31,6 +30,6 @@ public class AddStreamProxy {
private String endTime;
private String stream;
private String stream;
}

View File

@@ -87,5 +87,11 @@ public interface ISisDeviceChannelService {
Boolean handleHikDeviceChannel(SisDeviceManageBo bo);
/**
* 通过设备ids 删除设备通道信息
* @param deviceIds 设备ids
* @return 返回删除数量
*/
Integer deleteByDeviceIds(List<Long> deviceIds);
}

View File

@@ -208,7 +208,7 @@ public class SisDeviceChannelServiceImpl implements ISisDeviceChannelService {
channel.setChannelName(bo.getDeviceName());
channel.setGroupId(bo.getGroupId());
channel.setDeviceIp(bo.getDeviceIp());
channel.setDevicePort(bo.getDevicePort());
channel.setDevicePort(HikSdkConstans.DEFAULT_RTSP_PORT);
channel.setFactoryNo(bo.getFactoryNo());
channel.setDeviceAccount(bo.getDeviceAccount());
channel.setDevicePwd(bo.getDevicePwd());
@@ -223,4 +223,11 @@ public class SisDeviceChannelServiceImpl implements ISisDeviceChannelService {
}
return false;
}
@Override
public Integer deleteByDeviceIds(List<Long> deviceIds) {
LambdaQueryWrapper<SisDeviceChannel> lqw = new LambdaQueryWrapper<>();
lqw.in(SisDeviceChannel::getDeviceId, deviceIds);
return baseMapper.delete(lqw);
}
}

View File

@@ -1,5 +1,6 @@
package org.dromara.sis.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -7,6 +8,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.TreeNode;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -15,15 +17,14 @@ import org.dromara.sis.domain.bo.SisDeviceManageBo;
import org.dromara.sis.domain.enums.FactoryNoEnum;
import org.dromara.sis.domain.vo.SisDeviceManageVo;
import org.dromara.sis.mapper.SisDeviceManageMapper;
import org.dromara.sis.sdk.hik.HikApiService;
import org.dromara.sis.service.ISisDeviceChannelService;
import org.dromara.sis.service.ISisDeviceManageService;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;
/**
@@ -38,7 +39,7 @@ import java.util.Objects;
public class SisDeviceManageServiceImpl implements ISisDeviceManageService {
private final SisDeviceManageMapper baseMapper;
private final ISisDeviceChannelService hikDeviceChannelService;
private final ISisDeviceChannelService deviceChannelService;
/**
* 查询设备管理
@@ -60,7 +61,7 @@ public class SisDeviceManageServiceImpl implements ISisDeviceManageService {
*/
@Override
public TableDataInfo<SisDeviceManageVo> queryPageList(SisDeviceManageBo bo, PageQuery pageQuery) {
Page<SisDeviceManageVo> result =baseMapper.selectByPage(pageQuery.build(), bo);
Page<SisDeviceManageVo> result = baseMapper.selectByPage(pageQuery.build(), bo);
return TableDataInfo.build(result);
}
@@ -110,7 +111,7 @@ public class SisDeviceManageServiceImpl implements ISisDeviceManageService {
public void handleDeviceChannelInfo(SisDeviceManageBo bo) {
if (Objects.equals(bo.getFactoryNo(), FactoryNoEnum.HIK.getCode())) {
hikDeviceChannelService.handleHikDeviceChannel(bo);
deviceChannelService.handleHikDeviceChannel(bo);
}
}
@@ -142,14 +143,49 @@ public class SisDeviceManageServiceImpl implements ISisDeviceManageService {
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Transactional(rollbackFor = Exception.class)
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
// 查询需要删除的设备
List<SisDeviceManage> sisDeviceManages = baseMapper.selectByIds(ids);
if (CollUtil.isEmpty(sisDeviceManages)) {
return true;
}
return baseMapper.deleteByIds(ids) > 0;
int i = baseMapper.deleteByIds(ids);
boolean flag = i > 0;
if (flag) {
SisDeviceManageServiceImpl aopProxy = SpringUtils.getAopProxy(this);
aopProxy.deleteDeviceRef(sisDeviceManages);
}
return flag;
}
/**
* 异步删除设备的关联关系
*/
@Async
public void deleteDeviceRef(List<SisDeviceManage> sisDeviceManages) {
List<Long> deviceIds = new ArrayList<>(sisDeviceManages.size());
Map<String, List<SisDeviceManage>> factoryGroup = new HashMap<>(10);
sisDeviceManages.forEach(sisDeviceManage -> {
deviceIds.add(sisDeviceManage.getId());
factoryGroup.computeIfAbsent(sisDeviceManage.getFactoryNo(), k -> new ArrayList<>()).add(sisDeviceManage);
});
// 删除设备通道
int num = deviceChannelService.deleteByDeviceIds(deviceIds);
log.info("删除设备通道完成,num={}", num);
// 设备sdk注销
for (Map.Entry<String, List<SisDeviceManage>> entry : factoryGroup.entrySet()) {
if (entry.getKey().equals(FactoryNoEnum.HIK.getCode())) {
entry.getValue().forEach(item -> {
HikApiService.getInstance().loginOut(item.getDeviceIp());
});
}
}
}
@Override
public SisDeviceManageVo queryVoByDeviceIp(Integer deviceCode) {
LambdaQueryWrapper<SisDeviceManage> lqw = Wrappers.lambdaQuery();

View File

@@ -32,3 +32,5 @@ spring:
- optional:nacos:application-common.yml
- optional:nacos:datasource.yml
- optional:nacos:${spring.application.name}.yml