package com.fdkankan.fusion.service.impl;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fdkankan.fusion.common.PageInfo;
import com.fdkankan.fusion.common.util.*;
import com.fdkankan.fusion.common.FilePath;
import com.fdkankan.fusion.common.ResultCode;
import com.fdkankan.fusion.config.CacheUtil;
import com.fdkankan.fusion.entity.*;
import com.fdkankan.fusion.exception.BusinessException;
import com.fdkankan.fusion.mapper.IModelMapper;
import com.fdkankan.fusion.request.ModelPram;
import com.fdkankan.fusion.response.SceneVo;
import com.fdkankan.fusion.service.*;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.redis.util.RedisUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
/**
*
* 服务实现类
*
*
* @author
* @since 2022-08-03
*/
@Service
@Slf4j
public class ModelServiceImpl extends ServiceImpl implements IModelService {
@Autowired
LocalToOssUtil localToOssUtil;
@Autowired
UploadService uploadService;
@Autowired
ICaseNumService caseNumService;
@Autowired
ICaseService caseService;
@Autowired
IFusionNumService fusionNumService;
@Autowired
RedisUtil redisUtil;
@Autowired
ITmDepartmentService tmDepartmentService;
@Autowired
ITmUserService tmUserService;
@Autowired
ITmCameraService tmCameraService;
@Autowired
ThreadService threadService;
@Autowired
ISceneService sceneService;
@Value("${spring.profiles.active}")
private String environment;
@Override
public Model uploadObj(MultipartFile file,String username) throws Exception {
if(file.isEmpty()){
throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST);
}
if(file.getSize()>10 * 1024 * 1024 * 100){
throw new BusinessException(ResultCode.UPLOAD_FILE_TO_LONG);
}
//获取文件名
String fileName = file.getOriginalFilename();
if(StringUtils.isEmpty(fileName)){
throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST);
}
if(com.fdkankan.fusion.common.util.StringUtils.isChinese(fileName)){
throw new BusinessException(ResultCode.UPLOAD_FILE_CHINA_NAME);
}
if(fileName.length() >50){
throw new BusinessException(ResultCode.UPLOAD_FILE_NAME_TO_LONG);
}
if(!fileName.toLowerCase().endsWith(".zip")){
throw new BusinessException(ResultCode.UPLOAD_FILE_TYPE_ERROR);
}
//获取文件后缀名
String modelName = fileName.substring(0,fileName.lastIndexOf("."));
TmUser tmUser = tmUserService.getLoginUser();
Model model = new Model();
model.setModelTitle(modelName);
model.setModelSize(FileWriterUtil.setFileSize(file.getSize()));
model.setUserName(username);
model.setDeptId(tmUser.getDeptId());
redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"0");
this.save(model);
String fileName2 = UUID.randomUUID().toString().replace("-","") +".zip";
String objPath = String.format(FilePath.OBJ_LOCAL_PATH,environment , "modelId_"+model.getModelId()) ;
log.info("uploadObj--ThreadStart-fileName:{},modeId:{}",fileName2,model.getModelId());
File newObjFile = new File(objPath +"/" + fileName2);
if(!newObjFile.getParentFile().exists()){
newObjFile.getParentFile().mkdirs();
}
file.transferTo(newObjFile);
threadService.uploadModelObj(fileName2,objPath,newObjFile,model);
return model;
}
@Override
public PageInfo pageList(ModelPram param, String userName) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
List deptIds = tmDepartmentService.getDeptIds();
if(deptIds.size() <=0){
return PageInfo.PageInfo(new Page<>(param.getPageNum(),param.getPageSize()));
}
if(param.getCaseId() !=null){
String deptId = caseService.getDeptId(param.getCaseId());
wrapper.eq(Model::getDeptId,deptId);
}
List deptIds2 = tmDepartmentService.getSonByDeptIdAndDeptIds(deptIds, param.getDeptId(),param.getSearchType());
wrapper.in(Model::getDeptId,deptIds2);
wrapper.eq(Model::getType,3);
wrapper.notIn(Model::getCreateStatus,-2);
if(param.getStatus()!=null){ //参数2为成功,数据库中成功为1
wrapper.eq(Model::getCreateStatus,param.getStatus() == 2 ? 1 :param.getStatus());
}
if(StringUtils.isNotBlank(param.getModelTitle())){
wrapper.like(Model::getModelTitle,param.getModelTitle());
}
wrapper.orderByDesc(Model::getCreateTime);
Page page = this.page(new Page<>(param.getPageNum(),param.getPageSize()),wrapper);
Set deptIdset = page.getRecords().stream().map(Model::getDeptId).collect(Collectors.toSet());
HashMap mapByDept = tmDepartmentService.getMapByDeptIds(deptIdset);
for (Model model : page.getRecords()) {
if(model.getType() == 3 && StringUtils.isEmpty(model.getNum())) {
model.setNum(model.getModelId().toString());
}
if(StringUtils.isNotBlank(model.getDeptId())){
TmDepartment tmDepartment = mapByDept.get(model.getDeptId());
if(tmDepartment != null){
model.setDeptName(tmDepartment.getName());
}
}
}
return PageInfo.PageInfo(page);
}
private List getByDeptIds(List asList) {
if(asList.size() >0){
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(Model::getDeptId,asList);
return list(wrapper);
}
return new ArrayList<>();
}
@Override
public void delete(Integer modelId) {
List caseNumEntityList = caseNumService.getByNum(modelId.toString());
List fusionNumList = fusionNumService.getByNum(modelId.toString());
if(caseNumEntityList.size() >0 || fusionNumList.size() >0){
StringBuilder title = new StringBuilder();
List caseIdIds = caseNumEntityList.parallelStream().map(CaseNumEntity::getCaseId).collect(Collectors.toList());
if(caseIdIds.size() >0){
List list = caseService.getByIds(caseIdIds);
List collect = list.parallelStream().map(CaseEntity::getCaseTitle).collect(Collectors.toList());
for (String str : collect) {
title.append(str).append(",");
}
if(title.length()>0){
title.delete(title.length()-1,title.length());
}
}
throw new BusinessException(ResultCode.CASE_USE.code, String.format(ResultCode.CASE_USE.msg,title));
}
Model model = this.getById(modelId);
if(model == null ){
throw new BusinessException(ResultCode.MODEL_NOT_EXIST);
}
this.removeById(modelId);
fusionNumService.deleteByModelId(modelId);
if(StringUtils.isNotBlank(model.getModelGlbUrl())){
uploadService.deleteOssUrl(model.getModelGlbUrl());
}
}
@Override
public List getListByNum(List numList) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(Model::getNum,numList);
return this.list(wrapper);
}
@Override
public List getListByModelIds(List modelIds) {
if(modelIds == null || modelIds.isEmpty()){
return new ArrayList<>();
}
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(Model::getModelId,modelIds);
return this.list(wrapper);
}
@Override
public List getListByModelIdStrs(List numList) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(Model::getModelId,numList);
wrapper.orderByDesc(Model::getCreateTime);
return this.list(wrapper);
}
@Override
public void deleteByNum(List numList) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.in(Model::getNum,numList);
this.remove(wrapper);
}
@Override
public List getByUserName(String username) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Model::getUserName,username)
.eq(Model::getType,3);
return this.list(wrapper);
}
@Override
public Model getIsNullNewByNum(String num,Integer type, Integer isObj) {
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Model::getNum,num);
wrapper.eq(Model::getType,type);
Model model = this.getOne(wrapper);
if(model == null){
model = new Model();
}
if(model.getModelId() != null && StringUtils.isNotBlank(model.getModelGlbUrl()) && StringUtils.isNotBlank(model.getModelSize())){
return model;
}
model.setModelDateType("obj");
model.setType(type);
model.setModelType("pointcloud"); //深时点云类型
model.setCreateStatus(1);
model.setIsObj(isObj);
if(isObj == 1){ //看看,看见
Scene scene = sceneService.getByNum(num);
if(scene == null){
throw new BusinessException(ResultCode.SCENE_NOT_EXIST);
}
String mesh3DtilesPath = String.format(FilePath.OBJ_OSS_PATH,num) + "/images/3dtiles/tileset.json";
String sizePath = scene.getWebPath() + String.format(FilePath.OBJ_OSS_PATH,num) + "/images/3dtiles";
if(localToOssUtil.existKey(scene.getWebPath() +mesh3DtilesPath)){
model.setModelDateType("b3dm");
model.setModelType("b3dm");
model.setModelGlbUrl(JSONArray.toJSONString(Arrays.asList(scene.getMapping() +"/" +mesh3DtilesPath)));
model.setModelSize(FileWriterUtil.setFileSize(localToOssUtil.getSizeCount( sizePath)));
}else {
String meshPath = String.format(FilePath.OBJ_OSS_PATH, num)+"/data/mesh";
if(localToOssUtil.existKey( scene.getWebPath() +meshPath +"/mesh.obj")){
Long size = localToOssUtil.getSizeCount( scene.getWebPath() +meshPath);
model.setModelSize(FileWriterUtil.setFileSize(size));
model.setModelGlbUrl(JSONArray.toJSONString(Arrays.asList(scene.getMapping()+"/" + meshPath+"/mesh.obj")));
}else {
List objPaths = new ArrayList<>();
String meshPathjs = String.format(FilePath.OBJ_OSS_PATH, num)+"/data/";
String jsonPath =scene.getWebPath() + meshPath + "/floors.json";
if(!localToOssUtil.existKey(jsonPath)){
jsonPath =scene.getWebPath() + meshPath +"mesh.json";
}
if(localToOssUtil.existKey(jsonPath)){
String objectContent = localToOssUtil.getObjectContent(meshPath + "/floors.json");
JSONObject jsonObject = JSONObject.parseObject(objectContent);
JSONArray floors1 = jsonObject.getJSONArray("floors");
for (Object object : floors1) {
JSONObject jb = (JSONObject) object;
String string = jb.getString("objPath");
objPaths.add(scene.getMapping()+"/" +meshPathjs + string);
}
model.setModelGlbUrl(JSONArray.toJSONString(objPaths));
Long size = localToOssUtil.getSize(scene.getWebPath() +meshPath);
model.setModelSize(FileWriterUtil.setFileSize(size));
}
}
model.setModelType("obj");
}
}
model.setNum(num);
this.saveOrUpdate(model);
return model;
}
@Override
public SceneVo getInfo(Integer modelId) {
Model model = this.getById(modelId);
if(model == null){
throw new BusinessException(ResultCode.SCENE_NOT_EXIST);
}
SceneVo sceneVo = new SceneVo();
BeanUtils.copyProperties(model,sceneVo);
return sceneVo;
}
@Override
public String uploadObjProgress(Integer modelId) {
String redisKey = RedisKeyUtil.modelUpload+modelId;
String cancel = RedisKeyUtil.modelCancelUpload+modelId;
if(redisUtil.hasKey(cancel)){
return redisUtil.get(cancel);
}
if(redisUtil.hasKey(redisKey)){
return redisUtil.get(redisKey);
}
return "0";
}
@Override
public void cancelUpload(Integer modelId) {
String redisKey = RedisKeyUtil.modelCancelUpload+modelId;
if(redisUtil.hasKey(redisKey)){
return;
}
Model model = this.getById(modelId);
if(model == null){
return;
}
model.setCreateStatus(-2);
this.updateById(model);
redisUtil.set(redisKey,"-2");
}
@Override
public HashMap getMapByNum(List numList) {
HashMap map = new HashMap<>();
List modelList = this.getListByNum(numList);
modelList.forEach(entity-> map.put(entity.getNum() + entity.getType(),entity));
return map;
}
@Override
public void copyModel(Integer modelId) {
Model modelEntity = this.getById(modelId);
if(modelEntity == null){
throw new BusinessException(ResultCode.MODEL_NOT_EXIST);
}
Integer oldId = modelEntity.getModelId();
modelEntity.setModelTitle(modelEntity.getModelTitle() +"(copy)");
modelEntity.setModelId(null);
this.save(modelEntity);
// if(StringUtils.isNotBlank(modelEntity.getModelGlbUrl())){
// String modelGlbUrl = modelEntity.getModelGlbUrl();
// copyOssResource(modelGlbUrl,oldId,modelEntity.getModelId());
// String newModelObjUrl = modelGlbUrl.replaceAll(oldId+"",modelEntity.getModelId()+"");
// modelEntity.setModelGlbUrl(newModelObjUrl);
// this.updateById(modelEntity);
// }
}
private String getGlbUrl(Integer type, String num,Model model,String scenePath) {
if(type == 0 || type == 1 || type == 4 || type == 6 || type == 7){ //看看,看见
//ShellUtil.yunDownload(String.format(FilePath.OBJ_OSS_PATH, num)+"/data/mesh" ,objPath);
String objPathSource = scenePath + String.format(FilePath.OBJ_OSS_PATH, num)+"/data/mesh";
String objPath = String.format(FilePath.OBJ_LOCAL_PATH ,environment,num);
ShellUtil.yunDownload(objPathSource ,objPath);
List localGlbPaths = new ArrayList<>();
List ossGlbPaths = new ArrayList<>();
File localFile = new File(objPath);
this.toGlB(localFile,localGlbPaths);
Long modelSize = 0L;
if(localGlbPaths.size() >0){
for (String localGlbPath : localGlbPaths) {
String ossGlbPath = localGlbPath.replace(FilePath.LOCAL_BASE_PATH,"fusion/");
localToOssUtil.uploadOss(localGlbPath,ossGlbPath);
if(ossGlbPath.contains("lod_")){
if(ossGlbPath.contains("lod_0")){
ossGlbPaths.add(CacheUtil.mapping +ossGlbPath);
modelSize += localToOssUtil.getSize(ossGlbPath);
}
continue;
}
modelSize += localToOssUtil.getSize(ossGlbPath);
ossGlbPaths.add( CacheUtil.mapping +ossGlbPath);
}
model.setModelSize(FileWriterUtil.setFileSize(modelSize));
FileUtil.del(objPath);
return JSONArray.toJSONString(ossGlbPaths);
}
FileUtil.del(objPath);
}
return null;
}
private void toGlB(File localFile, List localGlbPath) {
File[] files = localFile.listFiles();
for (File file : files) {
if(file.isDirectory()){
toGlB(file,localGlbPath);
}
if(file.getName().contains(".obj")){
String glbPath = OBJToGLBUtil.objToGlb(file.getPath(),file.getPath().replace(".obj",".glb") );
localGlbPath.add(glbPath);
}
}
}
}