|
@@ -1,462 +1,474 @@
|
|
|
-//package com.fdkankan.modeling.receiver;
|
|
|
-//
|
|
|
-//import cn.hutool.core.collection.CollUtil;
|
|
|
-//import cn.hutool.core.io.FileUtil;
|
|
|
-//import cn.hutool.core.io.watch.WatchMonitor;
|
|
|
-//import cn.hutool.core.io.watch.Watcher;
|
|
|
-//import cn.hutool.core.lang.Console;
|
|
|
-//import cn.hutool.core.util.ObjectUtil;
|
|
|
-//import cn.hutool.core.util.StrUtil;
|
|
|
-//import com.alibaba.fastjson.JSON;
|
|
|
-//import com.alibaba.fastjson.JSONArray;
|
|
|
-//import com.alibaba.fastjson.JSONObject;
|
|
|
-//import com.fdkankan.common.constant.CommonOperStatus;
|
|
|
-//import com.fdkankan.common.constant.ModelingBuildStatus;
|
|
|
-//import com.fdkankan.common.util.CmdUtils;
|
|
|
-//import com.fdkankan.common.util.FileUtils;
|
|
|
-//import com.fdkankan.model.constants.ConstantFilePath;
|
|
|
-//import com.fdkankan.model.utils.ComputerUtil;
|
|
|
-//import com.fdkankan.model.utils.CreateObjUtil;
|
|
|
-//import com.fdkankan.modeling.bean.BuildSceneResultBean;
|
|
|
-//import com.fdkankan.modeling.constants.CmdConstant;
|
|
|
-//import com.fdkankan.modeling.constants.SysConstants;
|
|
|
-//import com.fdkankan.modeling.entity.BuildLog;
|
|
|
-//import com.fdkankan.modeling.exception.BuildException;
|
|
|
-//import com.fdkankan.modeling.handler.LaserSceneObjGenerateHandler;
|
|
|
-//import com.fdkankan.modeling.service.IBuildLogService;
|
|
|
-//import com.fdkankan.modeling.service.IBuildService;
|
|
|
-//import com.fdkankan.modeling.service.ISceneBuildProcessLogService;
|
|
|
-//import com.fdkankan.rabbitmq.bean.BuildSceneCallMessage;
|
|
|
-//import com.fdkankan.rabbitmq.bean.BuildSceneProcessLogMessage;
|
|
|
-//import com.fdkankan.rabbitmq.bean.BuildSceneResultMqMessage;
|
|
|
-//import com.fdkankan.rabbitmq.util.RabbitMqProducer;
|
|
|
-//import com.fdkankan.redis.util.RedisLockUtil;
|
|
|
-//import com.fdkankan.redis.util.RedisUtil;
|
|
|
-//import com.rabbitmq.client.Channel;
|
|
|
-//import com.fdkankan.model.constants.SceneBuildProcessType;
|
|
|
-//import lombok.extern.slf4j.Slf4j;
|
|
|
-//import org.apache.commons.lang3.StringUtils;
|
|
|
-//import org.apache.commons.lang3.time.StopWatch;
|
|
|
-//import org.springframework.amqp.core.Message;
|
|
|
-//import org.springframework.amqp.rabbit.annotation.Queue;
|
|
|
-//import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|
|
-//import org.springframework.beans.factory.annotation.Autowired;
|
|
|
-//import org.springframework.beans.factory.annotation.Value;
|
|
|
-//import org.springframework.stereotype.Component;
|
|
|
-//import org.springframework.util.ObjectUtils;
|
|
|
-//import java.io.File;
|
|
|
-//import java.nio.charset.StandardCharsets;
|
|
|
-//import java.nio.file.Path;
|
|
|
-//import java.nio.file.WatchEvent;
|
|
|
-//import java.util.*;
|
|
|
-//import java.util.concurrent.Future;
|
|
|
-//import java.util.concurrent.TimeUnit;
|
|
|
-//import java.util.concurrent.TimeoutException;
|
|
|
-//
|
|
|
-///**
|
|
|
-// * <p>
|
|
|
-// * TODO
|
|
|
-// * </p>
|
|
|
-// *
|
|
|
-// * @author dengsixing
|
|
|
-// * @since 2022/4/20
|
|
|
-// **/
|
|
|
-//@Slf4j
|
|
|
-//@Component
|
|
|
-//public class RabbitMqListener {
|
|
|
-//
|
|
|
-// @Value("${queue.modeling.modeling-call}")
|
|
|
-// private String queueModelingCall;
|
|
|
-// @Value("${queue.modeling.modeling-post}")
|
|
|
-// private String queueModelingPost;
|
|
|
-// @Value("${queue.modeling.modeling-process-log}")
|
|
|
-// private String queueModelingProcessLog;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private RedisUtil redisUtil;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private RedisLockUtil redisLockUtil;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private RabbitMqProducer rabbitMqProducer;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private IBuildLogService buildLogService;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private LaserSceneObjGenerateHandler laserSceneObjGenerateHandler;
|
|
|
-// @Autowired
|
|
|
-// private ISceneBuildProcessLogService sceneBuildProcessLogService;
|
|
|
-//
|
|
|
-// @Autowired
|
|
|
-// private IBuildService buildService;
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 场景计算
|
|
|
-// * @param channel
|
|
|
-// * @param message
|
|
|
-// * @throws Exception
|
|
|
-// */
|
|
|
-// @RabbitListener(
|
|
|
-// queuesToDeclare = @Queue("${queue.modeling.modeling-call}"),
|
|
|
-// concurrency = "${maxThread.modeling.modeling-call}",
|
|
|
-// priority = "${mq.consumerPriority}"
|
|
|
-// )
|
|
|
-// public void buildSceneHandler(Channel channel, Message message) throws Exception {
|
|
|
-// SysConstants.SYSTEM_BUILDING = true;
|
|
|
-// long deliveryTag = message.getMessageProperties().getDeliveryTag();
|
|
|
-// if (SysConstants.SYSTEM_OFFING) {
|
|
|
-// SysConstants.SYSTEM_BUILDING = false;
|
|
|
-// channel.basicNack(deliveryTag, true, true);
|
|
|
-// log.error("服务实例:{} 正在关闭,退出构建!", SysConstants.hostName);
|
|
|
-// return;
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (ObjectUtils.isEmpty(message.getBody())) {
|
|
|
-// SysConstants.SYSTEM_BUILDING = false;
|
|
|
-// log.error("消息内容为空,退出构建,当前服务器id:{}", SysConstants.hostName);
|
|
|
-// return;
|
|
|
-// }
|
|
|
-// String msg = new String(message.getBody(), StandardCharsets.UTF_8);
|
|
|
-// BuildSceneCallMessage buildSceneMessage = JSONObject.parseObject(msg, BuildSceneCallMessage.class);
|
|
|
-//
|
|
|
-// String messageId = message.getMessageProperties().getMessageId();
|
|
|
-// if(Objects.isNull(buildSceneMessage) || StrUtil.isBlank(buildSceneMessage.getSceneNum())){
|
|
|
-// log.error("消息内容错误,id:{},消息体:{}", messageId, msg);
|
|
|
-// return;
|
|
|
-// }
|
|
|
-//
|
|
|
-// BuildLog buildLog = new BuildLog();
|
|
|
-// log.info("场景计算开始,队列名:{},id:{},deliveryTag:{},消息体:{}", queueModelingCall, messageId,deliveryTag,msg);
|
|
|
-// buildLog.setMessageId(messageId);
|
|
|
-// buildLog.setContent(msg);
|
|
|
-//
|
|
|
-// this.process(buildSceneMessage,buildLog);
|
|
|
-// log.info("场景计算结束,队列名:{},id:{}", queueModelingCall, messageId);
|
|
|
-//
|
|
|
-// //计算完毕,将当前系统构建状态改为false
|
|
|
-// SysConstants.SYSTEM_BUILDING = false;
|
|
|
-//
|
|
|
-// channel.basicAck(deliveryTag, false);
|
|
|
-// }
|
|
|
-//
|
|
|
-// public void process(BuildSceneCallMessage message,BuildLog buildLog) {
|
|
|
-// //开始计时
|
|
|
-// StopWatch watch = new StopWatch();
|
|
|
-// watch.start();
|
|
|
-//
|
|
|
-// String num = message.getSceneNum();
|
|
|
-//
|
|
|
-// //发送记录计算状态为计算中
|
|
|
-// this.sendCallBuildProcessLog(message, ModelingBuildStatus.CALCULATING);
|
|
|
-//
|
|
|
-// final BuildSceneResultBean buildSceneResult = new BuildSceneResultBean();
|
|
|
-// String resultQueueName = StrUtil.isNotBlank(message.getResultReceiverMqName()) ?
|
|
|
-// message.getResultReceiverMqName() : queueModelingPost;
|
|
|
-// buildSceneResult.setResultQueueName(resultQueueName);
|
|
|
-// ModelingBuildStatus status = null;
|
|
|
-// Future<ModelingBuildStatus> future = null;
|
|
|
-// try {
|
|
|
-// Map<String,Object> buildContext = new HashMap<>();
|
|
|
-// //计算前准备
|
|
|
-// preBuild(buildContext,message, buildLog);
|
|
|
-// future = SysConstants.executorService.submit(() -> {
|
|
|
-// try {
|
|
|
-// return buildScene(buildContext,message, buildSceneResult,buildLog);
|
|
|
-// } catch (Exception e) {
|
|
|
-// log.error("服务实例:{} 构建异常:", SysConstants.hostName, e);
|
|
|
-// e.printStackTrace();
|
|
|
-// return ModelingBuildStatus.FAILED;
|
|
|
-// }
|
|
|
-// });
|
|
|
-// status = future.get(SysConstants.modelTimeOut, TimeUnit.HOURS);
|
|
|
-//
|
|
|
-// //结束计时
|
|
|
-// watch.stop();
|
|
|
-// buildLog.setDuration(watch.getTime(TimeUnit.SECONDS));
|
|
|
-// } catch (TimeoutException ex) {
|
|
|
-// log.error("服务实例:{} 构建异常:",SysConstants.hostName,ex);
|
|
|
-// status = ModelingBuildStatus.OVERTIME;
|
|
|
-// log.info("释放线程");
|
|
|
-// //场景计算超时,需要中断当前执行任务,释放线程池中的任务线程,否则下个场景计算获取不到线程进行计算
|
|
|
-// future.cancel(true);
|
|
|
-// } catch (BuildException e){
|
|
|
-// status = e.getBuildStatus();
|
|
|
-// } catch(Exception e) {
|
|
|
-// log.error("服务实例:{} 构建异常:", SysConstants.hostName, e);
|
|
|
-// if (e.getCause() instanceof BuildException) {
|
|
|
-// status = ((BuildException) e.getCause()).getBuildStatus();
|
|
|
-// buildLog.setStatus(((BuildException) e.getCause()).getBuildStatus().code());
|
|
|
-// } else {
|
|
|
-// status = ModelingBuildStatus.FAILED;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// buildLog.setStatus(status.code());
|
|
|
-// buildSceneResult.setCameraType(message.getCameraType());
|
|
|
-// buildSceneResult.setBuildStatus(status);
|
|
|
-// //计算后处理
|
|
|
-// afterBuild(message, buildSceneResult, buildLog);
|
|
|
-//
|
|
|
-// }
|
|
|
-//
|
|
|
-// private ModelingBuildStatus buildScene(Map<String,Object> buildContext,BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult,BuildLog logRecord) throws Exception{
|
|
|
-// //如果mq生产者在消息体中设置了结算结果mq队列名,就发到这个队列,否则就发送到默认队列
|
|
|
-// String path = message.getPath();
|
|
|
-// String num = message.getSceneNum();
|
|
|
-// //不同的相机不同的方法
|
|
|
-// String cameraType = message.getCameraType();
|
|
|
-// String algorithm = message.getAlgorithm();
|
|
|
-// //0表示有4k图,1表示没有
|
|
|
-// String resolution = message.getResolution();
|
|
|
-// //判断调用V2还是V3版本的算法
|
|
|
-// String buildType = ObjectUtils.isEmpty(message.getBuildType()) ? "V2" : message.getBuildType();
|
|
|
-//
|
|
|
-// buildSceneResult.setCameraType(cameraType);
|
|
|
-// buildSceneResult.setNum(num);
|
|
|
-// buildSceneResult.setPath(path);
|
|
|
-//
|
|
|
-// log.info("用的算法是:" + algorithm);
|
|
|
-//
|
|
|
-// String dataFdagePath = path + File.separator + "capture" +File.separator+"data.fdage";
|
|
|
-// log.info("dataFdagePath 文件路径 :{}", dataFdagePath);
|
|
|
-// String data = FileUtils.readFile(dataFdagePath);
|
|
|
-// //获取data.fdage的内容
|
|
|
-// JSONObject dataJson = new JSONObject();
|
|
|
-// if(data!=null){
|
|
|
-// dataJson = JSONObject.parseObject(data);
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (dataJson.containsKey("OnlyExportMeshObj")) {
|
|
|
-// logRecord.setBuildType(2);
|
|
|
-// Map<String, String> context = new HashMap<>();
|
|
|
-// context.put("path", path);
|
|
|
-// context.put("cameraType", cameraType);
|
|
|
-// context.put("algorithm", algorithm);
|
|
|
-// context.put("resolution", resolution);
|
|
|
-// context.put("projectNum", num);
|
|
|
-// context.put("dataJson", data);
|
|
|
-// try {
|
|
|
-// laserSceneObjGenerateHandler.handle(context);
|
|
|
-// } catch (Exception e) {
|
|
|
-// e.printStackTrace();
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 检测计算结果文件是否有生成
|
|
|
-// String resultsPath = path + File.separator + "results" + File.separator;
|
|
|
-// if (!new File(resultsPath + "upload.json").exists()) {
|
|
|
-// log.error("未检测到计算结果文件:upload.json");
|
|
|
-// return ModelingBuildStatus.FAILED;
|
|
|
-// }
|
|
|
-//
|
|
|
-// return ModelingBuildStatus.SUCCESS;
|
|
|
-// }
|
|
|
-//
|
|
|
-// Map<String, String> dataMap = buildService.getTypeString(cameraType, algorithm, resolution,dataJson);
|
|
|
-//
|
|
|
-// String splitType = dataMap.get("splitType");
|
|
|
-// String skyboxType = dataMap.get("skyboxType");
|
|
|
-//
|
|
|
-// ComputerUtil.createProjectAndDataFile(path,num, splitType, skyboxType,null,null);
|
|
|
-// //计算模型并返回需要上传oss的文件集合
|
|
|
-// ComputerUtil.computer(num, path, buildType);
|
|
|
-//
|
|
|
-// // 检测计算结果文件是否有生成
|
|
|
-// String resultsPath = path + File.separator + "results" + File.separator;
|
|
|
-// if (!new File(resultsPath + "upload.json").exists()) {
|
|
|
-// log.error("未检测到计算结果文件:upload.json");
|
|
|
-// return ModelingBuildStatus.FAILED;
|
|
|
-// }
|
|
|
-//
|
|
|
-// Object linkPanTargetListObj = message.getExt().get("linkPanTargetList");
|
|
|
-// if(Objects.nonNull(linkPanTargetListObj)){
|
|
|
-// List<String> linkPanTargetList = (List<String>) linkPanTargetListObj;
|
|
|
-// for (String target : linkPanTargetList) {
|
|
|
-// CreateObjUtil.build3dModel(target,null);
|
|
|
-//
|
|
|
-// // 检测计算结果文件是否有生成
|
|
|
-// String linkPanoResultsPath = target + File.separator + "results" + File.separator;
|
|
|
-// Thread.sleep(2000L);
|
|
|
-// if (!new File(linkPanoResultsPath + "upload.json").exists()) {
|
|
|
-// log.error("未检测到场景关联计算结果文件:upload.json, linkPanoResultsPath:{}", linkPanoResultsPath);
|
|
|
-// return ModelingBuildStatus.FAILED;
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// //平面图ai识别
|
|
|
-// buildSceneResult.setDetFloorplan(this.detFloorplan(path));
|
|
|
-//
|
|
|
-// return ModelingBuildStatus.SUCCESS;
|
|
|
-// }
|
|
|
-//
|
|
|
-// private LinkedHashMap<Integer, Boolean> detFloorplan(String path) throws Exception {
|
|
|
-// LinkedHashMap<Integer, Boolean> result = new LinkedHashMap<>();
|
|
|
-// String workDir = path + "/detFloorplan/";
|
|
|
-// if(FileUtil.exist(workDir)){
|
|
|
-// FileUtil.del(workDir);
|
|
|
-// }
|
|
|
-// String infoJsonPath = path + "/results/floorplan/info.json";
|
|
|
-// if(!FileUtil.exist(infoJsonPath)){
|
|
|
-// return result;
|
|
|
-// }
|
|
|
-//
|
|
|
-// JSONObject infoObj = JSON.parseObject(FileUtil.readUtf8String(infoJsonPath));
|
|
|
-// JSONArray floors = infoObj.getJSONArray("floors");
|
|
|
-// if(CollUtil.isEmpty(floors)){
|
|
|
-// return result;
|
|
|
-// }
|
|
|
-// for (Object o : floors) {
|
|
|
-// JSONObject floor = (JSONObject) o;
|
|
|
-// Integer subgroup = floor.getInteger("subgroup");
|
|
|
-// String detectPath = workDir + subgroup + "/detect.json";
|
|
|
-// String floorKeyPath = path + "/results/floorplan/floor_" + subgroup + ".png";
|
|
|
-// String parent = FileUtil.getParent(detectPath, 1);
|
|
|
-// FileUtil.mkdir(parent);
|
|
|
-// result.put(subgroup, false);
|
|
|
-// if(!FileUtil.exist(floorKeyPath)){
|
|
|
-// continue;
|
|
|
-// }
|
|
|
-// String cmd = CmdConstant.LAYOUT_DETECT;
|
|
|
-// cmd = cmd.replace("@in", floorKeyPath);
|
|
|
-// cmd = cmd.replace("@out", detectPath);
|
|
|
-// CmdUtils.callLine(cmd, 50);
|
|
|
-// if (ComputerUtil.checkComputeCompleted(detectPath,5, 500)) {
|
|
|
-// result.put(subgroup, true);
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// return result;
|
|
|
-// }
|
|
|
-//
|
|
|
-// public static void main(String[] args) {
|
|
|
-// File file = FileUtil.file("D:\\test\\111.txt");
|
|
|
-////这里只监听文件或目录的修改事件
|
|
|
-// WatchMonitor watchMonitor = WatchMonitor.create(file);
|
|
|
-// watchMonitor.setWatcher(new Watcher(){
|
|
|
-// @Override
|
|
|
-// public void onCreate(WatchEvent<?> event, Path currentPath) {
|
|
|
-// Object obj = event.context();
|
|
|
-// Console.log("创建:{}-> {}", currentPath, obj);
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// public void onModify(WatchEvent<?> event, Path currentPath) {
|
|
|
-// Object obj = event.context();
|
|
|
-// Console.log("修改:{}-> {}", currentPath, obj);
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// public void onDelete(WatchEvent<?> event, Path currentPath) {
|
|
|
-// Object obj = event.context();
|
|
|
-// Console.log("删除:{}-> {}", currentPath, obj);
|
|
|
-// }
|
|
|
-//
|
|
|
-// @Override
|
|
|
-// public void onOverflow(WatchEvent<?> event, Path currentPath) {
|
|
|
-// Object obj = event.context();
|
|
|
-// Console.log("Overflow:{}-> {}", currentPath, obj);
|
|
|
-// }
|
|
|
-// });
|
|
|
-// watchMonitor.start();
|
|
|
-// for (int i= 0; i< 10; i++ ){
|
|
|
-// System.out.println(i);
|
|
|
-// }
|
|
|
-//
|
|
|
-// }
|
|
|
-//
|
|
|
-// private void afterBuild(BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult, BuildLog buildLog){
|
|
|
-// ModelingBuildStatus buildStatus = null;
|
|
|
-// try {
|
|
|
-// buildStatus = buildSceneResult.getBuildStatus();
|
|
|
-// log.info("服务{} 计算结束:{},计算状态:{}", SysConstants.hostName, buildLog.getSceneNum(),buildStatus.message());
|
|
|
-// //释放锁
|
|
|
-// Long decr = redisUtil.decr(SysConstants.SCENE_BUILDING + buildLog.getSceneNum(), 1);
|
|
|
-// if (decr.compareTo(1L) < 0) {
|
|
|
-// redisUtil.del(SysConstants.SCENE_BUILDING + buildLog.getSceneNum());
|
|
|
-// }
|
|
|
-// buildLog.setUpdateTime(new Date());
|
|
|
-// buildLog.setResultQuequeName(buildSceneResult.getResultQueueName());
|
|
|
-// buildLogService.updateById(buildLog);
|
|
|
-// } catch (Exception e) {
|
|
|
-// log.error("计算后业务处理出错!", e);
|
|
|
-// }finally {
|
|
|
-// //发送计算结果mq
|
|
|
-// buildSceneResult.setDuration(buildLog.getDuration());
|
|
|
-// this.sendCallResult(message, buildSceneResult);
|
|
|
-// this.sendCallBuildProcessLog(message, buildStatus);
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 发送计算流程状态日志mq
|
|
|
-// * @param message
|
|
|
-// * @param buildStatus
|
|
|
-// */
|
|
|
-// private void sendCallBuildProcessLog(BuildSceneCallMessage message, ModelingBuildStatus buildStatus){
|
|
|
-// rabbitMqProducer.sendByWorkQueue(queueModelingProcessLog,
|
|
|
-// BuildSceneProcessLogMessage.builder().num(message.getSceneNum()).buildStatus(buildStatus.code()).build());
|
|
|
-// }
|
|
|
-//
|
|
|
-// private void preBuild(Map<String,Object> buildContext,BuildSceneCallMessage message, BuildLog buildLog) throws BuildException {
|
|
|
-//
|
|
|
-// // 初始化日志参数
|
|
|
-// buildLog.setHostName(SysConstants.hostName);
|
|
|
-// buildLog.setQueueName(queueModelingCall);
|
|
|
-// buildLog.setSceneNum(message.getSceneNum());
|
|
|
-// buildLog.setDataSource(message.getPath());
|
|
|
-// buildLog.setCreateTime(new Date());
|
|
|
-// buildLog.setUpdateTime(new Date());
|
|
|
-// buildLog.setBuildType(0);
|
|
|
-// buildLog.setStatus(0);
|
|
|
-// // 设置缓存锁
|
|
|
-// String key = SysConstants.SCENE_BUILDING + buildLog.getSceneNum();
|
|
|
-// // 如果是强制重新计算,则删除key。
|
|
|
-// if (StringUtils.equals(message.getRebuild(), "1")) {
|
|
|
-// redisUtil.del(key);
|
|
|
-// }
|
|
|
-//
|
|
|
-// // 获取缓存锁,防止重复消费
|
|
|
-// Long building = redisUtil.incr(key, 1);
|
|
|
-// buildLogService.save(buildLog);
|
|
|
-//
|
|
|
-// if(!ObjectUtils.isEmpty(buildLog.getMessageId())){
|
|
|
-// // 设置消息id幂等性,防止消息重复消费
|
|
|
-// boolean lock = redisLockUtil.lock(SysConstants.SCENE_MESSAGE_BUILDING + buildLog.getMessageId(), SysConstants.modelTimeOut * 3600);
|
|
|
-// if (!lock) {
|
|
|
-// log.error("服务:{},消息重复消费:{}", SysConstants.hostName, buildLog.getMessageId());
|
|
|
-// throw new BuildException(ModelingBuildStatus.REPEAT);
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// if (building.compareTo(1L) > 0) {
|
|
|
-// log.error("服务:{},重复构建:{},构建次数:{}", SysConstants.hostName, buildLog.getSceneNum(),building);
|
|
|
-// throw new BuildException(ModelingBuildStatus.REPEAT);
|
|
|
-// } else {
|
|
|
-// redisUtil.expire(key, Integer.toUnsignedLong(SysConstants.modelTimeOut * 3600));
|
|
|
-// }
|
|
|
-// }
|
|
|
-//
|
|
|
-// /**
|
|
|
-// * 发送计算结果
|
|
|
-// * @param message
|
|
|
-// * @param buildSceneResult
|
|
|
-// */
|
|
|
-// private void sendCallResult(BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult){
|
|
|
-// ModelingBuildStatus buildStatus = buildSceneResult.getBuildStatus();
|
|
|
-// //重复计算不需要发送mq做后置处理
|
|
|
-// if(buildStatus.equals(ModelingBuildStatus.REPEAT)){
|
|
|
-// return;
|
|
|
-// }
|
|
|
-// BuildSceneResultMqMessage buildResult = BuildSceneResultMqMessage.builder()
|
|
|
-// .buildSuccess(buildStatus.equals(ModelingBuildStatus.SUCCESS))
|
|
|
-// .computeTime(buildSceneResult.getDuration())
|
|
|
-// .path(buildSceneResult.getPath())
|
|
|
-// .hostName(SysConstants.hostName)
|
|
|
-// .build();
|
|
|
-// buildResult.setBuildContext(message.getBuildContext());
|
|
|
-// buildResult.setExt(message.getExt());
|
|
|
-// buildResult.setDetFloorplan(buildSceneResult.getDetFloorplan());
|
|
|
-// rabbitMqProducer.sendByWorkQueue(buildSceneResult.getResultQueueName(),buildResult);
|
|
|
-// }
|
|
|
-//}
|
|
|
+package com.fdkankan.modeling.receiver;
|
|
|
+
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.io.FileUtil;
|
|
|
+import cn.hutool.core.io.watch.WatchMonitor;
|
|
|
+import cn.hutool.core.io.watch.Watcher;
|
|
|
+import cn.hutool.core.lang.Console;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.fdkankan.common.constant.CommonOperStatus;
|
|
|
+import com.fdkankan.common.constant.ErrorCode;
|
|
|
+import com.fdkankan.common.constant.ModelingBuildStatus;
|
|
|
+import com.fdkankan.common.exception.BusinessException;
|
|
|
+import com.fdkankan.common.util.CmdUtils;
|
|
|
+import com.fdkankan.common.util.FileUtils;
|
|
|
+import com.fdkankan.model.constants.ConstantFilePath;
|
|
|
+import com.fdkankan.model.utils.ComputerUtil;
|
|
|
+import com.fdkankan.model.utils.CreateObjUtil;
|
|
|
+import com.fdkankan.modeling.bean.BuildSceneResultBean;
|
|
|
+import com.fdkankan.modeling.constants.CmdConstant;
|
|
|
+import com.fdkankan.modeling.constants.SysConstants;
|
|
|
+import com.fdkankan.modeling.entity.BuildLog;
|
|
|
+import com.fdkankan.modeling.exception.BuildException;
|
|
|
+import com.fdkankan.modeling.handler.LaserSceneObjGenerateHandler;
|
|
|
+import com.fdkankan.modeling.service.IBuildLogService;
|
|
|
+import com.fdkankan.modeling.service.IBuildService;
|
|
|
+import com.fdkankan.modeling.service.ISceneBuildProcessLogService;
|
|
|
+import com.fdkankan.rabbitmq.bean.BuildSceneCallMessage;
|
|
|
+import com.fdkankan.rabbitmq.bean.BuildSceneProcessLogMessage;
|
|
|
+import com.fdkankan.rabbitmq.bean.BuildSceneResultMqMessage;
|
|
|
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
|
|
|
+import com.fdkankan.redis.util.RedisLockUtil;
|
|
|
+import com.fdkankan.redis.util.RedisUtil;
|
|
|
+import com.rabbitmq.client.Channel;
|
|
|
+import com.fdkankan.model.constants.SceneBuildProcessType;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.lang3.StringUtils;
|
|
|
+import org.apache.commons.lang3.time.StopWatch;
|
|
|
+import org.springframework.amqp.core.Message;
|
|
|
+import org.springframework.amqp.rabbit.annotation.Queue;
|
|
|
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.util.ObjectUtils;
|
|
|
+import java.io.File;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.WatchEvent;
|
|
|
+import java.util.*;
|
|
|
+import java.util.concurrent.Future;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
+import java.util.concurrent.TimeoutException;
|
|
|
+
|
|
|
+/**
|
|
|
+ * <p>
|
|
|
+ * TODO
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @author dengsixing
|
|
|
+ * @since 2022/4/20
|
|
|
+ **/
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class RabbitMqListener {
|
|
|
+
|
|
|
+ @Value("${queue.modeling.modeling-call}")
|
|
|
+ private String queueModelingCall;
|
|
|
+ @Value("${queue.modeling.modeling-post}")
|
|
|
+ private String queueModelingPost;
|
|
|
+ @Value("${queue.modeling.modeling-process-log}")
|
|
|
+ private String queueModelingProcessLog;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisUtil redisUtil;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisLockUtil redisLockUtil;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RabbitMqProducer rabbitMqProducer;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IBuildLogService buildLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private LaserSceneObjGenerateHandler laserSceneObjGenerateHandler;
|
|
|
+ @Autowired
|
|
|
+ private ISceneBuildProcessLogService sceneBuildProcessLogService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private IBuildService buildService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 场景计算
|
|
|
+ * @param channel
|
|
|
+ * @param message
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ @RabbitListener(
|
|
|
+ queuesToDeclare = @Queue("${queue.modeling.modeling-call}"),
|
|
|
+ concurrency = "${maxThread.modeling.modeling-call}",
|
|
|
+ priority = "${mq.consumerPriority}"
|
|
|
+ )
|
|
|
+ public void buildSceneHandler(Channel channel, Message message) throws Exception {
|
|
|
+ SysConstants.SYSTEM_BUILDING = true;
|
|
|
+ long deliveryTag = message.getMessageProperties().getDeliveryTag();
|
|
|
+ if (SysConstants.SYSTEM_OFFING) {
|
|
|
+ SysConstants.SYSTEM_BUILDING = false;
|
|
|
+ channel.basicNack(deliveryTag, true, true);
|
|
|
+ log.error("服务实例:{} 正在关闭,退出构建!", SysConstants.hostName);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ObjectUtils.isEmpty(message.getBody())) {
|
|
|
+ SysConstants.SYSTEM_BUILDING = false;
|
|
|
+ log.error("消息内容为空,退出构建,当前服务器id:{}", SysConstants.hostName);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String msg = new String(message.getBody(), StandardCharsets.UTF_8);
|
|
|
+ BuildSceneCallMessage buildSceneMessage = JSONObject.parseObject(msg, BuildSceneCallMessage.class);
|
|
|
+
|
|
|
+ String messageId = message.getMessageProperties().getMessageId();
|
|
|
+ if(Objects.isNull(buildSceneMessage) || StrUtil.isBlank(buildSceneMessage.getSceneNum())){
|
|
|
+ log.error("消息内容错误,id:{},消息体:{}", messageId, msg);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //进入计算程序前,场景已删除,就不往下跑
|
|
|
+ if(SysConstants.interrupCallingNums.contains(buildSceneMessage.getSceneNum())){
|
|
|
+ channel.basicAck(deliveryTag, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ BuildLog buildLog = new BuildLog();
|
|
|
+ log.info("场景计算开始,队列名:{},id:{},deliveryTag:{},消息体:{}", queueModelingCall, messageId,deliveryTag,msg);
|
|
|
+ buildLog.setMessageId(messageId);
|
|
|
+ buildLog.setContent(msg);
|
|
|
+
|
|
|
+ this.process(buildSceneMessage,buildLog);
|
|
|
+ log.info("场景计算结束,队列名:{},id:{}", queueModelingCall, messageId);
|
|
|
+
|
|
|
+ //计算完毕,将当前系统构建状态改为false
|
|
|
+ SysConstants.SYSTEM_BUILDING = false;
|
|
|
+
|
|
|
+ channel.basicAck(deliveryTag, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void process(BuildSceneCallMessage message,BuildLog buildLog) {
|
|
|
+ //开始计时
|
|
|
+ StopWatch watch = new StopWatch();
|
|
|
+ watch.start();
|
|
|
+
|
|
|
+ String num = message.getSceneNum();
|
|
|
+
|
|
|
+ //发送记录计算状态为计算中
|
|
|
+ this.sendCallBuildProcessLog(message, ModelingBuildStatus.CALCULATING);
|
|
|
+
|
|
|
+ final BuildSceneResultBean buildSceneResult = new BuildSceneResultBean();
|
|
|
+ String resultQueueName = StrUtil.isNotBlank(message.getResultReceiverMqName()) ?
|
|
|
+ message.getResultReceiverMqName() : queueModelingPost;
|
|
|
+ buildSceneResult.setResultQueueName(resultQueueName);
|
|
|
+ ModelingBuildStatus status = null;
|
|
|
+ Future<ModelingBuildStatus> future = null;
|
|
|
+ try {
|
|
|
+ Map<String,Object> buildContext = new HashMap<>();
|
|
|
+ //计算前准备
|
|
|
+ preBuild(buildContext,message, buildLog);
|
|
|
+ future = SysConstants.executorService.submit(() -> {
|
|
|
+ try {
|
|
|
+ return buildScene(buildContext,message, buildSceneResult,buildLog);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("服务实例:{} 构建异常:", SysConstants.hostName, e);
|
|
|
+ return ModelingBuildStatus.FAILED;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ status = future.get(SysConstants.modelTimeOut, TimeUnit.HOURS);
|
|
|
+
|
|
|
+ //结束计时
|
|
|
+ watch.stop();
|
|
|
+ buildLog.setDuration(watch.getTime(TimeUnit.SECONDS));
|
|
|
+ } catch (TimeoutException ex) {
|
|
|
+ log.error("服务实例:{} 构建异常:",SysConstants.hostName,ex);
|
|
|
+ status = ModelingBuildStatus.OVERTIME;
|
|
|
+ log.info("释放线程");
|
|
|
+ //场景计算超时,需要中断当前执行任务,释放线程池中的任务线程,否则下个场景计算获取不到线程进行计算
|
|
|
+ future.cancel(true);
|
|
|
+ } catch (BuildException e){
|
|
|
+ status = e.getBuildStatus();
|
|
|
+ } catch(Exception e) {
|
|
|
+ log.error("服务实例:{} 构建异常:", SysConstants.hostName, e);
|
|
|
+ if (e.getCause() instanceof BuildException) {
|
|
|
+ status = ((BuildException) e.getCause()).getBuildStatus();
|
|
|
+ buildLog.setStatus(((BuildException) e.getCause()).getBuildStatus().code());
|
|
|
+ } else {
|
|
|
+ status = ModelingBuildStatus.FAILED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ buildLog.setStatus(status.code());
|
|
|
+ buildSceneResult.setCameraType(message.getCameraType());
|
|
|
+ buildSceneResult.setBuildStatus(status);
|
|
|
+ //计算后处理
|
|
|
+
|
|
|
+ afterBuild(message, buildSceneResult, buildLog);
|
|
|
+ }
|
|
|
+
|
|
|
+ private ModelingBuildStatus buildScene(Map<String,Object> buildContext,BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult,BuildLog logRecord) throws Exception{
|
|
|
+ //如果mq生产者在消息体中设置了结算结果mq队列名,就发到这个队列,否则就发送到默认队列
|
|
|
+ String path = message.getPath();
|
|
|
+ String num = message.getSceneNum();
|
|
|
+ //不同的相机不同的方法
|
|
|
+ String cameraType = message.getCameraType();
|
|
|
+ String algorithm = message.getAlgorithm();
|
|
|
+ //0表示有4k图,1表示没有
|
|
|
+ String resolution = message.getResolution();
|
|
|
+ //判断调用V2还是V3版本的算法
|
|
|
+ String buildType = ObjectUtils.isEmpty(message.getBuildType()) ? "V2" : message.getBuildType();
|
|
|
+
|
|
|
+ buildSceneResult.setCameraType(cameraType);
|
|
|
+ buildSceneResult.setNum(num);
|
|
|
+ buildSceneResult.setPath(path);
|
|
|
+
|
|
|
+ log.info("用的算法是:" + algorithm);
|
|
|
+
|
|
|
+ String dataFdagePath = path + File.separator + "capture" +File.separator+"data.fdage";
|
|
|
+ log.info("dataFdagePath 文件路径 :{}", dataFdagePath);
|
|
|
+ String data = FileUtils.readFile(dataFdagePath);
|
|
|
+ //获取data.fdage的内容
|
|
|
+ JSONObject dataJson = new JSONObject();
|
|
|
+ if(data!=null){
|
|
|
+ dataJson = JSONObject.parseObject(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dataJson.containsKey("OnlyExportMeshObj")) {
|
|
|
+ logRecord.setBuildType(2);
|
|
|
+ Map<String, String> context = new HashMap<>();
|
|
|
+ context.put("path", path);
|
|
|
+ context.put("cameraType", cameraType);
|
|
|
+ context.put("algorithm", algorithm);
|
|
|
+ context.put("resolution", resolution);
|
|
|
+ context.put("projectNum", num);
|
|
|
+ context.put("dataJson", data);
|
|
|
+ try {
|
|
|
+ laserSceneObjGenerateHandler.handle(context);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 检测计算结果文件是否有生成
|
|
|
+ String resultsPath = path + File.separator + "results" + File.separator;
|
|
|
+ if (!new File(resultsPath + "upload.json").exists()) {
|
|
|
+ log.error("未检测到计算结果文件:upload.json");
|
|
|
+ return ModelingBuildStatus.FAILED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ModelingBuildStatus.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, String> dataMap = buildService.getTypeString(cameraType, algorithm, resolution,dataJson);
|
|
|
+
|
|
|
+ String splitType = dataMap.get("splitType");
|
|
|
+ String skyboxType = dataMap.get("skyboxType");
|
|
|
+
|
|
|
+ ComputerUtil.createProjectAndDataFile(path,num, splitType, skyboxType,null,null);
|
|
|
+
|
|
|
+ //场景已删除,不启动算法进程
|
|
|
+ if(SysConstants.interrupCallingNums.contains(num)){
|
|
|
+ throw new BusinessException(ErrorCode.APP_ID_ILLEGAL);
|
|
|
+ }
|
|
|
+
|
|
|
+ //计算模型并返回需要上传oss的文件集合
|
|
|
+ ComputerUtil.computer(num, path, buildType);
|
|
|
+
|
|
|
+ // 检测计算结果文件是否有生成
|
|
|
+ String resultsPath = path + File.separator + "results" + File.separator;
|
|
|
+ if (!new File(resultsPath + "upload.json").exists()) {
|
|
|
+ log.error("未检测到计算结果文件:upload.json");
|
|
|
+ return ModelingBuildStatus.FAILED;
|
|
|
+ }
|
|
|
+
|
|
|
+ Object linkPanTargetListObj = message.getExt().get("linkPanTargetList");
|
|
|
+ if(Objects.nonNull(linkPanTargetListObj)){
|
|
|
+ List<String> linkPanTargetList = (List<String>) linkPanTargetListObj;
|
|
|
+ for (String target : linkPanTargetList) {
|
|
|
+ CreateObjUtil.build3dModel(target,null);
|
|
|
+
|
|
|
+ // 检测计算结果文件是否有生成
|
|
|
+ String linkPanoResultsPath = target + File.separator + "results" + File.separator;
|
|
|
+ Thread.sleep(2000L);
|
|
|
+ if (!new File(linkPanoResultsPath + "upload.json").exists()) {
|
|
|
+ log.error("未检测到场景关联计算结果文件:upload.json, linkPanoResultsPath:{}", linkPanoResultsPath);
|
|
|
+ return ModelingBuildStatus.FAILED;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //平面图ai识别
|
|
|
+ buildSceneResult.setDetFloorplan(this.detFloorplan(path));
|
|
|
+
|
|
|
+ return ModelingBuildStatus.SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ private LinkedHashMap<Integer, Boolean> detFloorplan(String path) throws Exception {
|
|
|
+ LinkedHashMap<Integer, Boolean> result = new LinkedHashMap<>();
|
|
|
+ String workDir = path + "/detFloorplan/";
|
|
|
+ if(FileUtil.exist(workDir)){
|
|
|
+ FileUtil.del(workDir);
|
|
|
+ }
|
|
|
+ String infoJsonPath = path + "/results/floorplan/info.json";
|
|
|
+ if(!FileUtil.exist(infoJsonPath)){
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ JSONObject infoObj = JSON.parseObject(FileUtil.readUtf8String(infoJsonPath));
|
|
|
+ JSONArray floors = infoObj.getJSONArray("floors");
|
|
|
+ if(CollUtil.isEmpty(floors)){
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ for (Object o : floors) {
|
|
|
+ JSONObject floor = (JSONObject) o;
|
|
|
+ Integer subgroup = floor.getInteger("subgroup");
|
|
|
+ String detectPath = workDir + subgroup + "/detect.json";
|
|
|
+ String floorKeyPath = path + "/results/floorplan/floor_" + subgroup + ".png";
|
|
|
+ String parent = FileUtil.getParent(detectPath, 1);
|
|
|
+ FileUtil.mkdir(parent);
|
|
|
+ result.put(subgroup, false);
|
|
|
+ if(!FileUtil.exist(floorKeyPath)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String cmd = CmdConstant.LAYOUT_DETECT;
|
|
|
+ cmd = cmd.replace("@in", floorKeyPath);
|
|
|
+ cmd = cmd.replace("@out", detectPath);
|
|
|
+ CmdUtils.callLine(cmd, 50);
|
|
|
+ if (ComputerUtil.checkComputeCompleted(detectPath,5, 500)) {
|
|
|
+ result.put(subgroup, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) {
|
|
|
+ File file = FileUtil.file("D:\\test\\111.txt");
|
|
|
+//这里只监听文件或目录的修改事件
|
|
|
+ WatchMonitor watchMonitor = WatchMonitor.create(file);
|
|
|
+ watchMonitor.setWatcher(new Watcher(){
|
|
|
+ @Override
|
|
|
+ public void onCreate(WatchEvent<?> event, Path currentPath) {
|
|
|
+ Object obj = event.context();
|
|
|
+ Console.log("创建:{}-> {}", currentPath, obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onModify(WatchEvent<?> event, Path currentPath) {
|
|
|
+ Object obj = event.context();
|
|
|
+ Console.log("修改:{}-> {}", currentPath, obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onDelete(WatchEvent<?> event, Path currentPath) {
|
|
|
+ Object obj = event.context();
|
|
|
+ Console.log("删除:{}-> {}", currentPath, obj);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onOverflow(WatchEvent<?> event, Path currentPath) {
|
|
|
+ Object obj = event.context();
|
|
|
+ Console.log("Overflow:{}-> {}", currentPath, obj);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ watchMonitor.start();
|
|
|
+ for (int i= 0; i< 10; i++ ){
|
|
|
+ System.out.println(i);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void afterBuild(BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult, BuildLog buildLog){
|
|
|
+ ModelingBuildStatus buildStatus = null;
|
|
|
+ try {
|
|
|
+ buildStatus = buildSceneResult.getBuildStatus();
|
|
|
+ log.info("服务{} 计算结束:{},计算状态:{}", SysConstants.hostName, buildLog.getSceneNum(),buildStatus.message());
|
|
|
+ //释放锁
|
|
|
+ Long decr = redisUtil.decr(SysConstants.SCENE_BUILDING + buildLog.getSceneNum(), 1);
|
|
|
+ if (decr.compareTo(1L) < 0) {
|
|
|
+ redisUtil.del(SysConstants.SCENE_BUILDING + buildLog.getSceneNum());
|
|
|
+ }
|
|
|
+ buildLog.setUpdateTime(new Date());
|
|
|
+ buildLog.setResultQuequeName(buildSceneResult.getResultQueueName());
|
|
|
+ buildLogService.updateById(buildLog);
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("计算后业务处理出错!", e);
|
|
|
+ }finally {
|
|
|
+ //发送计算结果mq
|
|
|
+ buildSceneResult.setDuration(buildLog.getDuration());
|
|
|
+ this.sendCallResult(message, buildSceneResult);
|
|
|
+ this.sendCallBuildProcessLog(message, buildStatus);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送计算流程状态日志mq
|
|
|
+ * @param message
|
|
|
+ * @param buildStatus
|
|
|
+ */
|
|
|
+ private void sendCallBuildProcessLog(BuildSceneCallMessage message, ModelingBuildStatus buildStatus){
|
|
|
+ rabbitMqProducer.sendByWorkQueue(queueModelingProcessLog,
|
|
|
+ BuildSceneProcessLogMessage.builder().num(message.getSceneNum()).buildStatus(buildStatus.code()).build());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void preBuild(Map<String,Object> buildContext,BuildSceneCallMessage message, BuildLog buildLog) throws BuildException {
|
|
|
+
|
|
|
+ // 初始化日志参数
|
|
|
+ buildLog.setHostName(SysConstants.hostName);
|
|
|
+ buildLog.setQueueName(queueModelingCall);
|
|
|
+ buildLog.setSceneNum(message.getSceneNum());
|
|
|
+ buildLog.setDataSource(message.getPath());
|
|
|
+ buildLog.setCreateTime(new Date());
|
|
|
+ buildLog.setUpdateTime(new Date());
|
|
|
+ buildLog.setBuildType(0);
|
|
|
+ buildLog.setStatus(0);
|
|
|
+ // 设置缓存锁
|
|
|
+ String key = SysConstants.SCENE_BUILDING + buildLog.getSceneNum();
|
|
|
+ // 如果是强制重新计算,则删除key。
|
|
|
+ if (StringUtils.equals(message.getRebuild(), "1")) {
|
|
|
+ redisUtil.del(key);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取缓存锁,防止重复消费
|
|
|
+ Long building = redisUtil.incr(key, 1);
|
|
|
+ buildLogService.save(buildLog);
|
|
|
+
|
|
|
+ if(!ObjectUtils.isEmpty(buildLog.getMessageId())){
|
|
|
+ // 设置消息id幂等性,防止消息重复消费
|
|
|
+ boolean lock = redisLockUtil.lock(SysConstants.SCENE_MESSAGE_BUILDING + buildLog.getMessageId(), SysConstants.modelTimeOut * 3600);
|
|
|
+ if (!lock) {
|
|
|
+ log.error("服务:{},消息重复消费:{}", SysConstants.hostName, buildLog.getMessageId());
|
|
|
+ throw new BuildException(ModelingBuildStatus.REPEAT);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (building.compareTo(1L) > 0) {
|
|
|
+ log.error("服务:{},重复构建:{},构建次数:{}", SysConstants.hostName, buildLog.getSceneNum(),building);
|
|
|
+ throw new BuildException(ModelingBuildStatus.REPEAT);
|
|
|
+ } else {
|
|
|
+ redisUtil.expire(key, Integer.toUnsignedLong(SysConstants.modelTimeOut * 3600));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送计算结果
|
|
|
+ * @param message
|
|
|
+ * @param buildSceneResult
|
|
|
+ */
|
|
|
+ private void sendCallResult(BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult){
|
|
|
+ ModelingBuildStatus buildStatus = buildSceneResult.getBuildStatus();
|
|
|
+ //重复计算不需要发送mq做后置处理
|
|
|
+ if(buildStatus.equals(ModelingBuildStatus.REPEAT)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ BuildSceneResultMqMessage buildResult = BuildSceneResultMqMessage.builder()
|
|
|
+ .buildSuccess(buildStatus.equals(ModelingBuildStatus.SUCCESS))
|
|
|
+ .computeTime(buildSceneResult.getDuration())
|
|
|
+ .path(buildSceneResult.getPath())
|
|
|
+ .hostName(SysConstants.hostName)
|
|
|
+ .build();
|
|
|
+ buildResult.setBuildContext(message.getBuildContext());
|
|
|
+ buildResult.setExt(message.getExt());
|
|
|
+ buildResult.setDetFloorplan(buildSceneResult.getDetFloorplan());
|
|
|
+ rabbitMqProducer.sendByWorkQueue(buildSceneResult.getResultQueueName(),buildResult);
|
|
|
+ }
|
|
|
+}
|