package com.fdkankan.modeling.service.impl; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.fdkankan.common.constant.CommonStatus; import com.fdkankan.common.constant.ModelingBuildStatus; import com.fdkankan.common.util.FileUtils; import com.fdkankan.model.enums.ModelTypeEnums; import com.fdkankan.model.utils.ComputerUtil; import com.fdkankan.modeling.bean.BuildSceneResultBean; import com.fdkankan.modeling.constants.SysConstants; import com.fdkankan.modeling.entity.BuildLog; import com.fdkankan.modeling.exception.BuildException; import com.fdkankan.modeling.service.IBuildLogService; import com.fdkankan.modeling.service.IReverseE57Service; 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 lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.time.StopWatch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import javax.print.DocFlavor; import java.io.File; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @Slf4j @Service public class ReverseE57ServiceImpl implements IReverseE57Service { @Value("${queue.modeling.modeling-call}") private String queueModelingCall; @Value("${queue.modeling.modeling-process-log}") private String queueModelingProcessLog; @Value("${queue.modeling.modeling-post}") private String queueModelingPost; @Autowired private IBuildLogService buildLogService; @Resource private RabbitMqProducer rabbitMqProducer; @Value("${model.type:#{null}}") private String modelType; @Override public void build(BuildSceneCallMessage message, BuildLog buildLog) { //开始计时 StopWatch watch = new StopWatch(); watch.start(); //发送记录计算状态为计算中 rabbitMqProducer.sendByWorkQueue(queueModelingProcessLog, BuildSceneProcessLogMessage.builder().num(message.getSceneNum()).buildStatus(ModelingBuildStatus.CALCULATING.code()).queueName(queueModelingCall).build()); final BuildSceneResultBean buildSceneResult = new BuildSceneResultBean(); String resultQueueName = StrUtil.isNotBlank(message.getResultReceiverMqName()) ? message.getResultReceiverMqName() : queueModelingPost; buildSceneResult.setResultQueueName(resultQueueName); ModelingBuildStatus status = null; Future future = null; try { Map buildContext = new HashMap<>(); buildContext.put("num", message.getSceneNum()); 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); buildLogService.save(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); //计算后处理 ModelingBuildStatus buildStatus = null; try { buildStatus = buildSceneResult.getBuildStatus(); log.info("服务{} 计算结束:{},计算状态:{}", SysConstants.hostName, buildLog.getSceneNum(),buildStatus.message()); buildLog.setUpdateTime(new Date()); buildLog.setResultQuequeName(buildSceneResult.getResultQueueName()); buildLogService.updateById(buildLog); } catch (Exception e) { log.error("计算后业务处理出错!", e); }finally { buildSceneResult.setDuration(buildLog.getDuration()); this.sendCallResult(message, buildSceneResult); rabbitMqProducer.sendByWorkQueue(queueModelingProcessLog, BuildSceneProcessLogMessage.builder().num(message.getSceneNum()).buildStatus(buildStatus.code()).queueName(queueModelingCall).build()); } } /** * 发送计算结果 * @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()); rabbitMqProducer.sendByWorkQueue(buildSceneResult.getResultQueueName(),buildResult); } private ModelingBuildStatus buildScene(Map buildContext,BuildSceneCallMessage message, BuildSceneResultBean buildSceneResult,BuildLog logRecord) throws Exception{ //如果mq生产者在消息体中设置了结算结果mq队列名,就发到这个队列,否则就发送到默认队列 String path = message.getPath(); String num = message.getSceneNum(); //不同的相机不同的方法 String cameraType = message.getCameraType(); //0表示有4k图,1表示没有 //判断调用V2还是V3版本的算法 String buildType = ObjectUtils.isEmpty(message.getBuildType()) ? "V2" : message.getBuildType(); buildSceneResult.setCameraType(cameraType); buildSceneResult.setNum(num); buildSceneResult.setPath(path); //计算模型并返回需要上传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; } log.info("八目上完oss结束修改数据:"+num); return ModelingBuildStatus.SUCCESS; } }