package com.fdkankan.contro.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.common.constant.*;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.util.DateExtUtil;
import com.fdkankan.common.util.FileUtils;
import com.fdkankan.common.util.SnowflakeIdGenerator;
import com.fdkankan.contro.constant.RedisConstants;
import com.fdkankan.contro.entity.*;
import com.fdkankan.contro.enums.CameraTypeEnum;
import com.fdkankan.contro.mapper.ISceneFileBuildMapper;
import com.fdkankan.contro.service.ICommonService;
import com.fdkankan.contro.service.*;
import com.fdkankan.contro.vo.ResponseSceneFile;
import com.fdkankan.contro.vo.ScenePlusVO;
import com.fdkankan.fyun.config.FYunFileConfig;
import com.fdkankan.fyun.face.FYunFileServiceInterface;
import com.fdkankan.image.MatrixToImageWriterUtil;
import com.fdkankan.model.constants.ConstantFilePath;
import com.fdkankan.model.constants.UploadFilePath;
import com.fdkankan.model.utils.SceneUtil;
import com.fdkankan.rabbitmq.bean.BuildSceneCallMessage;
import com.fdkankan.rabbitmq.util.RabbitMqProducer;
import com.fdkankan.redis.constant.RedisKey;
import com.fdkankan.redis.util.RedisLockUtil;
import com.fdkankan.redis.util.RedisUtil;
import com.fdkankan.web.response.Result;
import com.fdkankan.web.response.ResultData;
import com.fdkankan.web.util.RSAEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
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.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
/**
*
* 场景文件建模表 服务实现类
*
*
* @author dengsixing
* @since 2021-12-23
*/
@RefreshScope
@Slf4j
@Service
public class SceneFileBuildServiceImpl extends ServiceImpl implements ISceneFileBuildService {
private static final String SPLICE = "#";
@Value("${main.url}")
private String mainUrl;
@Value("${scene.pro.new.url}")
private String sceneProNewUrl;
@Value("${scene.pro.v3.url}")
private String sceneProV3Url;
@Value("${queue.modeling.modeling-pre}")
private String queueModelingPre;
@Value("${queue.modeling.v3.modeling-pre}")
private String queueV3ModelingPre;
@Value("${queue.modeling.intermit.modeling-pre}")
private String queueIntermitModelingPre;
@Value("${queue.modeling.liguang.modeling-pre:liguang-modeling-pre}")
private String queueLiguangModelingPre;
@Value("${v3.controlUrl:#{null}}")
private String v3controlUrl;
@Value("${model.modelKind:3dtiles}")
private String modelKind;
@Value("#{'${model.3dtiles.sceneSource:}'.split(',')}")
private List sdTilesSceneSourceList;
@Value("#{'${camType.laser:}'.split(',')}")
private List laserCamTypeList;
@Value("${build.notSupport.beforeTime:202203}")
private String jgNotSupportBuildTime;
@Autowired
private RedisUtil redisUtil;
@Autowired
private IScenePlusExtService scenePlusExtService;
@Autowired
private IScene3dNumService scene3dNumService;
@Autowired
private IScenePlusService scenePlusService;
@Autowired
private RabbitMqProducer rabbitMqProducer;
@Autowired
private ISceneProEditService sceneProEditService;
@Autowired
private ISceneEditInfoService sceneEditInfoService;
@Autowired
private ISceneEditControlsService sceneEditControlsService;
@Autowired
private ISceneEditInfoExtService sceneEditInfoExtService;
@Autowired
private ISceneCooperationService sceneCooperationService;
@Autowired
private ISceneResourceCameraService sceneResourceCameraService;
@Autowired
private ISceneResourceCooperationService sceneResourceCooperationService;
@Autowired
private ICameraService cameraService;
@Autowired
private ICameraDetailService cameraDetailService;
@Autowired
private IUserService userService;
@Autowired
private ICompanyService companyService;
@Resource
private FYunFileServiceInterface fYunFileService;
@Autowired
private FYunFileConfig fYunFileConfig;
@Autowired
private ISceneProService sceneProService;
@Autowired
private IFdkkLaserService fdkkLaserService;
@Autowired
private RedisLockUtil redisLockUtil;
@Autowired
private ICameraTypeService cameraTypeService;
private RestTemplate restTemplate = new RestTemplate();
@Autowired
private ISceneCopyDistinctEnvService sceneCopyDistinctEnvService;
@Autowired
private ISceneCopyLogService sceneCopyLogService;
@Autowired
private ISceneCleanOrigService sceneCleanOrigService;
@Autowired
private ICommonService commonService;
@Autowired
private IExceedSpaceSceneService exceedSpaceSceneService;
@Autowired
private ISceneColdStorageLogService sceneColdStorageLogService;
@Autowired
private ISceneColdStorageService sceneColdStorageService;
@Autowired
private IntermitSceneService intermitSceneService;
@Autowired
private ISceneRebuildLogService sceneRebuildLogService;
@Autowired
private ISceneUploadCountService sceneUploadCountService;
@Autowired
private IWbService wbService;
@Override
public SceneFileBuild findByFileId(String fileId) {
List list = this.list(new LambdaQueryWrapper().eq(SceneFileBuild::getFileId, fileId)
.orderByDesc(SceneFileBuild::getId));
if (CollUtil.isEmpty(list)) {
return null;
}
return list.get(0);
}
@Override
public ResponseSceneFile preUpload(String params) throws Exception {
log.info("preUpload-params: " + params);
if (StrUtil.isEmpty(params)) {
throw new BusinessException(ErrorCode.PARAM_REQUIRED);
}
params = params.replaceAll("%2B", "+");
Base64 base64 = new Base64();
String cipher = params;
// 私钥解密过程
byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile()),
base64.decode(cipher));
String restr = new String(res, "UTF-8");
log.debug("preUpload-params解密结果:" + restr);
String[] strArr = restr.split(SPLICE);
if (strArr.length != 5) {
throw new BusinessException(ErrorCode.PARAM_REQUIRED);
}
String mac = strArr[0];
String totalPicNum = strArr[1];
String chunks = strArr[2];
String folderName = strArr[3];
if (StrUtil.isEmpty(mac)) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5044);
}
if (totalPicNum == null) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5045);
}
if (chunks == null) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5046);
}
if (folderName == null) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5047);
}
Camera camera = cameraService.getBySnCode(mac);
if(Objects.isNull(camera)){
cameraService.getOne(new LambdaQueryWrapper()
.like(Camera::getChildName, mac)
.or().like(Camera::getSnCode, mac)
.or().like(Camera::getWifiName, mac));
throw new BusinessException(ErrorCode.FAILURE_CODE_7010);
}
CameraDetail cameraDetail = cameraDetailService.getByCameraId(camera.getId());
if (Objects.isNull(cameraDetail)) {
throw new BusinessException(ErrorCode.FAILURE_CODE_7010);
}
Long companyId = cameraDetail.getCompanyId();
if (Objects.nonNull(companyId)) {
Company company = companyService.getById(companyId);
if (Objects.nonNull(company)) {
Integer canUpWebsite = company.getCanUpWebsite();
if (Objects.nonNull(canUpWebsite) && canUpWebsite == CommonStatus.NO.code().intValue()) {
throw new BusinessException(ErrorCode.FAILURE_CODE_4006);
}
}
}
log.info("mac:{} 准备上传文件,folderName:{}", mac, folderName);
ResponseSceneFile responseSceneFile = new ResponseSceneFile();
// 检测是否有生成
String fileId = redisUtil.get(String.format(RedisConstants.FOLDER_FILEID_BUILD, folderName));
if (StrUtil.isEmpty(fileId)) {
SceneFileBuild sceneFileBuild = this.findByUnicode(folderName);
if (sceneFileBuild != null) {
fileId = sceneFileBuild.getFileId();
}
}
if (StrUtil.isNotEmpty(fileId)) {
//校验目录是否被上锁,如果上锁,抛出错误(避免删除原始资源定时任务执行过程中,有场景补拍重新上传)
String homePath = redisUtil.get(String.format(RedisKey.SCENE_OSS_HOME_DIR_DELETE, folderName));
if (StrUtil.isNotEmpty(homePath)) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5073);
}
//如果原始资源目录不是正在被定时任务删除中,就加上上传锁,并正常返回
homePath = ConstantFilePath.OSS_PREFIX.concat(mac).concat("/").concat(fileId).concat("/").concat(folderName);
redisUtil.set(String.format(RedisKey.SCENE_OSS_HOME_DIR_UPLOAD, folderName), homePath, RedisKey.CAMERA_EXPIRE_7_TIME);
responseSceneFile.setFileId(fileId);
redisUtil.set(String.format(RedisConstants.FOLDER_FILEID_BUILD, folderName), fileId, 2 * 24 * 60 * 60);
return responseSceneFile;
}
// 加锁
boolean lock = redisLockUtil.lock(String.format(RedisConstants.FOLDER_LOCK_BUILD, folderName), 120);
if (!lock) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5052);
}
// 查找场景表
LambdaQueryWrapper proWrapper = new LambdaQueryWrapper<>();
proWrapper.like(ScenePro::getDataSource, "/" + folderName);
ScenePro pro = sceneProService.getOne(proWrapper);
String dataSource = null;
if (!ObjectUtils.isEmpty(pro)) {
dataSource = pro.getDataSource();
} else {
dataSource = scenePlusService.getDataSourceLikeUnicode("/" + folderName);
}
if (StrUtil.isNotEmpty(dataSource)) {
log.info("从数据库中查到与 fileId:{} 匹配的路径为:{}", fileId, dataSource);
int n = dataSource.split("/").length;
if (n > 1) {
fileId = dataSource.split("/")[n - 2];
}
}
if (StrUtil.isEmpty(fileId)) {
fileId = new SnowflakeIdGenerator(0, 0).nextId() + "";
log.info("新生成build数据,{}", fileId);
}
SceneFileBuild sceneFileBuild = new SceneFileBuild();
sceneFileBuild.setChildName(mac);
sceneFileBuild.setFileId(fileId);
sceneFileBuild.setRecStatus("A");
sceneFileBuild.setUnicode(folderName);
sceneFileBuild.setTotalPicNum(Integer.valueOf(totalPicNum));
sceneFileBuild.setChunks(Integer.valueOf(chunks));
sceneFileBuild.setCreateTime(new Date());
this.save(sceneFileBuild);
redisUtil.set(String.format(RedisConstants.FOLDER_FILEID_BUILD, folderName), fileId, 2 * 24 * 60 * 60);
redisUtil.set(String.format(RedisConstants.FILEID_FOLDER_BUILD, fileId), folderName, 2 * 24 * 60 * 60);
responseSceneFile.setFileId(fileId);
return responseSceneFile;
}
public SceneFileBuild findByUnicode(String unicode) {
List list = this.list(new QueryWrapper()
.eq("unicode", unicode)
.orderByDesc("id"));
if (CollUtil.isEmpty(list))
return null;
return list.get(0);
}
public ScenePlusVO buildScene(String fileId, String prefix, JSONObject jsonObject, String buildType, long cameraType) throws Exception {
//调用createScene方法生成scene数据和加入算法队列
String sceneNum = "";
String cameraName = jsonObject.getJSONObject("cam").getString("uuid");
String unicode = jsonObject.getString("creator") + "_" + jsonObject.getString("uuidtime");
Camera camera = cameraService.getByChildName(cameraName);
if (camera == null) {
throw new BusinessException(CameraConstant.FAILURE_6003);
}
CameraDetail cameraDetail = cameraDetailService.getByCameraId(camera.getId());
if (cameraDetail == null) {
log.error("该相机详情不存在:" + cameraName);
throw new BusinessException(CameraConstant.FAILURE_6003);
}
//查看场景中的文件目录是否有改文件id,有则重新计算改场景,无则新建场景
ScenePlus scenePlus = scenePlusService.getByFileId("/" + fileId + "/");
int rebuild = CommonStatus.YES.code();
if (ObjectUtils.isEmpty(scenePlus)) {
//清除超容量场景记录
exceedSpaceSceneService.repeal(camera.getId(), fileId, unicode);
sceneNum = scene3dNumService.generateSceneNum(cameraDetail.getType());
rebuild = CommonStatus.NO.code();
} else {
sceneNum = scenePlus.getNum();
sceneCopyLogService.checkCanBuild(sceneNum);
//看看相机固件有bug,会重复发两次计算请求,所以这里判断,如果是看看场景,需要判断场景是否在计算中,如果是,直接返回成功
if (scenePlus.getSceneStatus().equals(SceneStatus.wait.code())) {
if (cameraType == 11L) {
log.info(scenePlus.getNum() + ":场景处于计算中,不能再计算");
return null;
} else {
throw new BusinessException(ErrorCode.FAILURE_CODE_5033);
}
}
}
if (sceneNum == null) {
log.error("大场景序号为空:" + sceneNum);
throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
}
//如果是相机计算容量的模式是场景个数模式,则需要拦截计算
//文保系统v1.5.0增加需求,文保vr场景默认不封存(条件companyI=26&&location=7)
if (rebuild == CommonStatus.NO.code() && !commonService.checkIsSpVr(jsonObject, cameraDetail)) {//新场景需要校验容量是否超出限制
boolean exceedSpace = exceedSpaceSceneService.cehckExceedSpace(sceneNum, cameraDetail, cameraName, fileId, unicode);
if (exceedSpace) {
ScenePlusVO scenePlusVO = new ScenePlusVO();
scenePlusVO.setNum(sceneNum);
scenePlusVO.setSceneStatus(SceneStatus.EXCEED_SPACE.code());
return scenePlusVO;
}
}
String dataSource = cameraName.replace("4DKKPRO_", "").replace("-fdage", "").toLowerCase() + File.separator +
fileId + File.separator + unicode;
if (cameraType == 14) {
dataSource = ConstantFilePath.BUILD_MODEL_LASER_PATH + dataSource;
} else {
dataSource = ConstantFilePath.BUILD_MODEL_PATH + dataSource;
}
String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, sceneNum);
String icon = null;
if (!ObjectUtils.isEmpty(jsonObject.getString("icon"))) {
fYunFileService.copyFileInBucket(ConstantFilePath.OSS_PREFIX + prefix + jsonObject.getString("icon"), imgViewPath + jsonObject.getString("icon"));
icon = fYunFileConfig.getHost() + imgViewPath + jsonObject.getString("icon");
log.info("上传icon成功....");
}
return buildScenePost(dataSource, jsonObject, buildType, cameraType, sceneNum, cameraDetail, rebuild, icon);
}
private ScenePlusVO buildScenePost(String dataSource, JSONObject jsonObject, String buildType, long cameraType,
String sceneNum, CameraDetail cameraDetail, int rebuild, String icon) throws Exception {
String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, sceneNum);
String userName = null;
if (!ObjectUtils.isEmpty(cameraDetail.getUserId())) {
SSOUser user = userService.getSSOUserByUserId(cameraDetail.getUserId());
userName = ObjectUtils.isEmpty(user) ? null : user.getUserName();
}
JSONObject firmwareVersion = new JSONObject();
if (!ObjectUtils.isEmpty(jsonObject.getString("camSoftwareVersion"))) {
firmwareVersion.put("camSoftwareVersion", jsonObject.getString("camSoftwareVersion"));
}
if (!ObjectUtils.isEmpty(jsonObject.getString("version"))) {
firmwareVersion.put("version", jsonObject.getString("version"));
}
String sceneUrl = mainUrl + "/" + sceneProNewUrl;
//重算的场景,先移除该场景对应的容量
if (rebuild == 1) {
scenePlusService.resetSpace(sceneNum);
} else {
//上传log-main.png
fYunFileService.uploadFile(ConstantFilePath.LOGO_PATH + "logo-main.png", imgViewPath + "logo-main.png");
fYunFileService.uploadFile(ConstantFilePath.LOGO_PATH + "logo-main-en.png", imgViewPath + "logo-main-en.png");
}
String algorithm = jsonObject.getString("location") != null && "1".equals(jsonObject.getString("location")) ? "sfm" : "slam";
ScenePlusVO scenePlusVO = this.createScenePlus(sceneNum, cameraDetail.getCameraId(), jsonObject.getString("creator"),
jsonObject.getString("pwd"), cameraType, jsonObject.getJSONObject("cam").getIntValue("type"),
dataSource, icon, cameraDetail.getUserId(), userName, algorithm, jsonObject.getInteger("location"),
jsonObject.getJSONArray("points").size(), jsonObject.getString("name"), jsonObject.getString("info"),
jsonObject.getInteger("scenetype"), jsonObject.getString("gps"), rebuild,
jsonObject.getInteger("resolution"), firmwareVersion.toString(), sceneUrl, buildType, cameraDetail.getCooperationUser());
try {
//上传app状态文件
commonService.uploadStatusJson(sceneNum, scenePlusVO.getSceneStatus(),
scenePlusVO.getWebSite(), scenePlusVO.getThumb(), PayStatus.NOT_PAY.code(),
String.format(UploadFilePath.DATA_VIEW_PATH, sceneNum));
BuildSceneCallMessage mqMessage = getBuildSceneMqMessage(sceneNum, cameraType, algorithm, jsonObject, buildType,
scenePlusVO.getDataSource());
if (cameraDetail.getCompanyId() != null) {
Company company = companyService.getById(cameraDetail.getCompanyId());
if (company != null && !ObjectUtils.isEmpty(company.getCalculateFlexibility()) && !company.getCalculateFlexibility()) {
mqMessage.setFlexibility(-1);
}
}
mqMessage.getExt().put("deleteExtras", true);
mqMessage.getExt().put("keepTitle", 0);
if (jsonObject.getIntValue("location") == 7) {
//发送到全景看看进行初始化
intermitSceneService.sendMq(scenePlusVO.getNum(), jsonObject, CommonSuccessStatus.WAITING.code());
rabbitMqProducer.sendByWorkQueue(queueIntermitModelingPre, mqMessage);
} else {
//如果是四普的看见相机场景,也需要推送全景vr
if (cameraType == 13 && Objects.nonNull(cameraDetail.getCompanyId()) && cameraDetail.getCompanyId() == 26) {
wbService.sendMq(sceneNum, CommonSuccessStatus.WAITING.code());
}
rabbitMqProducer.sendByWorkQueue(queueModelingPre, mqMessage);
}
} catch (Exception e) {
//接口最后失败了,把场景置位失败状态,可以让后续的计算请求进来重新发起计算
scenePlusService.update(new LambdaUpdateWrapper().eq(ScenePlus::getNum, scenePlusVO.getNum()).set(ScenePlus::getSceneStatus, SceneStatus.FAILD.code()));
log.error("发起计算请求失败,num:{}", scenePlusVO.getNum(), e);
throw e;
}
return scenePlusVO;
}
public ScenePlusVO buildV3Scene(ScenePro scenePro, String fileId, String prefix, JSONObject jsonObject, String buildType, long cameraType) throws Exception {
sceneCopyLogService.checkCanBuild(scenePro.getNum());
//调用createScene方法生成scene数据和加入算法队列
String cameraName = jsonObject.getJSONObject("cam").getString("uuid");
String unicode = jsonObject.getString("creator") + "_" + jsonObject.getString("uuidtime");
Camera camera = cameraService.getByChildName(cameraName);
if (camera == null) {
throw new BusinessException(CameraConstant.FAILURE_6003);
}
CameraDetail cameraDetail = cameraDetailService.getByCameraId(camera.getId());
if (cameraDetail == null) {
log.error("该相机详情不存在:" + cameraName);
throw new BusinessException(CameraConstant.FAILURE_6003);
}
String sceneNum = scenePro.getNum();
if (scenePro.getStatus().equals(SceneStatus.wait.code())) {
log.info(scenePro.getNum() + ":场景处于计算中,不能再计算");
return null;
}
String localDataPath = String.format(ConstantFilePath.DATABUFFER_FORMAT, sceneNum);
String imgViewPath = String.format(ConstantFilePath.IMAGE_PATH_FORMAT, sceneNum);
String dataViewPath = String.format(ConstantFilePath.DATA_PATH_FORMAT, sceneNum);
String userName = null;
if (!ObjectUtils.isEmpty(cameraDetail.getUserId())) {
SSOUser user = userService.getSSOUserByUserId(cameraDetail.getUserId());
userName = ObjectUtils.isEmpty(user) ? null : user.getUserName();
}
String icon = null;
if (!ObjectUtils.isEmpty(jsonObject.getString("icon"))) {
fYunFileService.copyFileInBucket(ConstantFilePath.OSS_PREFIX + prefix + jsonObject.getString("icon"), imgViewPath + jsonObject.getString("icon"));
icon = fYunFileConfig.getHost() + imgViewPath + jsonObject.getString("icon");
log.info("上传icon成功....");
}
JSONObject firmwareVersion = new JSONObject();
if (!ObjectUtils.isEmpty(jsonObject.getString("camSoftwareVersion"))) {
firmwareVersion.put("camSoftwareVersion", jsonObject.getString("camSoftwareVersion"));
}
if (!ObjectUtils.isEmpty(jsonObject.getString("version"))) {
firmwareVersion.put("version", jsonObject.getString("version"));
}
//删除oss的houst_floor.json(国际版可能会卡住)
fYunFileService.deleteFile(dataViewPath + "houst_floor.json");
String algorithm = jsonObject.getString("location") != null && "1".equals(jsonObject.getString("location")) ? "sfm" : "slam";
ScenePlusVO scenePlusVO = this.createScenePro(sceneNum, camera.getId(), camera.getChildName(), jsonObject.getString("creator"),
jsonObject.getString("pwd"), unicode, cameraType, fileId, icon, cameraDetail.getUserId(), userName, algorithm,
jsonObject.getJSONArray("points").size(), jsonObject.getString("name"), jsonObject.getString("info"),
jsonObject.getInteger("scenetype"), jsonObject.getString("gps"),
jsonObject.getInteger("resolution"), firmwareVersion.toString(), buildType);
//上传场景状态文件
commonService.uploadStatusJson(sceneNum, scenePlusVO.getSceneStatus(),
scenePlusVO.getWebSite(), scenePlusVO.getThumb(), PayStatus.NOT_PAY.code(),
String.format(ConstantFilePath.DATA_PATH_FORMAT, sceneNum));
BuildSceneCallMessage mqMessage = getBuildSceneMqMessage(sceneNum, cameraType, algorithm, jsonObject, buildType,
scenePlusVO.getDataSource());
if (cameraDetail.getCompanyId() != null) {
Company company = companyService.getById(cameraDetail.getCompanyId());
if (company != null) {
log.info("复制企业logo");
SceneProEdit sceneEditInfo = sceneProEditService.getByProId(scenePlusVO.getId());
if (StrUtil.isNotEmpty(company.getTopLogo())) {
fYunFileService.copyFileInBucket(company.getTopLogo(), imgViewPath + "logo-main.png");
}
if (StrUtil.isNotEmpty(company.getFloorLogo())) {
fYunFileService.copyFileInBucket(company.getFloorLogo(), imgViewPath + "floorLogoImg.png");
sceneEditInfo.setFloorLogo("user");
}
if (StrUtil.isNotEmpty(company.getQrLogo())) {
createQrCode(sceneNum, scenePlusVO.getWebSite(), company.getQrLogo());
}
sceneProEditService.updateById(sceneEditInfo);
if (!ObjectUtils.isEmpty(company.getCalculateFlexibility()) && !company.getCalculateFlexibility()) {
mqMessage.setFlexibility(-1);
}
}
}
rabbitMqProducer.sendByWorkQueue(queueV3ModelingPre, mqMessage);
return scenePlusVO;
}
private void createQrCode(String num, String url, String qrLogo) {
String localLogoPath = null;
if (!org.apache.commons.lang3.ObjectUtils.isEmpty(qrLogo)) {
try {
localLogoPath = ConstantFilePath.AGENT_PATH + qrLogo.substring(qrLogo.lastIndexOf("//") + 1);
HttpUtil.downloadFile(qrLogo, localLogoPath);
} catch (Exception e) {
log.error("公司logo下载失败:{}", qrLogo);
localLogoPath = null;
}
}
//生成二维码
String outPathZh = ConstantFilePath.BASE_PATH + File.separator + "sceneQRcode/" + num + ".png";
String outPathEn = ConstantFilePath.BASE_PATH + File.separator + "sceneQRcode/" + num + "_en.png";
QrConfig qrConfig = QrConfig.create();
qrConfig.setWidth(512);
qrConfig.setHeight(512);
if (!org.apache.commons.lang3.ObjectUtils.isEmpty(localLogoPath)) {
qrConfig.setImg(localLogoPath);
}
QrCodeUtil.generate(url, qrConfig, FileUtil.file(outPathZh));
QrCodeUtil.generate(url + "&lang=en", qrConfig, FileUtil.file(outPathEn));
//上传二维码
fYunFileService.uploadFile(outPathZh, String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + num + ".png");
fYunFileService.uploadFile(outPathEn, String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + num + "_en.png");
if (!org.apache.commons.lang3.ObjectUtils.isEmpty(localLogoPath)) {
FileUtils.deleteFile(localLogoPath);
}
}
@Override
public ResultData uploadSuccessBuild(String params) throws Exception {
log.info("uploadSuccessBuild-params: " + params);
String preParams = params;
if (StringUtils.isEmpty(params)) {
throw new BusinessException(ErrorCode.PARAM_REQUIRED);
}
params = params.replaceAll("%2B", "+");
params = params.replaceAll(" ", "+");
Base64 base64 = new Base64();
String cipher = params;
// 私钥解密过程
byte[] res = RSAEncrypt.decrypt(RSAEncrypt.loadPrivateKeyByStr(RSAEncrypt.loadPrivateKeyByFile()), base64.decode(cipher));
String restr = new String(res, "UTF-8");
log.info("uploadSuccessBuild-params解密结果:" + restr);
String[] strArr = restr.split(SPLICE);
if (strArr.length != 3) {
throw new BusinessException(ErrorCode.PARAM_REQUIRED);
}
String mac = strArr[0];
String fileId = strArr[1];
String folderName = redisUtil.get(String.format(RedisConstants.FILEID_FOLDER_BUILD, fileId));
if (StringUtils.isEmpty(folderName)) {
SceneFileBuild fileBuild = findByFileId(fileId);
if (ObjectUtils.isEmpty(fileBuild)) {
throw new BusinessException(ErrorCode.FAILURE_CODE_5012);
}
folderName = fileBuild.getUnicode();
redisUtil.set(String.format(RedisConstants.FILEID_FOLDER_BUILD, fileId), folderName, 2 * 24 * 60 * 60);
}
sceneUploadCountService.resetCountByUuid(folderName);
StringBuilder prefixBuffer = new StringBuilder(mac).append(File.separator).append(fileId).append(File.separator).append(folderName).append(File.separator);
String buildType = "V2";
Long cameraType = 10L;
if (!fYunFileService.fileExist(ConstantFilePath.OSS_PREFIX + prefixBuffer + "data.fdage")) {
log.error("data.fdage文件不存在");
throw new BusinessException(CameraConstant.FAILURE_6009);
}
JSONObject fdageJson = JSONObject.parseObject(fYunFileService.getFileContent(ConstantFilePath.OSS_PREFIX + prefixBuffer + "data.fdage"));
if (ObjectUtils.isEmpty(fdageJson)) {
log.info("data.fdage文件为空!");
throw new BusinessException(CameraConstant.FAILURE_6009);
}
//根据videoVersion判断是V2还是V3版本的算法和页面
if (fdageJson.containsKey("videoVersion") && StrUtil.isNotEmpty(fdageJson.getString("videoVersion"))) {
if (fdageJson.getIntValue("videoVersion") >= 4) {
buildType = "V3";
cameraType = 11L;
}
}
this.removeUpdateV4(ConstantFilePath.OSS_PREFIX + prefixBuffer + "data.fdage", fdageJson);
// 判断是否是V3的场景
ScenePro scenePro = sceneProService.getOne(
new LambdaQueryWrapper().like(ScenePro::getDataSource, "/".concat(fileId).concat("/")));
boolean callV3 = callV3(scenePro, preParams, fdageJson, "api/scene/file/uploadSuccessBuild");
if (callV3) return ResultData.ok();
if (ObjectUtils.isEmpty(scenePro) || (!ObjectUtils.isEmpty(scenePro.getIsUpgrade()) && scenePro.getIsUpgrade() == 1)) {
buildScene(fileId, prefixBuffer.toString(), fdageJson, buildType, cameraType);
} else {
buildV3Scene(scenePro, fileId, prefixBuffer.toString(), fdageJson, buildType, cameraType);
}
return ResultData.ok();
}
private void removeUpdateV4(String dataFdagePath, JSONObject fdageJson) {
Integer updateV4 = fdageJson.getInteger("updateV4");
if (Objects.isNull(updateV4) || updateV4 == 0) {
return;
}
fdageJson.put("updateV4", CommonStatus.NO.code());
fYunFileService.uploadFile(fdageJson.toJSONString().getBytes(StandardCharsets.UTF_8), dataFdagePath);
}
private boolean callV3(ScenePro scenePro, String preParams, JSONObject fdageJson, String api) throws Exception {
//复制出来的场景不支持补拍上传
if (Objects.nonNull(scenePro)) {
sceneCopyLogService.checkCanBuild(scenePro.getNum());
}
String cameraName = fdageJson.getJSONObject("cam").getString("uuid");
Camera camera = cameraService.getByChildName(cameraName);
if (camera == null) {
throw new BusinessException(CameraConstant.FAILURE_6003);
}
CameraDetail cameraDetail = cameraDetailService.getByCameraId(camera.getId());
if (cameraDetail == null) {
log.error("该相机详情不存在:" + cameraName);
throw new BusinessException(CameraConstant.FAILURE_6003);
}
// 判断是否是正顺|火调|普通v3的场景,如果是正顺|火调|普通v3的场景,则发送到原来的系统进行计算
if (!ObjectUtils.isEmpty(cameraDetail.getCompanyId())) {
Company company = companyService.getById(cameraDetail.getCompanyId());
if (ObjectUtils.isEmpty(company)) {
log.error("企业配置有误:" + cameraName);
throw new BusinessException(CameraConstant.FAILURE_6003);
}
if (!ObjectUtils.isEmpty(company.getSceneVersion()) && company.getSceneVersion().equals("V3")) {
//如果是app重新上传,需要解冻结
if (Objects.nonNull(scenePro)) {
sceneColdStorageService.unfreeze(scenePro.getNum(), "用户相机重新全量上传", scenePro.getDataSource());
}
callV3Service(preParams, api);
return Boolean.TRUE;
}
}
// TODO: 2023/1/12 3dtiles临时上激光场景
// else if (Objects.nonNull(scenePro) &&
// scenePro.getSceneSource() != SceneSource.JG.code() &&
// scenePro.getIsUpgrade() == CommonStatus.NO.code().intValue()){
// callV3Service(preParams,api);
// return Boolean.TRUE;
// }
return Boolean.FALSE;
}
public void callV3Service(String params, String api) throws Exception {
log.info("params:{}", params);
if (ObjectUtils.isEmpty(v3controlUrl)) {
log.error("未配置V3服务器!");
throw new Exception("未配置V3服务器!");
}
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap paramMap = new LinkedMultiValueMap();
paramMap.add("params", params);
HttpEntity