|  |  | 
 |  |  | package com.genersoft.iot.vmp.vmanager.gb28181.device; | 
 |  |  |  | 
 |  |  | import com.alibaba.fastjson.JSONObject; | 
 |  |  | import com.alibaba.fastjson2.JSONObject; | 
 |  |  | import com.genersoft.iot.vmp.conf.DynamicTask; | 
 |  |  | import com.genersoft.iot.vmp.conf.exception.ControllerException; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.bean.Device; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; | 
 |  |  | import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; | 
 |  |  | 
 |  |  | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | 
 |  |  | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; | 
 |  |  | import com.genersoft.iot.vmp.vmanager.bean.BaseTree; | 
 |  |  | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | 
 |  |  | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | 
 |  |  | import com.github.pagehelper.PageInfo; | 
 |  |  | import io.swagger.v3.oas.annotations.Operation; | 
 |  |  | import io.swagger.v3.oas.annotations.Parameter; | 
 |  |  | import io.swagger.v3.oas.annotations.tags.Tag; | 
 |  |  | import org.apache.commons.compress.utils.IOUtils; | 
 |  |  | import org.apache.http.HttpResponse; | 
 |  |  | import org.slf4j.Logger; | 
 |  |  | import org.slf4j.LoggerFactory; | 
 |  |  | import org.springframework.beans.factory.annotation.Autowired; | 
 |  |  | import org.springframework.http.HttpStatus; | 
 |  |  | import org.springframework.http.MediaType; | 
 |  |  | import org.springframework.http.ResponseEntity; | 
 |  |  | import org.springframework.util.StringUtils; | 
 |  |  | import org.springframework.util.ObjectUtils; | 
 |  |  | import org.springframework.web.bind.annotation.*; | 
 |  |  | import org.springframework.web.context.request.async.DeferredResult; | 
 |  |  |  | 
 |  |  | import javax.servlet.http.HttpServletResponse; | 
 |  |  | import javax.sip.DialogState; | 
 |  |  | import java.io.*; | 
 |  |  | import javax.sip.InvalidArgumentException; | 
 |  |  | import javax.sip.SipException; | 
 |  |  | import java.io.File; | 
 |  |  | import java.io.IOException; | 
 |  |  | import java.io.InputStream; | 
 |  |  | import java.nio.file.Files; | 
 |  |  | import java.text.ParseException; | 
 |  |  | import java.util.*; | 
 |  |  |  | 
 |  |  | @Tag(name  = "国标设备查询", description = "国标设备查询") | 
 |  |  | 
 |  |  |    @Autowired | 
 |  |  |    private DynamicTask dynamicTask; | 
 |  |  |  | 
 |  |  |    @Autowired | 
 |  |  |    private SubscribeHolder subscribeHolder; | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  |     * 使用ID查询国标设备 | 
 |  |  |     * @param deviceId 国标ID | 
 |  |  | 
 |  |  |    @Operation(summary = "查询国标设备") | 
 |  |  |    @Parameter(name = "deviceId", description = "设备国标编号", required = true) | 
 |  |  |    @GetMapping("/devices/{deviceId}") | 
 |  |  |    public ResponseEntity<Device> devices(@PathVariable String deviceId){ | 
 |  |  |    public Device devices(@PathVariable String deviceId){ | 
 |  |  |        | 
 |  |  |       Device device = storager.queryVideoDevice(deviceId); | 
 |  |  |       return new ResponseEntity<>(device,HttpStatus.OK); | 
 |  |  |       return storager.queryVideoDevice(deviceId); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |    @GetMapping("/devices") | 
 |  |  |    public PageInfo<Device> devices(int page, int count){ | 
 |  |  |        | 
 |  |  |       return storager.queryVideoDeviceList(page, count); | 
 |  |  |       return storager.queryVideoDeviceList(page, count,null); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |    @Parameter(name = "online", description = "是否在线") | 
 |  |  |    @Parameter(name = "channelType", description = "设备/子目录-> false/true") | 
 |  |  |    @Parameter(name = "catalogUnderDevice", description = "是否直属与设备的目录") | 
 |  |  |    public ResponseEntity<PageInfo> channels(@PathVariable String deviceId, | 
 |  |  |    public PageInfo channels(@PathVariable String deviceId, | 
 |  |  |                                     int page, int count, | 
 |  |  |                                     @RequestParam(required = false) String query, | 
 |  |  |                                     @RequestParam(required = false) Boolean online, | 
 |  |  |                                     @RequestParam(required = false) Boolean channelType, | 
 |  |  |                                     @RequestParam(required = false) Boolean catalogUnderDevice) { | 
 |  |  |       if (StringUtils.isEmpty(query)) { | 
 |  |  |       if (ObjectUtils.isEmpty(query)) { | 
 |  |  |          query = null; | 
 |  |  |       } | 
 |  |  |  | 
 |  |  |       PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, catalogUnderDevice, page, count); | 
 |  |  |       return new ResponseEntity<>(pageResult,HttpStatus.OK); | 
 |  |  |       return storager.queryChannelsByDeviceId(deviceId, query, channelType, online, catalogUnderDevice, page, count); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |     */ | 
 |  |  |    @Operation(summary = "同步设备通道") | 
 |  |  |    @Parameter(name = "deviceId", description = "设备国标编号", required = true) | 
 |  |  |    @PostMapping("/devices/{deviceId}/sync") | 
 |  |  |    @GetMapping("/devices/{deviceId}/sync") | 
 |  |  |    public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId){ | 
 |  |  |        | 
 |  |  |       if (logger.isDebugEnabled()) { | 
 |  |  | 
 |  |  |       boolean status = deviceService.isSyncRunning(deviceId); | 
 |  |  |       // 已存在则返回进度 | 
 |  |  |       if (status) { | 
 |  |  |          WVPResult<SyncStatus> wvpResult = new WVPResult<>(); | 
 |  |  |          wvpResult.setCode(0); | 
 |  |  |          SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId); | 
 |  |  |          wvpResult.setData(channelSyncStatus); | 
 |  |  |          return wvpResult; | 
 |  |  |          return WVPResult.success(channelSyncStatus); | 
 |  |  |       } | 
 |  |  |       deviceService.sync(device); | 
 |  |  |  | 
 |  |  | 
 |  |  |    @Operation(summary = "移除设备") | 
 |  |  |    @Parameter(name = "deviceId", description = "设备国标编号", required = true) | 
 |  |  |    @DeleteMapping("/devices/{deviceId}/delete") | 
 |  |  |    public ResponseEntity<String> delete(@PathVariable String deviceId){ | 
 |  |  |    public String delete(@PathVariable String deviceId){ | 
 |  |  |        | 
 |  |  |       if (logger.isDebugEnabled()) { | 
 |  |  |          logger.debug("设备信息删除API调用,deviceId:" + deviceId); | 
 |  |  |       } | 
 |  |  |  | 
 |  |  |       // 清除redis记录 | 
 |  |  |       boolean isSuccess = storager.delete(deviceId); | 
 |  |  |       boolean isSuccess = deviceService.delete(deviceId); | 
 |  |  |       if (isSuccess) { | 
 |  |  |          redisCatchStorage.clearCatchByDeviceId(deviceId); | 
 |  |  |          // 停止此设备的订阅更新 | 
 |  |  | 
 |  |  |          } | 
 |  |  |          JSONObject json = new JSONObject(); | 
 |  |  |          json.put("deviceId", deviceId); | 
 |  |  |          return new ResponseEntity<>(json.toString(),HttpStatus.OK); | 
 |  |  |          return json.toString(); | 
 |  |  |       } else { | 
 |  |  |          logger.warn("设备信息删除API调用失败!"); | 
 |  |  |          return new ResponseEntity<String>("设备信息删除API调用失败!", HttpStatus.INTERNAL_SERVER_ERROR); | 
 |  |  |          throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备信息删除API调用失败!"); | 
 |  |  |       } | 
 |  |  |    } | 
 |  |  |  | 
 |  |  | 
 |  |  |    @Parameter(name = "online", description = "是否在线") | 
 |  |  |    @Parameter(name = "channelType", description = "设备/子目录-> false/true") | 
 |  |  |    @GetMapping("/sub_channels/{deviceId}/{channelId}/channels") | 
 |  |  |    public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId, | 
 |  |  |    public PageInfo subChannels(@PathVariable String deviceId, | 
 |  |  |                                       @PathVariable String channelId, | 
 |  |  |                                       int page, | 
 |  |  |                                       int count, | 
 |  |  | 
 |  |  |       DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); | 
 |  |  |       if (deviceChannel == null) { | 
 |  |  |          PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>(); | 
 |  |  |          return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK); | 
 |  |  |          return deviceChannelPageResult; | 
 |  |  |       } | 
 |  |  |  | 
 |  |  |       PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count); | 
 |  |  |       return new ResponseEntity<>(pageResult,HttpStatus.OK); | 
 |  |  |       return pageResult; | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |    @Parameter(name = "deviceId", description = "设备国标编号", required = true) | 
 |  |  |    @Parameter(name = "channel", description = "通道信息", required = true) | 
 |  |  |    @PostMapping("/channel/update/{deviceId}") | 
 |  |  |    public ResponseEntity updateChannel(@PathVariable String deviceId,DeviceChannel channel){ | 
 |  |  |    public void updateChannel(@PathVariable String deviceId,DeviceChannel channel){ | 
 |  |  |       deviceChannelService.updateChannel(deviceId, channel); | 
 |  |  |       return new ResponseEntity<>(null,HttpStatus.OK); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |    @Parameter(name = "streamMode", description = "数据流传输模式, 取值:" + | 
 |  |  |          "UDP(udp传输),TCP-ACTIVE(tcp主动模式,暂不支持),TCP-PASSIVE(tcp被动模式)", required = true) | 
 |  |  |    @PostMapping("/transport/{deviceId}/{streamMode}") | 
 |  |  |    public ResponseEntity updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){ | 
 |  |  |       Device device = storager.queryVideoDevice(deviceId); | 
 |  |  |    public void updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){ | 
 |  |  |       Device device = deviceService.getDevice(deviceId); | 
 |  |  |       device.setStreamMode(streamMode); | 
 |  |  |       deviceService.updateDevice(device); | 
 |  |  |       return new ResponseEntity<>(null,HttpStatus.OK); | 
 |  |  |       deviceService.updateCustomDevice(device); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  |     * 添加设备信息 | 
 |  |  |     * @param device 设备信息 | 
 |  |  |     * @return | 
 |  |  |     */ | 
 |  |  |    @Operation(summary = "添加设备信息") | 
 |  |  |    @Parameter(name = "device", description = "设备", required = true) | 
 |  |  |    @PostMapping("/device/add/") | 
 |  |  |    public void addDevice(Device device){ | 
 |  |  |  | 
 |  |  |       if (device == null || device.getDeviceId() == null) { | 
 |  |  |          throw new ControllerException(ErrorCode.ERROR400); | 
 |  |  |       } | 
 |  |  |  | 
 |  |  |       // 查看deviceId是否存在 | 
 |  |  |       boolean exist = deviceService.isExist(device.getDeviceId()); | 
 |  |  |       if (exist) { | 
 |  |  |          throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备编号已存在"); | 
 |  |  |       } | 
 |  |  |       deviceService.addDevice(device); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |    @Operation(summary = "更新设备信息") | 
 |  |  |    @Parameter(name = "device", description = "设备", required = true) | 
 |  |  |    @PostMapping("/device/update/") | 
 |  |  |    public ResponseEntity<WVPResult<String>> updateDevice(Device device){ | 
 |  |  |    public void updateDevice(Device device){ | 
 |  |  |  | 
 |  |  |       if (device != null && device.getDeviceId() != null) { | 
 |  |  |          deviceService.updateDevice(device); | 
 |  |  |          deviceService.updateCustomDevice(device); | 
 |  |  |       } | 
 |  |  |       WVPResult<String> result = new WVPResult<>(); | 
 |  |  |       result.setCode(0); | 
 |  |  |       result.setMsg("success"); | 
 |  |  |       return new ResponseEntity<>(result,HttpStatus.OK); | 
 |  |  |    } | 
 |  |  |  | 
 |  |  |    /** | 
 |  |  | 
 |  |  |          result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId),HttpStatus.OK)); | 
 |  |  |          return result; | 
 |  |  |       } | 
 |  |  |       cmder.deviceStatusQuery(device, event -> { | 
 |  |  |          RequestMessage msg = new RequestMessage(); | 
 |  |  |          msg.setId(uuid); | 
 |  |  |          msg.setKey(key); | 
 |  |  |          msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg)); | 
 |  |  |          resultHolder.invokeResult(msg); | 
 |  |  |       }); | 
 |  |  |       try { | 
 |  |  |          cmder.deviceStatusQuery(device, 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) { | 
 |  |  |          logger.error("[命令发送失败] 获取设备状态: {}", e.getMessage()); | 
 |  |  |          throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); | 
 |  |  |       } | 
 |  |  |       result.onTimeout(()->{ | 
 |  |  |          logger.warn(String.format("获取设备状态超时")); | 
 |  |  |          // 释放rtpserver | 
 |  |  | 
 |  |  |       Device device = storager.queryVideoDevice(deviceId); | 
 |  |  |       String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId; | 
 |  |  |       String uuid = UUID.randomUUID().toString(); | 
 |  |  |       cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { | 
 |  |  |          RequestMessage msg = new RequestMessage(); | 
 |  |  |          msg.setId(uuid); | 
 |  |  |          msg.setKey(key); | 
 |  |  |          msg.setData(String.format("设备报警查询失败,错误码: %s, %s",event.statusCode, event.msg)); | 
 |  |  |          resultHolder.invokeResult(msg); | 
 |  |  |       }); | 
 |  |  |         DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L); | 
 |  |  |       try { | 
 |  |  |          cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, 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) { | 
 |  |  |          logger.error("[命令发送失败] 设备报警查询: {}", e.getMessage()); | 
 |  |  |          throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); | 
 |  |  |       } | 
 |  |  |       DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (3 * 1000L); | 
 |  |  |       result.onTimeout(()->{ | 
 |  |  |          logger.warn(String.format("设备报警查询超时")); | 
 |  |  |          // 释放rtpserver | 
 |  |  | 
 |  |  |          wvpResult.setCode(-1); | 
 |  |  |          wvpResult.setMsg("同步尚未开始"); | 
 |  |  |       }else { | 
 |  |  |          wvpResult.setCode(0); | 
 |  |  |          wvpResult.setCode(ErrorCode.SUCCESS.getCode()); | 
 |  |  |          wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); | 
 |  |  |          wvpResult.setData(channelSyncStatus); | 
 |  |  |          if (channelSyncStatus.getErrorMsg() != null) { | 
 |  |  |             wvpResult.setMsg(channelSyncStatus.getErrorMsg()); | 
 |  |  | 
 |  |  |    @GetMapping("/{deviceId}/subscribe_info") | 
 |  |  |    @Operation(summary = "获取设备的订阅状态") | 
 |  |  |    @Parameter(name = "deviceId", description = "设备国标编号", required = true) | 
 |  |  |    public WVPResult<Map<String, String>> getSubscribeInfo(@PathVariable String deviceId) { | 
 |  |  |    public WVPResult<Map<String, Integer>> getSubscribeInfo(@PathVariable String deviceId) { | 
 |  |  |       Set<String> allKeys = dynamicTask.getAllKeys(); | 
 |  |  |       Map<String, String> dialogStateMap = new HashMap<>(); | 
 |  |  |       Map<String, Integer> dialogStateMap = new HashMap<>(); | 
 |  |  |       for (String key : allKeys) { | 
 |  |  |          if (key.startsWith(deviceId)) { | 
 |  |  |             ISubscribeTask subscribeTask = (ISubscribeTask)dynamicTask.get(key); | 
 |  |  |             DialogState dialogState = subscribeTask.getDialogState(); | 
 |  |  |             if (dialogState == null) { | 
 |  |  |                continue; | 
 |  |  |             } | 
 |  |  |             if (subscribeTask instanceof CatalogSubscribeTask) { | 
 |  |  |                dialogStateMap.put("catalog", dialogState.toString()); | 
 |  |  |                dialogStateMap.put("catalog", 1); | 
 |  |  |             }else if (subscribeTask instanceof MobilePositionSubscribeTask) { | 
 |  |  |                dialogStateMap.put("mobilePosition", dialogState.toString()); | 
 |  |  |                dialogStateMap.put("mobilePosition", 1); | 
 |  |  |             } | 
 |  |  |          } | 
 |  |  |       } | 
 |  |  |       WVPResult<Map<String, String>> wvpResult = new WVPResult<>(); | 
 |  |  |       WVPResult<Map<String, Integer>> wvpResult = new WVPResult<>(); | 
 |  |  |       wvpResult.setCode(0); | 
 |  |  |       wvpResult.setData(dialogStateMap); | 
 |  |  |       return wvpResult; |