SceneOfflinePackagePushServiceImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. package com.fdkankan.external.service.impl;
  2. import cn.hutool.core.bean.BeanUtil;
  3. import cn.hutool.core.collection.CollUtil;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.date.TimeInterval;
  6. import cn.hutool.core.io.FileUtil;
  7. import cn.hutool.core.lang.UUID;
  8. import cn.hutool.core.thread.ExecutorBuilder;
  9. import cn.hutool.core.util.RuntimeUtil;
  10. import cn.hutool.core.util.StrUtil;
  11. import cn.hutool.core.util.ZipUtil;
  12. import cn.hutool.http.HttpUtil;
  13. import com.alibaba.fastjson.JSON;
  14. import com.alibaba.fastjson.JSONObject;
  15. import com.fdkankan.common.constant.CommonStatus;
  16. import com.fdkankan.common.constant.CommonSuccessStatus;
  17. import com.fdkankan.common.constant.FileSizeUnitType;
  18. import com.fdkankan.common.constant.SceneSource;
  19. import com.fdkankan.common.util.DateExtUtil;
  20. import com.fdkankan.common.util.FileSizeUtil;
  21. import com.fdkankan.external.bean.DownloadProcessBean;
  22. import com.fdkankan.external.bean.LaserDownloadBean;
  23. import com.fdkankan.external.callback.ErrorCallback;
  24. import com.fdkankan.external.callback.SuccessCallback;
  25. import com.fdkankan.external.entity.*;
  26. import com.fdkankan.external.httpclient.HttpClient;
  27. import com.fdkankan.external.mapper.SceneOfflinePackagePushMapper;
  28. import com.fdkankan.external.service.*;
  29. import com.fdkankan.external.util.CmdUtils;
  30. import com.fdkankan.redis.constant.RedisKey;
  31. import com.fdkankan.redis.util.RedisUtil;
  32. import com.fdkankan.web.response.Result;
  33. import com.fdkankan.web.response.ResultData;
  34. import com.mybatisflex.core.query.QueryWrapper;
  35. import com.mybatisflex.spring.service.impl.ServiceImpl;
  36. import lombok.extern.slf4j.Slf4j;
  37. import org.apache.commons.lang3.StringUtils;
  38. import org.springframework.beans.factory.annotation.Autowired;
  39. import org.springframework.beans.factory.annotation.Value;
  40. import org.springframework.stereotype.Service;
  41. import javax.annotation.Resource;
  42. import java.io.File;
  43. import java.nio.charset.Charset;
  44. import java.util.*;
  45. import java.util.concurrent.ThreadPoolExecutor;
  46. import java.util.stream.Collectors;
  47. /**
  48. * 场景离线包推送表 服务层实现。
  49. *
  50. * @author dsx
  51. * @since 2023-12-07
  52. */
  53. @Slf4j
  54. @Service
  55. public class SceneOfflinePackagePushServiceImpl extends ServiceImpl<SceneOfflinePackagePushMapper, SceneOfflinePackagePush> implements ISceneOfflinePackagePushService {
  56. @Value("${host.4dkk.scene}")
  57. private String fdkkSceneHost;
  58. @Value("${host.laser}")
  59. private String laserHost;
  60. @Value("${oss.host.laser.old}")
  61. private String ossHostLaserOld;
  62. @Value("${oss.host.laser.new}")
  63. private String ossHostLaserNew;
  64. @Value("${oss.host.4dkk.old}")
  65. private String ossHost4dkkOld;
  66. @Value("${oss.host.4dkk.new}")
  67. private String ossHost4dkkNew;
  68. @Value("${api.4dkk.scene.getInfo}")
  69. private String getInfoUrl;
  70. @Value("${api.laser.downOfflineScene}")
  71. private String downOfflineSceneUrl;
  72. @Value("${file.offlineZip.dir}")
  73. private String offlineZipDir;
  74. private final static ThreadPoolExecutor threadPoolExecutor = ExecutorBuilder.create().setCorePoolSize(1).setMaxPoolSize(3).build();
  75. @Autowired
  76. private IDepartmentService departmentService;
  77. @Autowired
  78. private IDepartmentCameraService departmentCameraService;
  79. @Autowired
  80. private IScenePlusService scenePlusService;
  81. @Autowired
  82. private IScenePlusExtService scenePlusExtService;
  83. @Autowired
  84. private ISceneOfflinePackagePushService sceneOfflinePackagePushService;
  85. @Autowired
  86. private ISceneService sceneService;
  87. @Resource
  88. private HttpClient httpClient;
  89. @Autowired
  90. private ICameraService cameraService;
  91. @Resource
  92. private RedisUtil redisUtil;
  93. @Override
  94. public void scenePushScheduleHandler(String departmentCode) {
  95. Department department = departmentService.getByCode(departmentCode);
  96. if(Objects.isNull(department)){
  97. return;
  98. }
  99. List<DepartmentCamera> departmentCameraList = departmentCameraService.listByDepartmentId(department.getId());
  100. if(CollUtil.isEmpty(departmentCameraList)){
  101. return;
  102. }
  103. List<String> snCodeList = departmentCameraList.stream().map(DepartmentCamera::getSnCode).collect(Collectors.toList());
  104. List<Camera> cameras = cameraService.listBySnCodeList(snCodeList);
  105. if(CollUtil.isEmpty(cameras)){
  106. return;
  107. }
  108. Map<Long, String> snCodeMap = cameras.stream().collect(Collectors.toMap(Camera::getId, Camera::getSnCode));
  109. List<Long> cameraIdList = cameras.stream().map(Camera::getId).collect(Collectors.toList());
  110. List<ScenePlus> scenePlusList = scenePlusService.listByCameraIdList(cameraIdList);
  111. if(CollUtil.isEmpty(scenePlusList)){
  112. return;
  113. }
  114. SceneOfflinePackagePush condition =
  115. SceneOfflinePackagePush.builder()
  116. .departmentId(department.getId())
  117. .pushStatus(CommonSuccessStatus.SUCCESS.code())
  118. .build();
  119. for (ScenePlus scenePlus : scenePlusList) {
  120. try {
  121. condition.setNum(scenePlus.getNum());
  122. SceneOfflinePackagePush commonPush =
  123. SceneOfflinePackagePush.builder()
  124. .departmentId(department.getId())
  125. .destUrl(department.getDestUrl())
  126. .storageType("oss")
  127. .snCode(snCodeMap.get(scenePlus.getCameraId()))
  128. .num(scenePlus.getNum()).build();
  129. ScenePlusExt scenePlusExt = null;
  130. //点云场景推送
  131. int isObj = CommonStatus.NO.code();
  132. if(scenePlus.getSceneSource() == SceneSource.JG.code() || scenePlus.getSceneSource() == SceneSource.SG.code()){
  133. condition.setZipType("laser");
  134. SceneOfflinePackagePush lastPush = sceneOfflinePackagePushService.getLastByCondition(condition);
  135. Scene scene = sceneService.getBySceneCode(scenePlus.getNum());
  136. if(Objects.isNull(scene)){
  137. throw new RuntimeException("未查询到激光系统场景信息,场景码:" + scenePlus.getNum());
  138. }
  139. //如果没有推送过或者推送过但是版本号不一致,就需要推送
  140. if(Objects.isNull(lastPush) || lastPush.getVersion() != scene.getOfflineVerForPush()){
  141. // threadPoolExecutor.submit(()->{
  142. SceneOfflinePackagePush push = BeanUtil.copyProperties(commonPush, SceneOfflinePackagePush.class);
  143. push.setZipType("laser");
  144. push.setVersion(scene.getOfflineVerForPush());
  145. try {
  146. sceneOfflinePackagePushService.scenePushHandler(push);
  147. }catch (Exception e){
  148. log.error("场景推送失败,num:{}",scenePlus.getNum(), e);
  149. }
  150. // });
  151. }
  152. scenePlusExt = scenePlusExtService.getByPlusId(scenePlus.getId());
  153. isObj = scenePlusExt.getIsObj();
  154. }
  155. //看看场景推送
  156. if(scenePlus.getSceneSource() == SceneSource.BM.code()
  157. || scenePlus.getSceneSource() == SceneSource.ZT.code()
  158. || isObj == CommonStatus.YES.code()){
  159. condition.setZipType("kankan");
  160. SceneOfflinePackagePush lastPush = sceneOfflinePackagePushService.getLastByCondition(condition);
  161. //查询版本号
  162. String getInfo = fdkkSceneHost.concat(String.format(getInfoUrl, scenePlus.getNum()));
  163. ResultData<Map<String, Object>> mapResultData = httpClient.get(getInfo, new HashMap<>(), new SuccessCallback(), new ErrorCallback());
  164. int version = (int)mapResultData.getData().get("version");
  165. //如果没有推送过或者推送过但是版本号不一致,就需要推送
  166. if(Objects.isNull(lastPush) || lastPush.getVersion() != version){
  167. // threadPoolExecutor.submit(()->{
  168. SceneOfflinePackagePush push = BeanUtil.copyProperties(commonPush, SceneOfflinePackagePush.class);
  169. push.setZipType("kankan");
  170. push.setVersion(version);
  171. try {
  172. sceneOfflinePackagePushService.scenePushHandler(push);
  173. }catch (Exception e){
  174. log.error("场景推送失败,num:{}",scenePlus.getNum(), e);
  175. }
  176. // });
  177. }
  178. }
  179. }catch (Exception e){
  180. log.error("场景推送失败,num:{}",scenePlus.getNum(), e);
  181. }
  182. }
  183. }
  184. private String genZipUrl4Kankan(String num){
  185. String downloadUrl = null;
  186. String downloadTaskKey = RedisKey.SCENE_DOWNLOADS_TASK_V4;
  187. String progressKey = String.format(RedisKey.PREFIX_DOWNLOAD_PROGRESS_V4, num);
  188. TimeInterval timer = DateUtil.timer();
  189. Map<String,String> playod = new HashMap<>(2);
  190. playod.put("type","local");
  191. playod.put("num",num);
  192. redisUtil.lRightPush(downloadTaskKey, JSONObject.toJSONString(playod));
  193. boolean exit = false;
  194. String progress = null;
  195. DownloadProcessBean downloadProcessBean = null;
  196. do {
  197. progress = redisUtil.get(progressKey);
  198. if(StringUtils.isEmpty(progress)){
  199. downloadProcessBean = new DownloadProcessBean();
  200. }else{
  201. downloadProcessBean = JSONObject.parseObject(progress, DownloadProcessBean.class);
  202. }
  203. Integer status = downloadProcessBean.getStatus();
  204. if (Objects.nonNull(status) && status == 1002) {
  205. downloadUrl = downloadProcessBean.getUrl();
  206. exit = true;
  207. }
  208. if (Objects.nonNull(status) && status == 1003) {
  209. log.error("下载失败,num:{}", num);
  210. throw new RuntimeException("下载失败,num:" + num);
  211. }
  212. if (timer.intervalMinute() > 8 * 60) {
  213. log.error("下载超时,num:{}", num);
  214. throw new RuntimeException("下载超时,num:" + num);
  215. }
  216. try {
  217. Thread.sleep(5000L);
  218. } catch (InterruptedException e) {
  219. throw new RuntimeException(e);
  220. }
  221. } while (!exit);
  222. return downloadUrl.replace(ossHost4dkkOld, ossHost4dkkNew);
  223. }
  224. private String genZipUrl4Laser(String num){
  225. String downloadUrl = null;
  226. TimeInterval timer = DateUtil.timer();
  227. boolean exit = false;
  228. //请求激光系统开始下载
  229. Map<String, Object> params = new HashMap<>();
  230. params.put("sceneCode", num);
  231. Result<LaserDownloadBean> resultData = httpClient.downOfflineScene(laserHost.concat(downOfflineSceneUrl), params, new SuccessCallback(), new ErrorCallback());
  232. LaserDownloadBean laserRes = resultData.getData();
  233. if(laserRes.getStatus() == 2){
  234. return laserRes.getUrl().replace(ossHostLaserOld, ossHostLaserNew);
  235. }
  236. do {
  237. resultData = httpClient.downOfflineScene(laserHost.concat(downOfflineSceneUrl), params, new SuccessCallback(), new ErrorCallback());
  238. laserRes = resultData.getData();
  239. Integer status = laserRes.getStatus();
  240. if (Objects.nonNull(status) && status == 2) {
  241. downloadUrl = laserRes.getUrl();
  242. exit = true;
  243. }
  244. if (Objects.nonNull(status) && status == -1) {
  245. log.error("下载失败,num:{}", num);
  246. throw new RuntimeException("下载失败,num:" + num);
  247. }
  248. if (timer.intervalMinute() > 8 * 60) {
  249. log.error("下载超时,num:{}", num);
  250. throw new RuntimeException("下载超时,num:" + num);
  251. }
  252. try {
  253. Thread.sleep(5000L);
  254. } catch (InterruptedException e) {
  255. throw new RuntimeException(e);
  256. }
  257. } while (!exit);
  258. return downloadUrl.replace(ossHostLaserOld, ossHostLaserNew);
  259. }
  260. @Override
  261. public SceneOfflinePackagePush getLastByCondition(SceneOfflinePackagePush condition) {
  262. QueryWrapper wrapper = new QueryWrapper();
  263. wrapper.eq(SceneOfflinePackagePush::getDepartmentId, condition.getDepartmentId());
  264. wrapper.eq(SceneOfflinePackagePush::getNum, condition.getNum());
  265. wrapper.orderBy(SceneOfflinePackagePush::getId, false);
  266. wrapper.limit(1);
  267. if(StrUtil.isNotEmpty(condition.getZipType())){
  268. wrapper.eq(SceneOfflinePackagePush::getZipType, condition.getZipType());
  269. }
  270. if(Objects.nonNull(condition.getPushStatus())){
  271. wrapper.eq(SceneOfflinePackagePush::getPushStatus, condition.getPushStatus());
  272. }
  273. return this.getOne(wrapper);
  274. }
  275. @Override
  276. public void scenePushHandler(SceneOfflinePackagePush push){
  277. String num = push.getNum();
  278. String zipType = push.getZipType();
  279. int version = push.getVersion();
  280. String downloadUrl = null;
  281. try {
  282. if("laser".equals(zipType)){
  283. downloadUrl = this.genZipUrl4Laser(num);
  284. }else{
  285. downloadUrl = this.genZipUrl4Kankan(num);
  286. }
  287. //开始推送到第三方服务
  288. if(StrUtil.isEmpty(downloadUrl)){
  289. throw new RuntimeException("场景下载失败,下载链接为空,场景码:" + num);
  290. }
  291. //下载到本地
  292. String zipPath = offlineZipDir.concat(num).concat(".zip");
  293. HttpUtil.downloadFile(downloadUrl, zipPath);
  294. String dirPath = null;
  295. String unzipPath = offlineZipDir.concat(num).concat("-").concat(zipType).concat("-").concat(String.valueOf(version));
  296. ZipUtil.unzip(zipPath, unzipPath, Charset.forName("GBK"));
  297. if("laser".equals(zipType)){
  298. dirPath = unzipPath.concat("/www");
  299. }else{
  300. dirPath = unzipPath.concat("/wwwroot/scene_view_data");
  301. }
  302. String zipDir = dirPath.concat("/zip/");
  303. FileUtil.del(zipDir);
  304. String volumeName = zipDir.concat(num).concat(".zip");
  305. FileUtil.mkParentDirs(volumeName);
  306. String cmd = "cd " + dirPath + " && zip -r " + volumeName + " " + num + " -s 100M";
  307. log.info("压缩命令:{}", cmd);
  308. CmdUtils.callLineSh(cmd, 200);
  309. List<String> fileList = FileUtil.listFileNames(zipDir);
  310. if(CollUtil.isEmpty(fileList)){
  311. throw new RuntimeException("压缩包不存在");
  312. }
  313. String id = UUID.fastUUID().toString();
  314. for (String file : fileList) {
  315. Map<String, Object> params = new HashMap<>();
  316. params.put("id", id);
  317. params.put("action", "upload");
  318. params.put("fileName", file);
  319. params.put("file", FileUtil.file(zipDir.concat(file)));
  320. String post = HttpUtil.post(push.getDestUrl(), params, 60 * 60 * 1000);
  321. log.info("场景推送成功,接收端返回结果:{}", post);
  322. }
  323. ScenePlus scenePlus = scenePlusService.getByNum(num);
  324. ScenePlusExt scenePlusExt = scenePlusExtService.getByPlusId(scenePlus.getId());
  325. String title = scenePlus.getTitle();
  326. if("laser".equals(zipType)){
  327. Scene scene = sceneService.getBySceneCode(scenePlus.getNum());
  328. title = scene.getTitle();
  329. }
  330. Map<String, Object> params = new HashMap<>();
  331. params.put("id", id);
  332. params.put("action", "save");
  333. params.put("fileName", num.concat(".zip"));
  334. params.put("num", num);
  335. params.put("title", title);
  336. params.put("zipType", zipType);
  337. params.put("downloadUrl", downloadUrl);
  338. params.put("version", push.getVersion());
  339. params.put("calcTime", DateExtUtil.format(scenePlusExt.getAlgorithmTime(), DateExtUtil.dateStyle8));
  340. String post = HttpUtil.post(push.getDestUrl(), params, 60 * 60 * 1000);
  341. log.info("场景推送成功,接收端返回结果:{}", post);
  342. push.setPushStatus(CommonSuccessStatus.SUCCESS.code());
  343. }catch (Exception e){
  344. log.error("场景推送失败,num:{}", num, e);
  345. push.setPushStatus(CommonSuccessStatus.FAIL.code());
  346. }
  347. this.saveOrUpdate(push);
  348. }
  349. public static void main(String[] args) throws Exception {
  350. // Map<String, Object> params = new HashMap<>();
  351. // params.put("num", "KJ-t-WypZvHxCR4X");
  352. // params.put("title", "123");
  353. // params.put("zipType", "kankan");
  354. // params.put("version", 1);
  355. // params.put("calcTime", DateExtUtil.format(new Date(), DateExtUtil.dateStyle8));
  356. // params.put("file", FileUtil.file("D:\\mnt\\external\\temp\\KJ-t-WypZvHxCR4X.zip"));
  357. // final String post = HttpUtil.post("http://localhost:8080/scene/receive2", params, 60 * 60 * 1000);
  358. // System.out.println(post);
  359. }
  360. }