package com.fdkankan.contro.mq.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.fdkankan.common.constant.*;
import com.fdkankan.common.util.FileUtils;
import com.fdkankan.contro.constant.UserEditDataType;
import com.fdkankan.contro.entity.*;
import com.fdkankan.contro.mq.service.IBuildSceneService;
import com.fdkankan.contro.service.ICommonService;
import com.fdkankan.contro.service.*;
import com.fdkankan.contro.service.impl.FdkkV4Service;
import com.fdkankan.fyun.face.FYunFileServiceInterface;
import com.fdkankan.model.constants.ConstantFileName;
import com.fdkankan.model.constants.ConstantFilePath;
import com.fdkankan.model.constants.UploadFilePath;
import com.fdkankan.model.utils.CreateObjUtil;
import com.fdkankan.rabbitmq.bean.BuildSceneCallMessage;
import com.fdkankan.rabbitmq.bean.BuildSceneResultMqMessage;
import com.fdkankan.rabbitmq.util.RabbitMqProducer;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.io.File;
import java.util.*;
/**
*
* TODO
*
*
* @author dengsixing
* @since 2022/3/1
**/
@Slf4j
@Service
@RefreshScope
public class BuildObjServiceImpl implements IBuildSceneService {
@Value("${queue.modeling.modeling-call}")
private String queueModelingCall;
@Value("${queue.modeling.obj.modeling-post}")
private String queueObjModelingPost;
@Value("${queue.modeling.obj.modeling-pre}")
private String queueObjModelingPre;
@Value("${model.modelKind:3dtiles}")
private String modelKind;
@Value("#{'${model.3dtiles.sceneSource:}'.split(',')}")
private List sdTilesSceneSourceList;
@Value("${env:gn}")
private String env;
@Autowired
private RabbitMqProducer mqProducer;
@Resource
private FYunFileServiceInterface fYunFileService;
@Autowired
private ISceneProService sceneProService;
@Autowired
private IFdkkLaserService fdkkLaserService;
@Autowired
private FdkkV4Service fdkkV4Service;
@Autowired
private IBuildSceneDTService buildSceneDTService;
@Autowired
private ISceneProEditService sceneProEditService;
@Autowired
private IScenePlusService scenePlusService;
@Autowired
private ISceneBuildProcessLogService sceneBuildProcessLogService;
@Autowired
private ICommonService commonService;
@Autowired
private IScenePlusExtService scenePlusExtService;
@Autowired
private RedisUtil redisUtil;
@Autowired
private ICameraDetailService cameraDetailService;
@Autowired
private ICompanyService companyService;
@Override
public void buildScenePre(BuildSceneCallMessage message) throws Exception{
boolean success = false;
String num = message.getSceneNum();
String path = message.getPath();
String laserObjFilePath = path + "_laser_obj";
try {
//根据相机类型,组装资源路径
log.info("开始准备生成OBJ场景资源,路径:{}", laserObjFilePath);
FileUtils.delAllFile(laserObjFilePath);
//获取解压后的资源的data.fdage中的数据
File folderPath = new File(path);
fYunFileService.downloadFile(ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_LASER_PATH, "") + "/data.fdage", laserObjFilePath + "/capture/data.fdage");
JSONObject jsonObject = FileUtils.readJson(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage");
if(ObjectUtils.isEmpty(jsonObject)){
log.error("data.fdage文件不存在");
return ;
}
//下载资源到本地
this.downLoadSource(message, laserObjFilePath);
if (!jsonObject.containsKey("exportMeshObj") || jsonObject.getIntValue("exportMeshObj") != 1) {
// 写入data.fdage 防止重算
jsonObject.put("exportMeshObj", 1);
FileUtil.writeUtf8String(jsonObject.toJSONString(), laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage");
fYunFileService.uploadFile(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage",
ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_LASER_PATH, "") + "/data.fdage");
}
// 重新构造datafdage文件,添加生成obt文件选项
jsonObject.put("OnlyExportMeshObj",true);
FileUtils.writeFile(laserObjFilePath + File.separator + "capture" + File.separator + "data.fdage", jsonObject.toJSONString());
message.getBuildContext().put("previousPath",path);
message.setCameraType("14");
message.setResolution(jsonObject.getString("resolution"));
message.setPath(laserObjFilePath);
message.setResultReceiverMqName(queueObjModelingPost);
//发送mq,就进行计算
mqProducer.sendByWorkQueue(queueModelingCall, message);
success = true;
log.info("场景计算资源准备结束,场景码:{}", message.getSceneNum());
}catch (Exception e){
log.error("生成OBJ场景资源准备异常,num=" + num, e);
buildSceneDTService.handBaseFail("生成OBJ场景资源准备异常", message.getPath(), message.getSceneNum(), "计算控制服务器");
throw e;
}finally {
fdkkLaserService.pushBuildStatusToLaserSystem(num, laserObjFilePath + "/laserData/mesh", success ? CommonOperStatus.SUCCESS.code() : CommonOperStatus.FAILD.code());
}
}
@Override
public void downLoadSource(BuildSceneCallMessage message,String path) throws Exception{
//下载原始资源文件
String ossPath = commonService.getOssOrignPath(message.getPath());
fYunFileService.downloadFileByCommand(path + File.separator + "capture", ossPath);
//下载caches/image,算法会执行快一些
String ossResultPath = String.format(UploadFilePath.scene_result_data_path, message.getSceneNum());
fYunFileService.downloadFileByCommand(path + "/caches/images/", ossResultPath + "caches/images/");
//下载点位校准文件
fYunFileService.downloadFileByCommand(path + "/extras/", ossResultPath + "extras/");
}
@Override
public void buildScenePost(BuildSceneResultMqMessage message) throws Exception {
String path = message.getPath();
String projectNum = message.getBuildContext().get("sceneNum").toString();
String laserObjFilePath = path;
boolean success = false;
try {
//上传计算日志
String buildLogPath = String.format(UploadFilePath.BUILD_LOG_PATH, projectNum);
fYunFileService.uploadFile(path + File.separator + "console.log", buildLogPath + "console.log");
if (!message.getBuildSuccess()) {
log.error("生成OBJ场景计算失败!");
// 发送钉钉消息,计算失败
buildSceneDTService.handModelFail("生成OBJ场景计算失败!", message.getPath(), message.getBuildContext().get("sceneNum").toString(), message.getHostName());
return;
}
ScenePro scenePro = sceneProService.getByNum(projectNum);
String version = "v4";
String ossImagePath = String.format(UploadFilePath.IMG_VIEW_PATH, projectNum);
//如果是微服务上线之前的存量场景且未生成过obj(未升级过),需要上传到v3的目录,在函数最后调用升级接口进行文件拷贝
if(Objects.nonNull(scenePro) && scenePro.getIsUpgrade() != CommonStatus.YES.code().intValue()){
ossImagePath = String.format(ConstantFilePath.IMAGE_PATH_FORMAT, projectNum);
version = "v3";
}
//上传obj
String resultsPath = path + File.separator + "results" + File.separator;
if(this.modelKind.equals(ModelKind.DAM.code())){
CreateObjUtil.convertTxtToDam(path + File.separator + "results" + File.separator + "tex" + File.separator + "modeldata.txt", path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam");
CreateObjUtil.convertDamToLzma(path + File.separator + "results/");
CreateObjUtil.convertTxtToDam(path + File.separator + "results" + File.separator + "tex" + File.separator + "modeldata.txt", path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam");
File file = new File(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam.lzma");
while (!file.exists()) {
Thread.sleep(60000);
}
fYunFileService.uploadFile(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam.lzma", ossImagePath + ConstantFileName.modelUUID + "_50k.dam.lzma");
fYunFileService.uploadFile(path + File.separator + "results" + File.separator + ConstantFileName.modelUUID + "_50k.dam", ossImagePath + ConstantFileName.modelUUID + "_50k.dam");
}
if(this.modelKind.equals(ModelKind.THREE_D_TILE.code())
&& CollUtil.isNotEmpty(sdTilesSceneSourceList)
&& sdTilesSceneSourceList.contains(SceneSource.JG.code())){
String threedtilesPath = resultsPath + ModelKind.THREE_D_TILE.code();
String oss3dtilesPath = ossImagePath + ModelKind.THREE_D_TILE.code();
List list = FileUtils.list(new File(threedtilesPath));
if(CollUtil.isEmpty(list)){
log.error("3dtiles目录异常,3dtiles地址:{}", new File(path + File.separator + "results" + File.separator + ModelKind.THREE_D_TILE.code()));
throw new Exception("3dtiles目录异常");
}
//上传3dtiles文件
fYunFileService.uploadFileByCommand(threedtilesPath, oss3dtilesPath);
}
String texPath = laserObjFilePath + File.separator + "results" + File.separator + "tex";
File texFile = new File(texPath);
if(texFile.exists()){
for (File textureFile : texFile.listFiles()) {
if(textureFile.getName().endsWith(".jpg")){
fYunFileService.uploadFile(textureFile.getAbsolutePath(),
ossImagePath + ConstantFileName.modelUUID + "_50k_texture_jpg_high1/"+textureFile.getName());
}
}
}
fYunFileService.uploadFile(laserObjFilePath + File.separator + "results" + File.separator + "tex/texture1.jpg",
ossImagePath + ConstantFileName.modelUUID + "_50k_texture_jpg_high1/texture1.jpg");
// 拷贝结果
log.info("开始拷贝obj文件");
FileUtils.copyFolderAllFiles(laserObjFilePath + "/results/mesh", laserObjFilePath + "/laserData/mesh/", true);
//上传mesh文件
fYunFileService.uploadFileByCommand(laserObjFilePath + "/results/mesh", String.format(UploadFilePath.DATA_VIEW_PATH, projectNum) + "mesh");
CreateObjUtil.convertTxtToVisionmodeldata(resultsPath + "vision.txt", resultsPath + "vision.modeldata");
fYunFileService.uploadFile(resultsPath + "vision.txt", ossImagePath.concat("vision.txt"));
fYunFileService.uploadFile(resultsPath + "vision.modeldata", ossImagePath.concat("vision.modeldata"));
if(!ObjectUtils.isEmpty(scenePro)){
LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper()
.set(ScenePro::getStatus, -2).eq(ScenePro::getNum, projectNum);
sceneProService.update(updateWrapper);
sceneProEditService.update(new LambdaUpdateWrapper().set(SceneProEdit::getMapVisi,0)
.eq(SceneProEdit::getProId,scenePro.getId()));
}
ScenePlus scenePlus = scenePlusService.getScenePlusByNum(projectNum);
if(Objects.nonNull(scenePlus)){
//清除用户编辑业务数据
Set bizs = new HashSet<>();
bizs.add(UserEditDataType.BOX_MODEL.message());
bizs.add(UserEditDataType.FLOORPLAN.message());
commonService.initUserEditData(projectNum, bizs, null);
LambdaUpdateWrapper plusUpdateWrapper = new LambdaUpdateWrapper()
.set(ScenePlus::getSceneStatus, -2).eq(ScenePlus::getNum, projectNum);
scenePlusService.update(plusUpdateWrapper);
ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
scenePlusExt.setAlgorithmTime(Calendar.getInstance().getTime());
//计算容量
Long space = commonService.getSpace(projectNum);
scenePlusExt.setSpace(space);
Object[] editInfoArr = commonService.updateEditInfo(scenePlus);
SceneEditInfo sceneEditInfo = (SceneEditInfo)editInfoArr[0];
SceneEditInfoExt sceneEditInfoExt = (SceneEditInfoExt)editInfoArr[1];
SceneEditControls sceneEditControls = (SceneEditControls)editInfoArr[2];
if(this.modelKind.equals(ModelKind.THREE_D_TILE.code())
&& CollUtil.isNotEmpty(sdTilesSceneSourceList)
&& sdTilesSceneSourceList.contains(scenePlus.getSceneSource())){
scenePlusExt.setModelKind(ModelKind.THREE_D_TILE.code());
scenePlusExtService.updateById(scenePlusExt);
}
log.info("生成scene.json上传oss并设置缓存,num:{}", projectNum);
CameraDetail cameraDetail = cameraDetailService.getByCameraId(scenePlus.getCameraId());
Company company = !org.apache.commons.lang3.ObjectUtils.isEmpty(cameraDetail.getCompanyId()) ? companyService.getById(cameraDetail.getCompanyId()) : null;
//写scene.json
commonService.writeSceneJson(projectNum, new JSONObject(),sceneEditInfo, sceneEditInfoExt, sceneEditControls, scenePlus,scenePlusExt,company);
}
// 如果未升级V4,则升级V4
if("v3".equals(version)){
fdkkV4Service.upgradeToV4(projectNum);
}
success = true;
//国际环境需要发邮件通知
if("eur".equals(env)){
commonService.sendEmail(projectNum);
}
}catch (Exception e){
log.error("生成OBJ场景计算结果处理异常,num=" + projectNum, e);
buildSceneDTService.handBaseFail("生成OBJ场景计算结果处理异常", message.getPath(), projectNum, "计算控制服务器");
throw e;
}finally {
fdkkLaserService.pushBuildStatusToLaserSystem(projectNum, laserObjFilePath + "/laserData/mesh", success ? CommonOperStatus.SUCCESS.code() : CommonOperStatus.FAILD.code());
}
}
}