Merge remote-tracking branch 'origin/dev' into dev
2 files added
13 files modified
| | |
| | | caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交")); |
| | | caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理")); |
| | | caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数")); |
| | | caches.add(new SysCache(CacheConstants.CAMERA_LIST_KEY, "相机列表")); |
| | | caches.add(new SysCache(CacheConstants.UAV_ONLINE_KEY, "在线无人机")); |
| | | caches.add(new SysCache(CacheConstants.SYS_USER_KEY, "用户列表")); |
| | | } |
| | | |
| | | @PreAuthorize("@ss.hasPermi('monitor:cache:list')") |
| | |
| | | * 校验航线任务是否可以创建航线 |
| | | */ |
| | | @ApiOperation("校验航线任务是否可以创建航线") |
| | | //@PreAuthorize("@ss.hasPermi('route:mission:query')") |
| | | @GetMapping(value = "/{missionId}") |
| | | public Boolean routeMissionNot(@PathVariable("missionId") String missionId) { |
| | | return ardRouteMissionService.selectRouteMissionNot(missionId); |
| | | @GetMapping("routeMissionNot/{id}") |
| | | public AjaxResult routeMissionNot(@PathVariable("id") String id) { |
| | | return success(ardRouteMissionService.selectRouteMissionNot(id)); |
| | | } |
| | | |
| | | } |
| | |
| | | /** |
| | | * 所有相机 redis key |
| | | */ |
| | | public static final String CAMERA_LIST_KEY = "camera_list:"; |
| | | public static final String CAMERA_LIST = "camera:list"; |
| | | |
| | | /** |
| | | * 在线无人机 redis key |
| | |
| | | /** |
| | | * 用户列表 redis key |
| | | */ |
| | | public static final String SYS_USER_KEY = "sys_user:"; |
| | | public static final String SYS_USER= "user:list"; |
| | | } |
| New file |
| | |
| | | package com.ard.device.camera.config; |
| | | |
| | | import org.springframework.context.annotation.Bean; |
| | | import org.springframework.context.annotation.Configuration; |
| | | import org.springframework.scheduling.annotation.EnableAsync; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | |
| | | import java.util.concurrent.ThreadPoolExecutor; |
| | | |
| | | /** |
| | | * @ClassName: AsyncConfiguration |
| | | * @Description: 异步线程配置类 |
| | | * @Author: Administrator |
| | | * @Date: 2023年02月03日 11:25 |
| | | * @Version: 1.0 |
| | | **/ |
| | | @Configuration |
| | | @EnableAsync(proxyTargetClass = true) |
| | | public class AsyncConfiguration { |
| | | |
| | | @Bean("globalExecutor") |
| | | public ThreadPoolTaskExecutor globalExecutor(){ |
| | | ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); |
| | | //配置核心线程数 |
| | | executor.setCorePoolSize(18); |
| | | //配置最大线程数 |
| | | executor.setMaxPoolSize(36); |
| | | //配置队列大小 |
| | | executor.setQueueCapacity(100); |
| | | //线程的名称前缀 |
| | | executor.setThreadNamePrefix("globalExecutor-"); |
| | | //线程活跃时间(秒) |
| | | executor.setKeepAliveSeconds(3000); |
| | | //等待所有任务结束后再关闭线程池 |
| | | executor.setWaitForTasksToCompleteOnShutdown(true); |
| | | //设置拒绝策略 |
| | | executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); |
| | | //执行初始化 |
| | | executor.initialize(); |
| | | return executor; |
| | | } |
| | | } |
| | |
| | | import org.springframework.context.event.EventListener; |
| | | import org.springframework.scheduling.annotation.Async; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | import javax.annotation.Resource; |
| | |
| | | @Resource |
| | | protected Validator validator; |
| | | |
| | | @Resource(name = "globalExecutor") |
| | | private ThreadPoolTaskExecutor executorService; |
| | | |
| | | @Override |
| | | public void run(ApplicationArguments args) { |
| | |
| | | |
| | | public void initCamera() { |
| | | //清空相机缓存 |
| | | redisService.deleteObject(redisService.keys(getCacheKey("*"))); |
| | | redisService.deleteObject(CacheConstants.CAMERA_LIST); |
| | | //重新加载相机到缓存 |
| | | ardCameraMapper.selectArdCameraList(new ArdCamera()).forEach(ardCamera -> { |
| | | ardCameraMapper.resetCameraLoginId(ardCamera); |
| | | redisService.setCacheObject(getCacheKey(ardCamera.getId()), ardCamera); |
| | | cameraSDKService.login(ardCamera); |
| | | redisService.setCacheMapValue(CacheConstants.CAMERA_LIST, ardCamera.getId(), ardCamera); |
| | | // 提交到线程池异步执行 |
| | | executorService.submit(() -> { |
| | | cameraSDKService.login(ardCamera); |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 设置cache key |
| | | * |
| | | * @param configKey 参数键 |
| | | * @return 缓存键key |
| | | */ |
| | | private String getCacheKey(String configKey) { |
| | | return CacheConstants.CAMERA_LIST_KEY + configKey; |
| | | } |
| | | |
| | | |
| | |
| | | ardCamera.setUserId(SecurityUtils.getUserId()); |
| | | int res = ardCameraMapper.insertArdCamera(ardCamera); |
| | | if (res > 0) { |
| | | redisService.setCacheMapValue(CacheConstants.CAMERA_LIST, ardCamera.getId(), ardCamera); |
| | | cameraSDKService.login(ardCamera);//sdk登录获取通道信息 |
| | | } |
| | | return res; |
| | |
| | | ardCamera.setUpdateBy(SecurityUtils.getUsername()); |
| | | int res = ardCameraMapper.updateArdCamera(ardCamera); |
| | | if (res > 0) { |
| | | redisService.setCacheMapValue(CacheConstants.CAMERA_LIST, ardCamera.getId(), ardCamera); |
| | | cameraSDKService.logout(ardCamera);//sdk注销 |
| | | cameraSDKService.login(ardCamera);//sdk登录获取通道信息 |
| | | } |
| | |
| | | ArdCamera camera = ardCameraMapper.selectArdCameraById(id); |
| | | if (camera != null) { |
| | | //redis中删除 |
| | | redisService.deleteObject(getCacheKey(id)); |
| | | redisService.deleteCacheMapValue(CacheConstants.CAMERA_LIST, id); |
| | | //删除当前相机的所有通道 |
| | | ardChannelService.deleteArdChannelByDeviceId(id); |
| | | //sdk注销 |
| | |
| | | int i = ardCameraMapper.deleteArdCameraById(id); |
| | | if (i > 0) { |
| | | //redis中删除 |
| | | redisService.deleteObject(getCacheKey(id)); |
| | | redisService.deleteCacheMapValue(CacheConstants.CAMERA_LIST, id); |
| | | //删除当前相机的所有通道 |
| | | ardChannelService.deleteArdChannelByDeviceId(id); |
| | | //sdk注销 |
| | |
| | | @Override |
| | | public ArdCamera checkAirportHasCamera(ArdCamera camera) { |
| | | ArdCamera info = ardCameraMapper.checkAirportHasCamera(camera); |
| | | if (StringUtils.isNotNull(info)&& !info.getId().equals(camera.getId())) { |
| | | if (StringUtils.isNotNull(info) && !info.getId().equals(camera.getId())) { |
| | | return info; |
| | | } |
| | | return null; |
| | |
| | | public void LoginEventListener(LoginEvent loginEvent) { |
| | | ArdCamera camera = loginEvent.getCamera(); |
| | | ardCameraMapper.updateArdCamera(camera); |
| | | // SDK 登录成功后写入 Redis |
| | | redisService.setCacheObject(getCacheKey(camera.getId()), camera); |
| | | } |
| | | |
| | | /** |
| | |
| | | log.error("同步相机在线状态异常:{}", ex.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 同步相机通道 |
| | | */ |
| | |
| | | private IArdVtduService ardVtduService; |
| | | @Resource |
| | | private MediamtxConfig mediamtxConfig; |
| | | |
| | | /** |
| | | * 查询通道管理 |
| | | * |
| | |
| | | ArdChannel ardChannel = new ArdChannel(); |
| | | ardChannel.setUseDataScope(false); |
| | | List<ArdChannel> channels = this.selectArdChannelList(ardChannel); |
| | | if (channels == null || channels.isEmpty()) { |
| | | // log.warn("没有获取到通道数据,退出同步"); |
| | | return; |
| | | } |
| | | // if (channels == null || channels.isEmpty()) { |
| | | // // log.warn("没有获取到通道数据,退出同步"); |
| | | // return; |
| | | // } |
| | | List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu()); |
| | | |
| | | Set<String> validNames = channels.stream() |
| | |
| | | "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name; // |
| | | // 拼接 webrtcUrl |
| | | String rtmpUrl = |
| | | "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; // 拼接 |
| | | "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; |
| | | // 拼接 |
| | | // webrtcUrl |
| | | String protocol = mediamtxConfig.isHttps() ? "https://" : "http://"; |
| | | String webrtcUrl = |
| | |
| | | log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("定时同步Vtdu任务异常:{}", e.getMessage()); |
| | | log.error("定时同步Vtdu任务异常:{}", e.getMessage()); |
| | | } |
| | | |
| | | } |
| | |
| | | // 根据通道信息获取rtsp源地址 |
| | | private String getRtspSource(ArdChannel channel) { |
| | | String rtspSource = ""; |
| | | ArdCamera ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + channel.getDeviceId()); |
| | | ArdCamera ardCamera = redisCache.getCacheMapValue(CacheConstants.CAMERA_LIST, channel.getDeviceId()); |
| | | if (ardCamera != null) { |
| | | switch (ardCamera.getFactory()) { |
| | | case "1": |
| New file |
| | |
| | | package com.ard.route.domain.route; |
| | | |
| | | import lombok.Data; |
| | | |
| | | @Data |
| | | public class MissionNot { |
| | | |
| | | /** |
| | | * 是否类型 |
| | | */ |
| | | private Boolean isNot; |
| | | |
| | | /** |
| | | * 消息 |
| | | */ |
| | | private String information; |
| | | |
| | | } |
| | |
| | | package com.ard.route.service; |
| | | |
| | | import com.ard.route.domain.route.ArdRouteMission; |
| | | import com.ard.route.domain.route.MissionNot; |
| | | import com.ard.route.domain.route.UpdateMission; |
| | | |
| | | import java.util.List; |
| | |
| | | /** |
| | | * 校验航线任务是否可以创建航线 |
| | | * |
| | | * @param missionId 航线任务ID |
| | | * @param id ID |
| | | * @return 结果 |
| | | */ |
| | | public Boolean selectRouteMissionNot(String missionId); |
| | | public MissionNot selectRouteMissionNot(String id); |
| | | |
| | | } |
| | |
| | | */ |
| | | @Override |
| | | public String insertArdRouteInfo(ArdRouteInfo ardRouteInfo) { |
| | | validateForCreate(ardRouteInfo); |
| | | checkRouteMissionStatus(ardRouteInfo,"1"); |
| | | checkRouteMissionStatus(ardRouteInfo,"2"); |
| | | ardRouteInfo.setId(IdUtils.simpleUUID()); |
| | |
| | | break; |
| | | default: |
| | | throw new RuntimeException("不支持的操作类型!!!"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 验证,只有当前用户是下发人才能创建航线 |
| | | private void validateForCreate(ArdRouteInfo ardRouteInfo) { |
| | | ArdRouteMission mission = ardRouteMissionMapper.selectArdRouteMissionById(ardRouteInfo.getMissionId()); |
| | | if (mission != null){ |
| | | if (!mission.getIssuerId().equals(getUserId())){ |
| | | throw new RuntimeException("创建航线,只能创建下发自己的航线任务信息【" + mission.getMissionName() + "】,无法执行操作!"); |
| | | //return "创建航线,只能创建下发自己的航线任务信息【" + mission.getMissionName() + "】,无法执行操作!"; |
| | | } |
| | | } |
| | | } |
| | |
| | | import com.ard.common.utils.uuid.IdUtils; |
| | | import com.ard.route.domain.route.ArdRouteMission; |
| | | import com.ard.route.domain.route.ArdRoutePoint; |
| | | import com.ard.route.domain.route.MissionNot; |
| | | import com.ard.route.domain.route.UpdateMission; |
| | | import com.ard.route.mapper.ArdRoutePointMapper; |
| | | import com.ard.route.websocket.utils.MiWebSocketUtils; |
| | |
| | | /** |
| | | * 校验航线任务是否可以创建航线 |
| | | * |
| | | * @param missionId 航线任务ID |
| | | * @param id ID |
| | | * @return 结果 |
| | | */ |
| | | @Override |
| | | public Boolean selectRouteMissionNot(String missionId) { |
| | | ArdRouteMission mission = ardRouteMissionMapper.selectArdRouteMissionById(missionId); |
| | | if (mission != null){ |
| | | throw new RuntimeException("创建航线,只能创建下发自己的航线任务信息【" + mission.getMissionName() + "】,无法执行操作!"); |
| | | public MissionNot selectRouteMissionNot(String id) { |
| | | // 1. 初始化返回对象,默认允许操作 |
| | | MissionNot missionNot = new MissionNot(); |
| | | missionNot.setIsNot(true); |
| | | |
| | | // 2. 根据ID查询航线任务 |
| | | ArdRouteMission mission = ardRouteMissionMapper.selectArdRouteMissionById(id); |
| | | |
| | | // 3. 空值快速返回(任务不存在则无需校验,直接允许操作) |
| | | if (mission == null) { |
| | | return missionNot; |
| | | } |
| | | return true; |
| | | |
| | | // 4. 校验任务创建者是否为当前用户 |
| | | // 增加空指针防护:避免issuerId为null导致空指针异常 |
| | | if (mission.getIssuerId() == null || !mission.getIssuerId().equals(getUserId())) { |
| | | String errorMsg = String.format("创建航线,只能创建下发自己的航线任务信息【%s】,无法执行操作!", |
| | | mission.getMissionName()); |
| | | missionNot.setInformation(errorMsg); |
| | | missionNot.setIsNot(false); |
| | | } |
| | | |
| | | // 5. 统一返回结果 |
| | | return missionNot; |
| | | } |
| | | |
| | | } |
| | |
| | | |
| | | // 将用户列表存入 Redis,使用用户 ID 作为 Redis 键 |
| | | userList.forEach(user -> { |
| | | redisCache.setCacheObject(CacheConstants.SYS_USER_KEY + user.getUserId(), user); |
| | | redisCache.setCacheMapValue(CacheConstants.SYS_USER, user.getUserId().toString(), user); |
| | | }); |
| | | |
| | | log.info("用户信息已成功加载到 Redis!"); |
| | |
| | | // 新增用户信息 |
| | | int rows = userMapper.insertUser(user); |
| | | // 同步到 Redis |
| | | redisCache.setCacheObject(CacheConstants.SYS_USER_KEY + user.getUserId(), user); |
| | | redisCache.setCacheMapValue(CacheConstants.SYS_USER, user.getUserId().toString(), user); |
| | | // 新增用户岗位关联 |
| | | insertUserPost(user); |
| | | // 新增用户与角色管理 |
| | |
| | | // 更新用户信息 |
| | | int result = userMapper.updateUser(user); |
| | | // 同步到 Redis |
| | | redisCache.setCacheObject(CacheConstants.SYS_USER_KEY + user.getUserId(), user); |
| | | redisCache.setCacheMapValue(CacheConstants.SYS_USER, user.getUserId().toString(), user); |
| | | return result; |
| | | } |
| | | |
| | |
| | | // 删除用户信息 |
| | | int result = userMapper.deleteUserById(userId); |
| | | // 从 Redis 删除用户信息 |
| | | redisCache.deleteObject(CacheConstants.SYS_USER_KEY + userId); |
| | | redisCache.deleteCacheMapValue(CacheConstants.SYS_USER, userId.toString()); |
| | | return result; |
| | | } |
| | | |
| | |
| | | |
| | | // 批量删除 Redis 中的用户信息 |
| | | for (Long userId : userIds) { |
| | | redisCache.deleteObject(CacheConstants.SYS_USER_KEY + userId); |
| | | redisCache.deleteCacheMapValue(CacheConstants.SYS_USER, userId.toString()); |
| | | } |
| | | return result; |
| | | } |
| | |
| | | map.put("signal", uavSignalInfo); |
| | | // 获取当前控制飞行的用户ID |
| | | Long flyUserId = uavControlService.getCurrentController(boxSn, "fly"); |
| | | SysUser flyUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + flyUserId); |
| | | SysUser flyUser = redisCache.getCacheMapValue(CacheConstants.SYS_USER, flyUserId.toString()); |
| | | // 将飞行当前控制者用户ID添加到映射中 |
| | | map.put("flyController", flyUser); |
| | | // 获取当前控制载荷的用户ID |
| | | Long payloadUserId = uavControlService.getCurrentController(boxSn, "payload"); |
| | | SysUser payloadUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + payloadUserId); |
| | | SysUser payloadUser = redisCache.getCacheMapValue(CacheConstants.SYS_USER, payloadUserId.toString()); |
| | | // 将载荷当前控制者用户ID添加到映射中 |
| | | map.put("payloadController", payloadUser); |
| | | return map; |
| | |
| | | */ |
| | | public void sendControlRequest(Long controllerId, String boxSn, String type, Long requesterId) { |
| | | |
| | | SysUser requester = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + requesterId); |
| | | SysUser requester = redisCache.getCacheMapValue(CacheConstants.SYS_USER, requesterId.toString()); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | |
| | | */ |
| | | public void sendControlApproval(Long requesterId, String boxSn, String type, Long controllerId) { |
| | | |
| | | SysUser controller = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + controllerId); |
| | | SysUser controller = redisCache.getCacheMapValue(CacheConstants.SYS_USER, controllerId.toString()); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | |
| | | */ |
| | | public void sendControlRejection(Long requesterId, String boxSn, String type, Long controllerId) { |
| | | |
| | | SysUser controller = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + controllerId); |
| | | SysUser controller = redisCache.getCacheMapValue(CacheConstants.SYS_USER, controllerId.toString()); |
| | | |
| | | UavControlMessage msg = new UavControlMessage(); |
| | | msg.setBoxSn(boxSn); |
| | |
| | | */ |
| | | public void sendControlTakeover(Long oldControllerId, Long newControllerId, String boxSn, String type) { |
| | | |
| | | SysUser newController = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + newControllerId); |
| | | SysUser oldController = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + oldControllerId); |
| | | SysUser newController = redisCache.getCacheMapValue(CacheConstants.SYS_USER, newControllerId.toString()); |
| | | SysUser oldController = redisCache.getCacheMapValue(CacheConstants.SYS_USER, oldControllerId.toString()); |
| | | |
| | | // 1️⃣ 通知原控制者:你被抢占了 |
| | | UavControlMessage msgOld = new UavControlMessage(); |
| | |
| | | * 控制权释放 |
| | | */ |
| | | public void sendControlRelease(String boxSn, String type, Long operatorId) { |
| | | SysUser operator = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + operatorId); |
| | | SysUser operator = redisCache.getCacheMapValue(CacheConstants.SYS_USER, operatorId.toString()); |
| | | |
| | | UavControlMessage message = new UavControlMessage(); |
| | | message.setBoxSn(boxSn); |
| | |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("boxSn", boxSn); |
| | | // 将飞行当前控制者用户ID添加到映射中 |
| | | SysUser flyUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + flyUserId); |
| | | SysUser flyUser = redisCache.getCacheMapValue(CacheConstants.SYS_USER, flyUserId.toString()); |
| | | map.put("flyController", flyUser); |
| | | // 将载荷当前控制者用户ID添加到映射中 |
| | | SysUser payloadUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + payloadUserId); |
| | | SysUser payloadUser = redisCache.getCacheMapValue(CacheConstants.SYS_USER, payloadUserId.toString()); |
| | | map.put("payloadController", payloadUser); |
| | | // 返回包含当前控制者信息的映射 |
| | | return map; |
| | |
| | | // 🚨 其他请求者自动拒绝(强烈建议) |
| | | for (Long other : requesters) { |
| | | if (!other.equals(requester)) { |
| | | requesters.remove(requester); |
| | | requesters.remove(other); |
| | | uavControlManager.sendControlRejection(other, boxSn, controlType.getType(), controller); |
| | | } |
| | | } |
| | |
| | | |
| | | Long flyUserId = uavControlService.getCurrentController(flightTask.getBoxSn(), "fly"); |
| | | if (flyUserId != null) { |
| | | SysUser flyUser = redisCache.getCacheObject(CacheConstants.SYS_USER_KEY + flyUserId); |
| | | SysUser flyUser = redisCache.getCacheMapValue(CacheConstants.SYS_USER, flyUserId.toString()); |
| | | if (flyUser != null && flyUser.getNickName() != null) { |
| | | flightTask.setCreateBy(flyUser.getNickName()); |
| | | } |