|
@@ -0,0 +1,299 @@
|
|
|
+package com.sooka.sponest.monitor.dahua.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.druid.support.json.JSONUtils;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.nacos.shaded.com.google.gson.Gson;
|
|
|
+import com.dahuatech.hutool.core.codec.Base64;
|
|
|
+import com.dahuatech.hutool.core.io.FileUtil;
|
|
|
+import com.dahuatech.hutool.core.io.StreamProgress;
|
|
|
+import com.dahuatech.hutool.http.HttpUtil;
|
|
|
+import com.dahuatech.hutool.http.Method;
|
|
|
+import com.dahuatech.hutool.json.JSONArray;
|
|
|
+import com.dahuatech.hutool.json.JSONObject;
|
|
|
+import com.dahuatech.hutool.json.JSONUtil;
|
|
|
+import com.dahuatech.icc.exception.ClientException;
|
|
|
+import com.dahuatech.icc.oauth.http.IccHttpHttpRequest;
|
|
|
+import com.dahuatech.icc.oauth.http.IccTokenResponse;
|
|
|
+import com.dahuatech.icc.util.BeanUtil;
|
|
|
+import com.ruoyi.common.core.constant.HttpStatus;
|
|
|
+import com.ruoyi.common.core.domain.R;
|
|
|
+import com.ruoyi.common.core.utils.DateUtils;
|
|
|
+import com.ruoyi.common.core.utils.StringUtils;
|
|
|
+import com.ruoyi.common.core.web.domain.AjaxResult;
|
|
|
+import com.ruoyi.common.redis.service.RedisService;
|
|
|
+import com.ruoyi.system.api.domain.SysFile;
|
|
|
+import com.sooka.sponest.monitor.base.service.impl.BaseService;
|
|
|
+import com.sooka.sponest.monitor.camera.domain.CentermonitorTCamera;
|
|
|
+import com.sooka.sponest.monitor.camera.mapper.CentermonitorTCameraMapper;
|
|
|
+import com.sooka.sponest.monitor.camera.service.ICentermonitorTCameraService;
|
|
|
+import com.sooka.sponest.monitor.dahua.domain.CenterdataTAttach;
|
|
|
+import com.sooka.sponest.monitor.dahua.domain.PlayBackProperties;
|
|
|
+import com.sooka.sponest.monitor.dahua.service.DahuaService;
|
|
|
+import com.sooka.sponest.monitor.dahua.utils.HttpEnum;
|
|
|
+import com.sooka.sponest.monitor.dahua.utils.HttpTestUtils;
|
|
|
+import com.sooka.sponest.monitor.remoteapi.service.data.RemoteDataBaseService;
|
|
|
+import com.sooka.sponest.monitor.remoteapi.service.event.RemoteEventBaseService;
|
|
|
+import com.sooka.sponest.monitor.remoteapi.service.event.domain.CentereventTDownloads;
|
|
|
+import com.sooka.sponest.monitor.remoteapi.service.file.RemoteFileBaseService;
|
|
|
+import com.sooka.sponest.monitor.util.Mp4ParserUtils;
|
|
|
+import org.apache.commons.collections4.CollectionUtils;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import java.io.File;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.KeyFactory;
|
|
|
+import java.security.interfaces.RSAPublicKey;
|
|
|
+import java.security.spec.X509EncodedKeySpec;
|
|
|
+import java.text.ParseException;
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class DahuaServiceImpl extends BaseService implements DahuaService {
|
|
|
+
|
|
|
+ private static org.slf4j.Logger log = LoggerFactory.getLogger(DahuaServiceImpl.class);
|
|
|
+
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private RedisService redisService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ICentermonitorTCameraService iCentermonitorTCameraService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private DahuaService dahuaService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private RemoteFileBaseService fileBaseService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private RemoteDataBaseService dataBaseService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private RemoteEventBaseService eventBaseService;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public AjaxResult getPlaybackByTime(String properties) {
|
|
|
+ log.info("**GetPlaybackByTime->"+new Date()+"->start**");
|
|
|
+ List<PlayBackProperties> propertiesList = JSON.parseArray(properties, PlayBackProperties.class);
|
|
|
+ for (PlayBackProperties property: propertiesList) {
|
|
|
+ //下载并上传视频
|
|
|
+ AjaxResult ajaxResult = getPlaybackByTime(property);
|
|
|
+ //将视频下载结果保存至事件中心
|
|
|
+ CentereventTDownloads downloads = new CentereventTDownloads();
|
|
|
+ downloads.setId(property.getId());
|
|
|
+ if (Integer.parseInt(ajaxResult.get("code").toString()) == HttpStatus.SUCCESS) {
|
|
|
+ downloads.setPath(ajaxResult.get("data").toString());
|
|
|
+ }
|
|
|
+ downloads.setFlag(ajaxResult.get("code").toString());
|
|
|
+ downloads.setReason(ajaxResult.get("msg").toString());
|
|
|
+ eventBaseService.downloads(downloads);
|
|
|
+ }
|
|
|
+ log.info("**GetPlaybackByTime->"+new Date()+"->end**");
|
|
|
+ return AjaxResult.success();
|
|
|
+ }
|
|
|
+
|
|
|
+ public AjaxResult getPlaybackByTime(PlayBackProperties playBackProperties) {
|
|
|
+ AjaxResult ajaxResult = new AjaxResult();
|
|
|
+ CentermonitorTCamera camera = iCentermonitorTCameraService.selectCentermonitorTCameraById(playBackProperties.getCameraId());
|
|
|
+ if (camera == null) {
|
|
|
+ return new AjaxResult(HttpStatus.ACCEPTED, "未查询到该摄像头");
|
|
|
+ } else if (camera.getChannelNum().isEmpty()) {
|
|
|
+ return new AjaxResult(HttpStatus.ACCEPTED, "未查询到该摄像头通道编号");
|
|
|
+ }
|
|
|
+ //开始时间
|
|
|
+ Long startTimeStamp = dahuaService.getTimeSeconds(playBackProperties.getStartTime());
|
|
|
+ //结束时间
|
|
|
+ Long endTimeStamp = dahuaService.getTimeSeconds(playBackProperties.getEndTime());
|
|
|
+ //录像请求地址
|
|
|
+ String QUERY_RECORDS_URL = host + "/evo-apigw/admin/API/SS/Record/QueryRecords";
|
|
|
+ //获取大华token
|
|
|
+ String token = dahuaService.getToken();
|
|
|
+ //构造请求参数
|
|
|
+ Map<String, Object> param = new HashMap<>();
|
|
|
+ Map<String, Object> data = new HashMap<>();
|
|
|
+ data.put("channelId", camera.getChannelNum());
|
|
|
+ data.put("recordSource", "3");
|
|
|
+ data.put("startTime", startTimeStamp);
|
|
|
+ data.put("endTime", endTimeStamp);
|
|
|
+ data.put("recordType", "0");
|
|
|
+ data.put("streamType", "1");
|
|
|
+ param.put("data", data);
|
|
|
+ //请求大华服务器查询录像
|
|
|
+ log.info("getPlaybackByTime-查询大华录像、");
|
|
|
+ JSONObject QueryRecordsResult = dahuaService.IccHttpHttpRequest(QUERY_RECORDS_URL, Method.POST, JSONUtil.toJsonStr(param), token, "QueryRecords");
|
|
|
+ //处理返回值
|
|
|
+ if (QueryRecordsResult.get("code") != null && QueryRecordsResult.get("code").toString().equals("1000")) {
|
|
|
+ //未查询到录像
|
|
|
+ if (QueryRecordsResult.getJSONObject("data") != null && QueryRecordsResult.getJSONObject("data").getJSONArray("records").isEmpty()) {
|
|
|
+ log.info("getPlaybackByTime-查询大华录像-result => {}", "该时段未查询到录像信息");
|
|
|
+ return new AjaxResult(HttpStatus.ACCEPTED, "该时段未查询到录像信息");
|
|
|
+ //查询到路线
|
|
|
+ } else {
|
|
|
+ List<String> fileNames = new ArrayList<>();
|
|
|
+ String dssFileDownloadUrl = dahuaService.isWindows() ? videoDownloadUrlWin : videoDownloadUrlLinux;
|
|
|
+ JSONArray records = QueryRecordsResult.getJSONObject("data").getJSONArray("records");
|
|
|
+ for (Object record : records) {
|
|
|
+ JSONObject jsonObject = JSONUtil.parseObj(record);
|
|
|
+ String url = host + "/download/vod/cam/download.mp4";
|
|
|
+ url += "?vcuid=" + camera.getChannelNum().split("\\$")[0] + "%240";
|
|
|
+ url += "&subtype=1";
|
|
|
+ url += "&starttime=" + dahuaService.secondsToFormat(Long.parseLong(jsonObject.getStr("startTime")));
|
|
|
+ url += "&endtime=" + dahuaService.secondsToFormat(Long.parseLong(jsonObject.getStr("endTime")));
|
|
|
+ url += "&videoType=3";//videoType 2:设备录像 3:平台录像
|
|
|
+ url += "&substream=1";//substream 码流类型:1:主码流;2:辅码流
|
|
|
+ url += "&token=1:" + token;
|
|
|
+ url += "&recordType=1";
|
|
|
+ String fileName = dssFileDownloadUrl + System.currentTimeMillis() + ".mp4";
|
|
|
+ //下载 录像
|
|
|
+ HttpUtil.downloadFile(url, FileUtil.file(fileName), new StreamProgress() {
|
|
|
+ @Override
|
|
|
+ public void start() {
|
|
|
+ log.info("getPlaybackByTime logId={} => 开始下载", playBackProperties.getLogId());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void progress(long progressSize) {
|
|
|
+// log.info("getPlaybackByTime => 已下载:{}", FileUtil.readableFileSize(progressSize));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void finish() {
|
|
|
+ log.info("getPlaybackByTime logId={} => 下载完成!", playBackProperties.getLogId());
|
|
|
+ fileNames.add(fileName);
|
|
|
+
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ File file;
|
|
|
+ //如果有多个视频 则合并视频并上传合并后的视频
|
|
|
+ if (fileNames.size() > 1) {
|
|
|
+ //合并本地下载的视频
|
|
|
+ String fileName = dssFileDownloadUrl + System.currentTimeMillis() + ".mp4";
|
|
|
+ file = new File(fileName);
|
|
|
+ Mp4ParserUtils.mergeVideo(fileNames, file);
|
|
|
+ } else {
|
|
|
+ file = new File(fileNames.get(0));
|
|
|
+ }
|
|
|
+ //文件上传到文件服务器
|
|
|
+ R<SysFile> sysFileR = fileBaseService.upload(Mp4ParserUtils.getMultipartFile(file));
|
|
|
+ if (sysFileR.getCode() == 200) {
|
|
|
+ log.info("getPlaybackByTime => 文件上传成功!{}", sysFileR.getData().getUrl());
|
|
|
+ //保存到数据中心
|
|
|
+ CenterdataTAttach attach = new CenterdataTAttach();
|
|
|
+ attach.setBusId(playBackProperties.getLogId());
|
|
|
+ attach.setAttachPath(sysFileR.getData().getUrl());
|
|
|
+ attach.setFileName(sysFileR.getData().getName());
|
|
|
+ attach.setBusSource("PC");
|
|
|
+ attach.setFileType("video");
|
|
|
+ dataBaseService.insertAttach(attach);
|
|
|
+ //清空文件夹
|
|
|
+ File folder = new File(dssFileDownloadUrl);
|
|
|
+ File[] files = folder.listFiles();
|
|
|
+ if (files != null){
|
|
|
+ for (File f : files) {
|
|
|
+ boolean b = f.delete();
|
|
|
+ if(!b) log.error("getPlaybackByTime => 文件删除失败!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("getPlaybackByTime => 文件上传失败!{}", sysFileR.getMsg());
|
|
|
+ }
|
|
|
+ return AjaxResult.success("文件下载成功", sysFileR.getData().getUrl());
|
|
|
+ }
|
|
|
+ }else {
|
|
|
+ log.error("getPlaybackByTime-查询大华录像-{}, result => {}", "录像回放接口报错", JSONUtil.toJsonStr(QueryRecordsResult));
|
|
|
+ return AjaxResult.error("录像回放接口报错", QueryRecordsResult.getStr("desc"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public Long getTimeSeconds(String time) {
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
|
|
+ long timeStamp = 0;
|
|
|
+ try {
|
|
|
+ Date date = simpleDateFormat.parse(time);
|
|
|
+ timeStamp = date.getTime() / 1000L;
|
|
|
+ } catch (ParseException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return timeStamp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取token
|
|
|
+ */
|
|
|
+ public String getToken() {
|
|
|
+ //如果缓存里有 用缓存的,没有就重新获取
|
|
|
+ String token = redisService.getCacheObject("DH_TOKEN");
|
|
|
+ if (token != null) {
|
|
|
+ return token;
|
|
|
+ }
|
|
|
+ String TOKEN_URL = host + "/evo-apigw/evo-oauth/" + version + "/oauth/extend/token";
|
|
|
+ try {
|
|
|
+ log.info("----开始执行----{}------请求地址:{}", "客户端模式_认证申请", TOKEN_URL);
|
|
|
+ Map<String, Object> map = new HashMap();
|
|
|
+ map.put("grant_type", "client_credentials");
|
|
|
+ map.put("client_id", client_id);
|
|
|
+ map.put("client_secret", client_secret);
|
|
|
+ IccHttpHttpRequest pr = new IccHttpHttpRequest(TOKEN_URL, Method.POST, JSONUtil.toJsonStr(map));
|
|
|
+ String prBody = pr.execute();
|
|
|
+ IccTokenResponse keyResp = BeanUtil.toBean(prBody, IccTokenResponse.class);
|
|
|
+ log.info("----结束执行----{}------返回报文:{}", "客户端模式_认证申请", keyResp);
|
|
|
+ token = keyResp.getData().getAccess_token();
|
|
|
+ redisService.setCacheObject("DH_TOKEN", token);
|
|
|
+ //token 有效期1小时59分
|
|
|
+ redisService.expire("DH_TOKEN", 60 * 60 * 2 - 60);
|
|
|
+ return token;
|
|
|
+ } catch (Exception e) {
|
|
|
+ return token;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public JSONObject IccHttpHttpRequest(String url, Method method, String param, String token, String action) {
|
|
|
+ log.info("----开始执行----{}------请求参数:{}", action, JSONUtil.toJsonStr(param));
|
|
|
+ String prBody;
|
|
|
+ IccHttpHttpRequest pr;
|
|
|
+ try {
|
|
|
+ pr = new IccHttpHttpRequest(url, method, param);
|
|
|
+ } catch (ClientException e) {
|
|
|
+ throw new RuntimeException(e);
|
|
|
+ }
|
|
|
+ pr.getHttpRequest().header("Authorization", "bearer " + token).header("User-Id", "1");
|
|
|
+ prBody = pr.execute();
|
|
|
+ log.info("----结束执行----{}------返回报文:{}", action, prBody);
|
|
|
+ JSONObject result = JSONUtil.parseObj(prBody);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 判断操作系统是否是 Windows
|
|
|
+ *
|
|
|
+ * @return true:操作系统是 Windows
|
|
|
+ * false:其它操作系统
|
|
|
+ */
|
|
|
+ public boolean isWindows() {
|
|
|
+ String osName = getOsName();
|
|
|
+ return osName != null && osName.startsWith("Windows");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取操作系统名称
|
|
|
+ *
|
|
|
+ * @return os.name 属性值
|
|
|
+ */
|
|
|
+ public static String getOsName() {
|
|
|
+ return System.getProperty("os.name");
|
|
|
+ }
|
|
|
+
|
|
|
+ public String secondsToFormat(Long seconds) {
|
|
|
+ Date d = new Date();
|
|
|
+ d.setTime(seconds * 1000);
|
|
|
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_M_d_HH_mm_ss");
|
|
|
+ return simpleDateFormat.format(d);
|
|
|
+ }
|
|
|
+}
|