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;
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)){
camera = cameraService.getOne(new LambdaQueryWrapper()
.like(Camera::getChildName, mac)
.or().like(Camera::getSnCode, mac)
.or().like(Camera::getWifiName, mac));
if(Objects.isNull(camera)){
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 (cameraType == 11L && scenePlus.getSceneStatus().equals(SceneStatus.wait.code())) {
log.info(scenePlus.getNum() + ":场景处于计算中,不能再计算");
return null;
}
}
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, jsonObject.getLong("account"), 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());
//上传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);
mqMessage.setRebuild(String.valueOf(rebuild));
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);
}
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