临时提交

This commit is contained in:
lin
2025-10-22 18:19:48 +08:00
parent 24c7bfb756
commit aae673e47e
14 changed files with 367 additions and 69 deletions

View File

@@ -658,7 +658,7 @@ public interface CommonGBChannelMapper {
void saveLevel(List<ChannelForThin> channels);
@SelectProvider(type = ChannelProvider.class, method = "queryCameraChannelByIds")
List<CameraChannel> queryCameraChannelByIds(List<Integer> ids);
List<CameraChannel> queryCameraChannelByIds(List<CommonGBChannel> channelList);
}

View File

@@ -833,13 +833,13 @@ public class ChannelProvider {
sqlBuild.append(BASE_SQL_FOR_CAMERA_DEVICE);
sqlBuild.append(" where wdc.id in ( ");
List<Integer> ids = (List<Integer>)params.get("ids");
List<CommonGBChannel> channelList = (List<CommonGBChannel>)params.get("channelList");
boolean first = true;
for (Integer id : ids) {
for (CommonGBChannel channel : channelList) {
if (!first) {
sqlBuild.append(",");
}
sqlBuild.append(id);
sqlBuild.append(channel.getGbId());
first = false;
}
sqlBuild.append(" )");

View File

@@ -74,7 +74,6 @@ public class EventPublisher {
applicationEventPublisher.publishEvent(channelEvent);
}
public void catalogEventPublish(Platform platform, CommonGBChannel deviceChannel, String type) {
catalogEventPublish(platform, Collections.singletonList(deviceChannel), type);
}

View File

@@ -32,7 +32,7 @@ public class ChannelEvent extends ApplicationEvent {
public enum ChannelEventMessageType {
ADD, UPDATE, DELETE, ONLINE, OFFLINE, VLOST, DEFECT
ADD, UPDATE, DEL, ON, OFF, VLOST, DEFECT
}
public static ChannelEvent getInstance(Object source, ChannelEventMessageType messageType, List<CommonGBChannel> channelList) {

View File

@@ -78,7 +78,7 @@ public interface IDeviceChannelService {
void changeAudio(Integer channelId, Boolean audio);
void updateChannelStatus(DeviceChannel channel);
void updateChannelStatusForNotify(DeviceChannel channel);
void addChannel(DeviceChannel channel);

View File

@@ -613,7 +613,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
}
@Override
public void updateChannelStatus(DeviceChannel channel) {
public void updateChannelStatusForNotify(DeviceChannel channel) {
channelMapper.updateStatus(channel);
}

View File

@@ -98,7 +98,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
commonGBChannelMapper.delete(gbId);
try {
// 发送通知
eventPublisher.channelEventPublish(channel, ChannelEvent.ChannelEventMessageType.DELETE);
eventPublisher.channelEventPublish(channel, ChannelEvent.ChannelEventMessageType.DEL);
} catch (Exception e) {
log.warn("[通道移除通知] 发送失败,{}", channel.getGbDeviceId(), e);
}
@@ -150,21 +150,6 @@ public class GbChannelServiceImpl implements IGbChannelService {
} catch (Exception e) {
log.warn("[更新通道通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
}
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setLongitude(commonGBChannel.getGbLongitude());
mobilePosition.setLatitude(commonGBChannel.getGbLatitude());
mobilePosition.setCreateTime(DateUtil.getNow());
mobilePosition.setDeviceId(commonGBChannel.getGbDeviceId());
mobilePosition.setTime(DateUtil.getNow());
mobilePosition.setAltitude(0.0);
mobilePosition.setDirection(0.0);
mobilePosition.setSpeed(0.0);
mobilePosition.setChannelId(commonGBChannel.getGbId());
try {
eventPublisher.mobilePositionEventPublish(mobilePosition);
}catch (Exception e) {
log.error("[向上级转发移动位置失败] ", e);
}
}
return result;
}
@@ -179,7 +164,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
if (result > 0) {
try {
// 发送通知
eventPublisher.channelEventPublish(commonGBChannel, ChannelEvent.ChannelEventMessageType.OFFLINE);
eventPublisher.channelEventPublish(commonGBChannel, ChannelEvent.ChannelEventMessageType.OFF);
} catch (Exception e) {
log.warn("[通道离线通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
}
@@ -211,7 +196,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
if (result > 0) {
try {
// 发送catalog
eventPublisher.channelEventPublish(commonGBChannelList, ChannelEvent.ChannelEventMessageType.OFFLINE);
eventPublisher.channelEventPublish(commonGBChannelList, ChannelEvent.ChannelEventMessageType.OFF);
} catch (Exception e) {
log.warn("[多个通道离线] 发送失败,数量:{}", commonGBChannelList.size(), e);
}
@@ -229,7 +214,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
if (result > 0) {
try {
// 发送通知
eventPublisher.channelEventPublish(commonGBChannel, ChannelEvent.ChannelEventMessageType.ONLINE);
eventPublisher.channelEventPublish(commonGBChannel, ChannelEvent.ChannelEventMessageType.ON);
} catch (Exception e) {
log.warn("[通道上线通知] 发送失败,{}", commonGBChannel.getGbDeviceId(), e);
}
@@ -260,7 +245,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
}
try {
// 发送catalog
eventPublisher.channelEventPublish(commonGBChannelList, ChannelEvent.ChannelEventMessageType.ONLINE);
eventPublisher.channelEventPublish(commonGBChannelList, ChannelEvent.ChannelEventMessageType.ON);
} catch (Exception e) {
log.warn("[多个通道上线] 发送失败,数量:{}", commonGBChannelList.size(), e);
}
@@ -417,7 +402,7 @@ public class GbChannelServiceImpl implements IGbChannelService {
// 发送通过更新通知
try {
// 发送通知
eventPublisher.catalogEventPublish(null, channelNew, CatalogEvent.UPDATE);
eventPublisher.channelEventPublishForUpdate(channelNew, channel);
} catch (Exception e) {
log.warn("[通道移除通知] 发送失败,{}", channelNew.getGbDeviceId(), e);
}

View File

@@ -148,7 +148,7 @@ public class GroupServiceImpl implements IGroupService, CommandLineRunner {
CommonGBChannel channel = CommonGBChannel.build(chjildGroup);
try {
// 发送catalog
eventPublisher.catalogEventPublish(null, channel, CatalogEvent.UPDATE);
eventPublisher.channelEventPublishForUpdate(channel, null);
}catch (Exception e) {
log.warn("[业务分组/虚拟组织变化] 发送失败,{}", group.getDeviceId(), e);
}
@@ -160,7 +160,7 @@ public class GroupServiceImpl implements IGroupService, CommandLineRunner {
CommonGBChannel channel = CommonGBChannel.build(group);
try {
// 发送catalog
eventPublisher.catalogEventPublish(null, channel, CatalogEvent.UPDATE);
eventPublisher.channelEventPublishForUpdate(channel, null);
}catch (Exception e) {
log.warn("[业务分组/虚拟组织变化] 发送失败,{}", group.getDeviceId(), e);
}

View File

@@ -8,7 +8,6 @@ import com.genersoft.iot.vmp.gb28181.bean.RegionTree;
import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
import com.genersoft.iot.vmp.gb28181.dao.RegionMapper;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelService;
import com.genersoft.iot.vmp.gb28181.service.IRegionService;
import com.genersoft.iot.vmp.utils.CivilCodeUtil;
@@ -125,7 +124,7 @@ public class RegionServiceImpl implements IRegionService {
// 发送变化通知
try {
// 发送catalog
eventPublisher.catalogEventPublish(null, CommonGBChannel.build(region), CatalogEvent.UPDATE);
eventPublisher.channelEventPublishForUpdate(CommonGBChannel.build(region), null);
}catch (Exception e) {
log.warn("[行政区划变化] 发送失败,{}", region.getDeviceId(), e);
}

View File

@@ -49,7 +49,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
@Autowired
private IDeviceChannelService deviceChannelService;
// @Scheduled(fixedRate = 2000) //每400毫秒执行一次
// public void showSize(){
// log.warn("[notify-目录订阅] 待处理消息数量: {}", taskQueue.size() );
@@ -282,7 +282,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent
try {
switch (notifyCatalogChannel.getType()) {
case STATUS_CHANGED:
deviceChannelService.updateChannelStatus(notifyCatalogChannel.getChannel());
deviceChannelService.updateChannelStatusForNotify(notifyCatalogChannel.getChannel());
break;
case ADD:
deviceChannelService.addChannel(notifyCatalogChannel.getChannel());

View File

@@ -81,7 +81,8 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement
// 查询设备是否存在
Device device = redisCatchStorage.getDevice(deviceId);
// 查询上级平台是否存在
Platform parentPlatform = platformService.queryPlatformByServerGBId(deviceId);
// Platform parentPlatform = platformService.queryPlatformByServerGBId(deviceId);
Platform parentPlatform = null;
try {
if (device != null && parentPlatform != null) {
String hostAddress = request.getRemoteAddress().getHostAddress();

View File

@@ -5,14 +5,20 @@ import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
import com.genersoft.iot.vmp.conf.security.JwtUtils;
import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel;
import com.genersoft.iot.vmp.media.bean.MediaServer;
import com.genersoft.iot.vmp.media.service.IMediaServerService;
import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
import com.genersoft.iot.vmp.service.ICloudRecordService;
import com.genersoft.iot.vmp.service.bean.CloudRecordItem;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService;
import com.genersoft.iot.vmp.utils.DateUtil;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
import com.genersoft.iot.vmp.vmanager.cloudRecord.bean.CloudRecordUrl;
import com.genersoft.iot.vmp.web.custom.bean.*;
import com.genersoft.iot.vmp.web.custom.service.CameraChannelService;
import com.github.pagehelper.PageInfo;
@@ -21,6 +27,7 @@ import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -29,9 +36,15 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.async.DeferredResult;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Tag(name = "第三方接口")
@Slf4j
@@ -52,6 +65,12 @@ public class CameraChannelController {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private ICloudRecordService cloudRecordService;
@Autowired
private IStreamPushPlayService streamPushPlayService;
@GetMapping(value = "/camera/list")
@ResponseBody
@@ -330,5 +349,228 @@ public class CameraChannelController {
return new StreamContent(streamInfo);
}
@ResponseBody
@GetMapping("/record/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("/record/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);
}
}
/************************* 以下这些接口只适合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("/record/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 (!org.apache.commons.lang3.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 && org.apache.commons.lang3.ObjectUtils.isEmpty(query.trim())) {
query = null;
}
if (app != null && org.apache.commons.lang3.ObjectUtils.isEmpty(app.trim())) {
app = null;
}
if (stream != null && org.apache.commons.lang3.ObjectUtils.isEmpty(stream.trim())) {
stream = null;
}
if (startTime != null && org.apache.commons.lang3.ObjectUtils.isEmpty(startTime.trim())) {
startTime = null;
}
if (endTime != null && org.apache.commons.lang3.ObjectUtils.isEmpty(endTime.trim())) {
endTime = null;
}
if (callId != null && org.apache.commons.lang3.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 (org.apache.commons.lang3.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((long)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 startTime 开始时间(yyyy-MM-dd HH:mm:ss)
* @param endTime 结束时间(yyyy-MM-dd HH:mm:ss)
* @param mediaServerId 流媒体ID置空则查询全部流媒体
* @param callId 每次录像的唯一标识,置空则查询全部流媒体
* @param remoteHost 拼接播放地址时使用的远程地址
*/
@ResponseBody
@GetMapping("/record/list-url")
@Operation(summary = "分页查询云端录像", security = @SecurityRequirement(name = JwtUtils.HEADER))
@Parameter(name = "query", description = "检索内容", required = false)
@Parameter(name = "app", description = "应用名", required = false)
@Parameter(name = "stream", description = "流ID", required = false)
@Parameter(name = "page", description = "当前页", required = true)
@Parameter(name = "count", description = "每页查询数量", required = true)
@Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = false)
@Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false)
@Parameter(name = "mediaServerId", description = "流媒体ID置空则查询全部流媒体", required = false)
@Parameter(name = "callId", description = "每次录像的唯一标识,置空则查询全部流媒体", required = false)
public PageInfo<CloudRecordUrl> getListWithUrl(HttpServletRequest request, @RequestParam(required = false) String query, @RequestParam(required = false) String app, @RequestParam(required = false) String stream, @RequestParam int page, @RequestParam int count, @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->{}, page->{}, count->{}, startTime->{}, endTime->{}, callId->{}", app, stream, mediaServerId, page, count, startTime, endTime, callId);
List<MediaServer> mediaServers;
if (!org.apache.commons.lang3.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 = null;
}
if (query != null && org.apache.commons.lang3.ObjectUtils.isEmpty(query.trim())) {
query = null;
}
if (app != null && org.apache.commons.lang3.ObjectUtils.isEmpty(app.trim())) {
app = null;
}
if (stream != null && org.apache.commons.lang3.ObjectUtils.isEmpty(stream.trim())) {
stream = null;
}
if (startTime != null && org.apache.commons.lang3.ObjectUtils.isEmpty(startTime.trim())) {
startTime = null;
}
if (endTime != null && org.apache.commons.lang3.ObjectUtils.isEmpty(endTime.trim())) {
endTime = null;
}
if (callId != null && org.apache.commons.lang3.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());
}
PageInfo<CloudRecordItem> cloudRecordItemPageInfo = cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServers, callId, null);
PageInfo<CloudRecordUrl> cloudRecordUrlPageInfo = new PageInfo<>();
if (!org.apache.commons.lang3.ObjectUtils.isEmpty(cloudRecordItemPageInfo)) {
cloudRecordUrlPageInfo.setPageNum(cloudRecordItemPageInfo.getPageNum());
cloudRecordUrlPageInfo.setPageSize(cloudRecordItemPageInfo.getPageSize());
cloudRecordUrlPageInfo.setSize(cloudRecordItemPageInfo.getSize());
cloudRecordUrlPageInfo.setEndRow(cloudRecordItemPageInfo.getEndRow());
cloudRecordUrlPageInfo.setStartRow(cloudRecordItemPageInfo.getStartRow());
cloudRecordUrlPageInfo.setPages(cloudRecordItemPageInfo.getPages());
cloudRecordUrlPageInfo.setPrePage(cloudRecordItemPageInfo.getPrePage());
cloudRecordUrlPageInfo.setNextPage(cloudRecordItemPageInfo.getNextPage());
cloudRecordUrlPageInfo.setIsFirstPage(cloudRecordItemPageInfo.isIsFirstPage());
cloudRecordUrlPageInfo.setIsLastPage(cloudRecordItemPageInfo.isIsLastPage());
cloudRecordUrlPageInfo.setHasPreviousPage(cloudRecordItemPageInfo.isHasPreviousPage());
cloudRecordUrlPageInfo.setHasNextPage(cloudRecordItemPageInfo.isHasNextPage());
cloudRecordUrlPageInfo.setNavigatePages(cloudRecordItemPageInfo.getNavigatePages());
cloudRecordUrlPageInfo.setNavigateFirstPage(cloudRecordItemPageInfo.getNavigateFirstPage());
cloudRecordUrlPageInfo.setNavigateLastPage(cloudRecordItemPageInfo.getNavigateLastPage());
cloudRecordUrlPageInfo.setNavigatepageNums(cloudRecordItemPageInfo.getNavigatepageNums());
cloudRecordUrlPageInfo.setTotal(cloudRecordItemPageInfo.getTotal());
List<CloudRecordUrl> cloudRecordUrlList = new ArrayList<>(cloudRecordItemPageInfo.getList().size());
List<CloudRecordItem> cloudRecordItemList = cloudRecordItemPageInfo.getList();
for (CloudRecordItem cloudRecordItem : cloudRecordItemList) {
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((long)cloudRecordItem.getStartTime()));
cloudRecordUrl.setPlayUrl(remoteHost + "/index/api/downloadFile?file_path=" + cloudRecordItem.getFilePath());
cloudRecordUrlList.add(cloudRecordUrl);
}
cloudRecordUrlPageInfo.setList(cloudRecordUrlList);
}
return cloudRecordUrlPageInfo;
}
@GetMapping(value = "/forceClose")
@ResponseBody
@Operation(summary = "强制停止推流", security = @SecurityRequirement(name = JwtUtils.HEADER))
public void stop(String app, String stream){
streamPushPlayService.stop(app, stream);
}
}

View File

@@ -11,7 +11,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Group;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper;
import com.genersoft.iot.vmp.gb28181.dao.GroupMapper;
import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
import com.genersoft.iot.vmp.gb28181.event.channel.ChannelEvent;
import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService;
import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService;
@@ -113,49 +113,120 @@ public class CameraChannelService implements CommandLineRunner {
// 监听通道变化如果是移动设备则发送redis消息
@EventListener
public void onApplicationEvent(CatalogEvent event) {
public void onApplicationEvent(ChannelEvent event) {
List<CommonGBChannel> channels = event.getChannels();
if (channels.isEmpty()) {
return;
}
List<CommonGBChannel> resultListForAdd = new ArrayList<>();
List<CameraChannel> resultListForDelete = new ArrayList<>();
List<CommonGBChannel> resultListForUpdate = new ArrayList<>();
List<CommonGBChannel> resultListForOnline = new ArrayList<>();
List<CommonGBChannel> resultListForOffline = new ArrayList<>();
List<CameraChannel> mobilechannelList = null;
if (event.getType().equals(CatalogEvent.DEL)) {
mobilechannelList = new ArrayList<>();
for (CommonGBChannel channel : channels) {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
CameraChannel cameraChannel = new CameraChannel();
cameraChannel.setGbDeviceId(channel.getGbDeviceId());
mobilechannelList.add(cameraChannel);
switch (event.getMessageType()) {
case UPDATE:
List<CommonGBChannel> oldChannelList = event.getOldChannels();
List<CommonGBChannel> channelList = event.getChannels();
// 更新操作
if (oldChannelList == null || oldChannelList.isEmpty()) {
// 无旧设备则不需要判断, 目前只有分组或行政区划转换为通道信息时没有旧的通道信息,这两个类型也是不需要发送通知的,直接忽略即可
break;
}
}
}else {
List<Integer> ids = new ArrayList<>();
channels.forEach((channel -> {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
ids.add(channel.getGbId());
// 需要比对旧数据,看看是否是新增的移动设备或者取消的移动设备
// 将 channelList 转为以 gbDeviceId 为 key 的 Map
Map<String, CommonGBChannel> oldChannelMap = new HashMap<>();
for (CommonGBChannel channel : oldChannelList) {
if (channel != null && channel.getGbDeviceId() != null) {
oldChannelMap.put(channel.getGbDeviceId(), channel);
}
}
}));
if (ids.isEmpty()) {
return;
}
mobilechannelList = channelMapper.queryCameraChannelByIds(ids);
for (CommonGBChannel channel : channelList) {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
CommonGBChannel oldChannel = oldChannelMap.get(channel.getGbDeviceId());
if (oldChannel != null) {
if (oldChannel.getGbPtzType() != null && oldChannel.getGbPtzType() == 99) {
resultListForUpdate.add(channel);
}else {
resultListForAdd.add(channel);
}
}else {
resultListForAdd.add(channel);
}
}else {
CommonGBChannel oldChannel = oldChannelMap.get(channel.getGbDeviceId());
if (oldChannel != null && oldChannel.getGbPtzType() != null && oldChannel.getGbPtzType() == 99) {
CameraChannel cameraChannel = new CameraChannel();
cameraChannel.setGbDeviceId(channel.getGbDeviceId());
resultListForDelete.add(cameraChannel);
}
}
}
break;
case DEL:
for (CommonGBChannel channel : channels) {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
CameraChannel cameraChannel = new CameraChannel();
cameraChannel.setGbDeviceId(channel.getGbDeviceId());
resultListForDelete.add(cameraChannel);
}
}
break;
case ON:
case OFF:
case DEFECT:
case VLOST:
for (CommonGBChannel channel : channels) {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
if (event.getMessageType() == ChannelEvent.ChannelEventMessageType.ON) {
resultListForOnline.add(channel);
}else {
resultListForOffline.add(channel);
}
}
}
break;
case ADD:
for (CommonGBChannel channel : channels) {
if (channel.getGbPtzType() != null && channel.getGbPtzType() == 99) {
resultListForAdd.add(channel);
}
}
break;
}
if (mobilechannelList == null || mobilechannelList.isEmpty()) {
if (!resultListForDelete.isEmpty()) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", ChannelEvent.ChannelEventMessageType.DEL);
jsonObject.put("list", resultListForDelete);
log.info("[SY-redis发送通知-DEL] 发送 通道信息变化 {}: {}", REDIS_CHANNEL_MESSAGE, jsonObject.toString());
redisTemplate.convertAndSend(REDIS_CHANNEL_MESSAGE, jsonObject);
}
if (!resultListForAdd.isEmpty()) {
sendChannelMessage(resultListForAdd, ChannelEvent.ChannelEventMessageType.ADD);
}
if (!resultListForUpdate.isEmpty()) {
sendChannelMessage(resultListForAdd, ChannelEvent.ChannelEventMessageType.UPDATE);
}
if (!resultListForOnline.isEmpty()) {
sendChannelMessage(resultListForAdd, ChannelEvent.ChannelEventMessageType.ON);
}
if (!resultListForOffline.isEmpty()) {
sendChannelMessage(resultListForAdd, ChannelEvent.ChannelEventMessageType.OFF);
}
}
private void sendChannelMessage(List<CommonGBChannel> channelList, ChannelEvent.ChannelEventMessageType type) {
if (channelList.isEmpty()) {
return;
}
String type = event.getType();
if (type.equals(CatalogEvent.VLOST) || type.equals(CatalogEvent.DEFECT)) {
type = CatalogEvent.OFF;
}
List<CameraChannel> cameraChannelList = channelMapper.queryCameraChannelByIds(channelList);
JSONObject jsonObject = new JSONObject();
jsonObject.put("type", type);
jsonObject.put("list", mobilechannelList);
log.info("[SY-redis发送通知] 发送 通道信息变化 {}: {}", REDIS_CHANNEL_MESSAGE, jsonObject.toString());
jsonObject.put("list", cameraChannelList);
log.info("[SY-redis发送通知-{}] 发送 通道信息变化 {}: {}", type, REDIS_CHANNEL_MESSAGE, jsonObject.toString());
redisTemplate.convertAndSend(REDIS_CHANNEL_MESSAGE, jsonObject);
}
// 监听GPS消息如果是移动设备则发送redis消息

View File

@@ -10,7 +10,7 @@
:add-channel-to-group="addChannelToGroup"
/>
<div style="padding: 0 20px">
<el-form :inline="true" size="mini">
<el-form :inline="true" size="mini" ref="queryForm">
<el-form-item>
<el-breadcrumb v-if="regionParents.length > 0" separator="/" style="display: ruby">
<el-breadcrumb-item v-for="key in regionParents" :key="key">{{ key }}</el-breadcrumb-item>
@@ -74,7 +74,7 @@
ref="channelListTable"
size="medium"
:data="channelList"
height="calc(100vh - 190px)"
:height="tableHeight"
style="width: 100%"
header-row-class-name="table-header"
@selection-change="handleSelectionChange"
@@ -132,6 +132,7 @@ export default {
data() {
return {
channelList: [],
tableHeight: `calc(100vh - ${this.$refs.queryForm.offsetHeight}px)`,
searchStr: '',
channelType: '',
online: '',