houzhongjian
2024-12-05 a709abfd8ffec1524cefff30c3581f4425695433
提交 | 用户 | 时间
449017 1 package com.iailab.module.model.mpk.service.impl;
D 2
3 import cn.hutool.core.io.FileUtil;
4 import cn.hutool.core.util.RuntimeUtil;
5 import cn.hutool.core.util.ZipUtil;
6 import com.alibaba.fastjson.JSON;
8b3ee3 7 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
449017 8 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
D 9 import com.baomidou.mybatisplus.core.metadata.IPage;
10 import com.iailab.framework.common.page.PageData;
c12dae 11 import com.iailab.framework.common.pojo.CommonResult;
449017 12 import com.iailab.framework.common.service.impl.BaseServiceImpl;
D 13 import com.iailab.framework.common.util.date.DateUtils;
14 import com.iailab.framework.common.util.object.ConvertUtils;
15 import com.iailab.framework.security.core.util.SecurityFrameworkUtils;
558ffc 16 import com.iailab.framework.tenant.core.context.TenantContextHolder;
449017 17 import com.iailab.module.infra.api.config.ConfigApi;
D 18 import com.iailab.module.model.mpk.common.MdkConstant;
c12dae 19 import com.iailab.module.model.mpk.common.utils.DllUtils;
449017 20 import com.iailab.module.model.mpk.common.utils.GenUtils;
D 21 import com.iailab.module.model.mpk.dao.MpkFileDao;
1fea3e 22 import com.iailab.module.model.mpk.dto.GeneratorCodeHistoryDTO;
0425a3 23 import com.iailab.module.model.mpk.dto.MethodSettingDTO;
1fea3e 24 import com.iailab.module.model.mpk.dto.ModelMethodDTO;
D 25 import com.iailab.module.model.mpk.dto.MpkFileDTO;
26 import com.iailab.module.model.mpk.entity.GeneratorCodeHistoryEntity;
27 import com.iailab.module.model.mpk.entity.MpkFileEntity;
558ffc 28 import com.iailab.module.model.mpk.entity.ProjectPackageHistoryEntity;
1fea3e 29 import com.iailab.module.model.mpk.entity.ProjectPackageHistoryModelEntity;
449017 30 import com.iailab.module.model.mpk.service.*;
D 31 import lombok.extern.slf4j.Slf4j;
32 import org.apache.commons.io.FileUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.velocity.VelocityContext;
35 import org.apache.velocity.app.Velocity;
36 import org.springframework.beans.factory.annotation.Autowired;
a27351 37 import org.springframework.beans.factory.annotation.Value;
449017 38 import org.springframework.stereotype.Service;
D 39 import org.springframework.util.CollectionUtils;
40 import org.springframework.web.multipart.MultipartFile;
41
f7932f 42 import java.io.*;
c12dae 43 import java.net.URLClassLoader;
912a1e 44 import java.nio.file.Files;
449017 45 import java.util.*;
D 46 import java.util.stream.Collectors;
47
48 /**
49  * @author PanZhibao
50  * @Description
51  * @createTime 2024年08月14日
52  */
53 @Slf4j
54 @Service
0255ea 55 public class MpkFileServiceImpl extends BaseServiceImpl<MpkFileDao, MpkFileEntity> implements MpkFileService {
449017 56
D 57     @Autowired
58     private GeneratorCodeHistoryService generatorCodeHistoryService;
8b3ee3 59
449017 60     @Autowired
D 61     private ProjectPackageHistoryService projectPackageHistoryService;
8b3ee3 62
449017 63     @Autowired
D 64     private ModelMethodService modelMethodService;
8b3ee3 65
449017 66     @Autowired
D 67     private ProjectPackageHistoryModelService projectPackageHistoryModelService;
68
69     @Autowired
70     private ConfigApi configApi;
71
1fea3e 72     @Value("${mpk.bak-file-path}")
a27351 73     private String mpkBakFilePath;
1fea3e 74
D 75     @Value("${mpk.bak-resources}")
76     private String mpkResources;
449017 77
D 78     @Override
79     public PageData<MpkFileDTO> page(Map<String, Object> params) {
80         IPage<MpkFileEntity> page = baseDao.selectPage(
81                 getPage(params, "create_date", false),
82                 getWrapper(params)
83         );
84
85         return getPageData(page, MpkFileDTO.class);
86     }
87
88     @Override
89     public List<MpkFileDTO> list(Map<String, Object> params) {
4f4b05 90 //        List<MpkFileEntity> entityList = baseDao.selectList(getWrapper(params).orderByDesc("create_date"));
D 91         List<MpkFileDTO> list = baseDao.list(params);
449017 92
4f4b05 93         return list;
449017 94     }
D 95
8b3ee3 96     private QueryWrapper<MpkFileEntity> getWrapper(Map<String, Object> params) {
449017 97         String pyName = (String) params.get("pyName");
D 98         String pyType = (String) params.get("pyType");
99         String remark = (String) params.get("remark");
d8db4b 100         String label = (String) params.get("label");
449017 101
D 102         QueryWrapper<MpkFileEntity> wrapper = new QueryWrapper<>();
22d6c7 103         wrapper.like(StringUtils.isNotBlank(pyName), "py_chinese_name", pyName)
449017 104                 .eq(StringUtils.isNotBlank(pyType), "py_type", pyType)
D 105                 .like(StringUtils.isNotBlank(remark), "remark", remark);
d8db4b 106
107         if (StringUtils.isNotBlank(label)) {
108             wrapper.and(w -> {
109                 w.eq(StringUtils.isNotBlank(label),"menu_name", label)
110                         .or().eq(StringUtils.isNotBlank(label),"group_name", label);
111             });
112         }
449017 113         return wrapper;
D 114     }
115
116     @Override
117     public MpkFileDTO get(String id) {
118         MpkFileDTO entity = baseDao.get(id);
119
120         return entity;
121     }
122
123     @Override
8b3ee3 124     @DSTransactional(rollbackFor = Exception.class)
449017 125     public void save(MpkFileDTO dto) {
D 126         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
8b3ee3 127         entity.setId(UUID.randomUUID().toString());
ed8ba3 128         entity.setPkgName(dto.getPkgName().trim());
129         entity.setFilePath(dto.getFilePath().trim());
449017 130         entity.setCreator(SecurityFrameworkUtils.getLoginUserId());
D 131         entity.setCreateDate(new Date());
132         insert(entity);
bb0155 133
0425a3 134         // 将备份的pyd文件,转移到MDK_PKGS环境变量下,并添加方法的默认参数(pyFile,模型路径)
D 135         String mdkPkgs = System.getenv("MDK_PKGS");
136         String fileName = entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\") + 1,entity.getFilePath().lastIndexOf(".pyd"));
137
138         String pyFilePath = mdkPkgs + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + fileName + ".pyd";
139         FileUtil.mkParentDirs(pyFilePath);
140         FileUtil.copy(entity.getFilePath(), pyFilePath, true);
141
142         // 添加参数
143         for (ModelMethodDTO method : dto.getModelMethods()) {
144             List<MethodSettingDTO> methodSettings = method.getMethodSettings();
145             if (methodSettings.stream().anyMatch(e -> e.getSettingKey().equals(MdkConstant.PY_FILE_KEY))) {
146                 methodSettings.forEach(e -> {
147                     if (e.getSettingKey().equals(MdkConstant.PY_FILE_KEY)) {
148                         e.setValue(entity.getPyModule() + "." + fileName);
149                     }
150                 });
151             }else {
152                 MethodSettingDTO setting = new MethodSettingDTO();
153                 setting.setId(UUID.randomUUID().toString());
154                 setting.setMethodId(method.getId());
155                 setting.setSettingKey(MdkConstant.PY_FILE_KEY);
156                 setting.setValue(entity.getPyModule() + "." + fileName);
157                 setting.setName("模型路径");
158                 setting.setType("input");
159                 setting.setValueType("string");
160                 methodSettings.add(setting);
161             }
162         }
163
164         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 165     }
D 166
167     @Override
8b3ee3 168     @DSTransactional(rollbackFor = Exception.class)
449017 169     public void update(MpkFileDTO dto) {
784ce3 170         // 添加方法的默认参数(pyFile,模型路径)
D 171         String mdkPkgs = System.getenv("MDK_PKGS");
172         String fileName = dto.getFilePath().substring(dto.getFilePath().lastIndexOf("\\") + 1,dto.getFilePath().lastIndexOf(".pyd"));
173         String pyFilePath = mdkPkgs + File.separator + dto.getPyModule().replace(".", File.separator) + File.separator + fileName + ".pyd";
174         // 判断文件是否存在,不存在的话将备份的pyd文件,转移到MDK_PKGS环境变量下
175         File pyFile = new File(pyFilePath);
176         if (!pyFile.exists()) {
0425a3 177             FileUtil.mkParentDirs(pyFilePath);
D 178             FileUtil.copy(dto.getFilePath(), pyFilePath, true);
784ce3 179         }
0425a3 180
784ce3 181         // 添加/修改参数
D 182         for (ModelMethodDTO method : dto.getModelMethods()) {
183             List<MethodSettingDTO> methodSettings = method.getMethodSettings();
184             if (methodSettings.stream().anyMatch(e -> e.getSettingKey().equals(MdkConstant.PY_FILE_KEY))) {
185                 methodSettings.forEach(e -> {
186                     if (e.getSettingKey().equals(MdkConstant.PY_FILE_KEY)) {
187                         e.setValue(dto.getPyModule() + "." + fileName);
188                     }
189                 });
190             }else {
191                 MethodSettingDTO setting = new MethodSettingDTO();
192                 setting.setId(UUID.randomUUID().toString());
193                 setting.setMethodId(method.getId());
194                 setting.setSettingKey(MdkConstant.PY_FILE_KEY);
195                 setting.setValue(dto.getPyModule() + "." + fileName);
196                 setting.setName("模型路径");
197                 setting.setType("input");
198                 setting.setValueType("string");
199                 methodSettings.add(setting);
0425a3 200             }
D 201         }
202
449017 203         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
D 204         entity.setUpdater(SecurityFrameworkUtils.getLoginUserId());
205         entity.setUpdateDate(new Date());
206         updateById(entity);
8b3ee3 207         modelMethodService.deleteModelMethod(entity.getId());
208         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 209     }
D 210
211     @Override
8b3ee3 212     @DSTransactional(rollbackFor = Exception.class)
449017 213     public void delete(String id) {
D 214
215         //删除源文件
216         MpkFileEntity mpkFileEntity = selectById(id);
217         if (StringUtils.isNoneBlank(mpkFileEntity.getFilePath())) {
218             File mpkFile = new File(mpkFileEntity.getFilePath());
219             if (mpkFile.exists()) {
220                 mpkFile.delete();
221                 log.info("删除源文件备份文件:" + mpkFileEntity.getFilePath());
222             }
223         }
224
225         //删除备份文件
8b3ee3 226         Map<String, Object> map1 = new HashMap<>();
227         map1.put("mdkId", id);
449017 228         List<GeneratorCodeHistoryDTO> list = generatorCodeHistoryService.list(map1);
D 229         list.forEach(e -> {
230             File file = new File(e.getFilePath());
231             if (file.exists()) {
232                 file.delete();
233                 log.info("删除生成代码备份文件:" + e.getFilePath());
234             }
235         });
236
0255ea 237         //删除 会级联删除掉关联表
D 238         deleteById(id);
449017 239     }
D 240
241     @Override
242     public byte[] generatorCode(String id, String remark, String zipFileName) {
558ffc 243         Long tenantId = TenantContextHolder.getTenantId();
D 244         // 备份文件 租户隔离
245         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
246
449017 247         MpkFileDTO entity = baseDao.get(id);
D 248         //生成代码
1fea3e 249         //设置velocity资源加载器
D 250         Properties prop = new Properties();
251         prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
252         Velocity.init(prop);
449017 253
1fea3e 254         //封装模板数据
D 255         Map<String, Object> map = new HashMap<>();
256         map.put("pkgName",entity.getPkgName());
257         map.put("modelMethods",entity.getModelMethods());
258         map.put("pyName",entity.getPyName());
259         map.put("pyModule",entity.getPyModule());
260
261         VelocityContext dataContext = new VelocityContext(map);
262
263         //临时文件夹
912a1e 264         File dirPath = null;
D 265         try {
266             dirPath = Files.createTempDirectory("generatorCodeTmp").toFile();
267             log.info("生成临时文件夹," + dirPath.getAbsolutePath());
268         } catch (IOException e) {
269             throw new RuntimeException("创建临时文件夹异常",e);
270         }
1fea3e 271
D 272         List<String> javaFilePaths = new ArrayList<>();
273         List<String> cppFilePaths = new ArrayList<>();
274
275         //生成java文件
276         File javaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + entity.getPyName() + ".java");
277         GenUtils.drawTemplate("abstract.java.vm", dataContext, javaFile);
278         javaFilePaths.add(javaFile.getAbsolutePath());
279
280         //生成Impl.java文件
281         File implJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + MdkConstant.IMPL + File.separator + entity.getPyName() + "Impl.java");
282         GenUtils.drawTemplate("impl.java.vm", dataContext, implJavaFile);
283         javaFilePaths.add(implJavaFile.getAbsolutePath());
284
285         //生成.cpp文件
286         File cppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".cpp");
287         GenUtils.drawTemplate("cpp.vm", dataContext, cppFile);
288         cppFilePaths.add(cppFile.getAbsolutePath());
289
290         //生成Jni.cpp文件
291         File jniCppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.cpp");
292         GenUtils.drawTemplate("Jni.cpp.vm", dataContext, jniCppFile);
293         cppFilePaths.add(jniCppFile.getAbsolutePath());
294
295         //生成.h文件
296         File hFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".h");
297         GenUtils.drawTemplate("h.vm", dataContext, hFile);
298
299         //生成Jni.h文件
300         File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h");
301         GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile);
a8c6a6 302
D 303         // 添加python源文件
8c86a9 304         String pyFilePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.ALGS + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\"));
a8c6a6 305         FileUtil.mkParentDirs(pyFilePath);
D 306         FileUtil.copy(entity.getFilePath(), pyFilePath, true);
1fea3e 307
D 308         // 资源文件
309         FileUtil.copy(mpkResources + File.separator + "libs", dirPath.getAbsolutePath(), true);
310
311         //生成dll文件
312         String dllSavePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "IAIL.MDK.Mid.Jni.dll";
313         createDllFile(dirPath.getAbsolutePath(),cppFilePaths,dllSavePath);
314         //备份dll文件,用于后续运行
558ffc 315         String dllBakPath = mpkTenantBakFilePath + File.separator + MdkConstant.DLL + File.separator + entity.getPyName() + ".dll";
1fea3e 316         FileUtil.mkParentDirs(dllBakPath);
D 317         FileUtil.copy(dllSavePath, dllBakPath, true);
318
319         //utils + env java文件
320         File utilsJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "utils" + File.separator + "AlgsUtils.java");
321         FileUtil.mkParentDirs(utilsJavaFile);
322         FileUtil.copy(mpkResources + File.separator +"IAILMDK/utils/AlgsUtils.java", utilsJavaFile.getAbsolutePath(), true);
323         javaFilePaths.add(utilsJavaFile.getAbsolutePath());
324         File envJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "common" + File.separator + "Environment.java");
325         FileUtil.mkParentDirs(envJavaFile);
326         FileUtil.copy(mpkResources + File.separator +"IAILMDK/common/Environment.java", envJavaFile.getAbsolutePath(), true);
327         javaFilePaths.add(envJavaFile.getAbsolutePath());
328         // 生成class文件
329         createClassFile(javaFilePaths);
330         // 删除java源文件
331         deleteJavaFile(javaFilePaths);
332         // 打jar包
333         String jarSavePath = pkgJar(dirPath.getAbsolutePath());
334         //备份jar文件,用于后续运行
558ffc 335         String jarBakPath = mpkTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + entity.getPyName() + ".jar";
1fea3e 336         FileUtil.mkParentDirs(dllBakPath);
D 337         FileUtil.copy(jarSavePath, jarBakPath, true);
338         // 打zip包
558ffc 339         String zipPath = mpkTenantBakFilePath + File.separator + zipFileName;
1fea3e 340         ZipUtil.zip(dirPath.getAbsolutePath(), zipPath);
D 341         byte[] bytes = FileUtil.readBytes(zipPath);
449017 342
D 343         //代码生成历史记录
344         GeneratorCodeHistoryEntity historyEntity = new GeneratorCodeHistoryEntity();
345         historyEntity.setId(UUID.randomUUID().toString());
346         historyEntity.setMdkId(id);
1fea3e 347         historyEntity.setFileName(zipFileName);
D 348         historyEntity.setFilePath(zipPath);
449017 349         historyEntity.setRemark(remark);
D 350         historyEntity.setCreateTime(new Date());
351         generatorCodeHistoryService.insert(historyEntity);
352
1fea3e 353         // 删除临时文件
3009e2 354         try {
D 355             FileUtils.deleteDirectory(dirPath);
356         } catch (IOException e) {
912a1e 357             throw new RuntimeException("删除临时文件异常",e);
3009e2 358         }
1fea3e 359         return bytes;
449017 360     }
D 361
362     @Override
8b3ee3 363     @DSTransactional(rollbackFor = Exception.class)
f7932f 364     public byte[] packageModel(List<String> ids, String projectId, String projectName, String zipFileName, String logs, String version) throws IOException, InterruptedException {
558ffc 365         Long tenantId = TenantContextHolder.getTenantId();
D 366         // 备份文件 租户隔离
367         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
368
449017 369         List<MpkFileDTO> entities = baseDao.selectByIds(ids);
D 370
371         //模板数据
1fea3e 372 //        Map<String, Object> map = new HashMap<>();
D 373 //        map.put("entities", entities);
374 //        VelocityContext context = new VelocityContext(map);
449017 375
D 376         //临时文件夹
912a1e 377         File dirPath = null;
D 378         try {
379             dirPath = Files.createTempDirectory("packageModelTmp").toFile();
380             log.info("生成临时文件夹," + dirPath.getAbsolutePath());
381         } catch (IOException e) {
382             throw new RuntimeException("创建临时文件夹异常",e);
383         }
449017 384
D 385         //设置velocity资源加载器
386         Properties prop = new Properties();
387         prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
388         Velocity.init(prop);
389
a27351 390         //生成menu.xml文件
2cc235 391         LinkedHashMap<String, LinkedHashMap<String, List<MpkFileDTO>>> collect = entities.stream().collect(Collectors.groupingBy(MpkFileDTO::getMenuName, LinkedHashMap::new, Collectors.groupingBy(e -> StringUtils.isNotBlank(e.getGroupName()) ? e.getGroupName() : "default_group",LinkedHashMap::new,Collectors.toList())));
a27351 392         Map<String, Object> map1 = new HashMap<>();
8b3ee3 393         map1.put("collects", collect);
c7009e 394         File xmlFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "menu.xml");
8b3ee3 395         GenUtils.drawTemplate("menu.xml.vm", new VelocityContext(map1), xmlFile);
449017 396
D 397         List<String> javaFilePaths = new ArrayList<>();
f7932f 398         List<String> cppFilePaths = new ArrayList<>();
449017 399
D 400         //生成java文件
401         for (MpkFileDTO entity : entities) {
402             //封装模板数据
403             Map<String, Object> data = new HashMap<>();
8b3ee3 404             data.put("pkgName", entity.getPkgName());
405             data.put("modelMethods", entity.getModelMethods());
406             data.put("pyName", entity.getPyName());
407             data.put("pyModule", entity.getPyModule());
449017 408             VelocityContext dataContext = new VelocityContext(data);
D 409             //生成java文件
410             File javaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + entity.getPyName() + ".java");
8b3ee3 411             GenUtils.drawTemplate("abstract.java.vm", dataContext, javaFile);
449017 412             javaFilePaths.add(javaFile.getAbsolutePath());
D 413
414             //生成Impl.java文件
415             File implJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + MdkConstant.IMPL + File.separator + entity.getPyName() + "Impl.java");
8b3ee3 416             GenUtils.drawTemplate("impl.java.vm", dataContext, implJavaFile);
449017 417             javaFilePaths.add(implJavaFile.getAbsolutePath());
D 418
f7932f 419             //生成.cpp文件
D 420             File cppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".cpp");
421             GenUtils.drawTemplate("cpp.vm", dataContext, cppFile);
422             cppFilePaths.add(cppFile.getAbsolutePath());
423
424             //生成Jni.cpp文件
425             File jniCppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.cpp");
426             GenUtils.drawTemplate("Jni.cpp.vm", dataContext, jniCppFile);
427             cppFilePaths.add(jniCppFile.getAbsolutePath());
428
429             //生成.h文件
430             File hFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".h");
431             GenUtils.drawTemplate("h.vm", dataContext, hFile);
432
433             //生成Jni.h文件
434             File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h");
435             GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile);
436
449017 437             // 添加python源文件
8c86a9 438             String pyFilePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.ALGS + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\"));
449017 439             FileUtil.mkParentDirs(pyFilePath);
8b3ee3 440             FileUtil.copy(entity.getFilePath(), pyFilePath, true);
449017 441         }
D 442
1fea3e 443         // 资源文件
D 444         FileUtil.copy(mpkResources + File.separator + "libs", dirPath.getAbsolutePath(), true);
c7009e 445
f7932f 446         //生成dll文件
c7009e 447         String dllSavePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "IAIL.MDK.Mid.Jni.dll";
f7932f 448         createDllFile(dirPath.getAbsolutePath(),cppFilePaths,dllSavePath);
c12dae 449         // 打包历史id
D 450         String historyId = UUID.randomUUID().toString();
451         //备份dll,发布时使用
452         File dllFile = new File(dllSavePath);
453         if (dllFile.exists()) {
558ffc 454             File dllBakFile = new File(mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll");
c12dae 455             FileUtil.copy(dllFile, dllBakFile, true);
D 456         }else {
457             log.error("dll文件不存在,无法备份。" + dllSavePath);
458         }
f7932f 459
449017 460         //utils + env java文件
c7009e 461         File utilsJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "utils" + File.separator + "AlgsUtils.java");
449017 462         FileUtil.mkParentDirs(utilsJavaFile);
1fea3e 463         FileUtil.copy(mpkResources + File.separator +"IAILMDK/utils/AlgsUtils.java", utilsJavaFile.getAbsolutePath(), true);
449017 464         javaFilePaths.add(utilsJavaFile.getAbsolutePath());
c7009e 465         File envJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "common" + File.separator + "Environment.java");
449017 466         FileUtil.mkParentDirs(envJavaFile);
1fea3e 467         FileUtil.copy(mpkResources + File.separator +"IAILMDK/common/Environment.java", envJavaFile.getAbsolutePath(), true);
449017 468         javaFilePaths.add(envJavaFile.getAbsolutePath());
D 469         // 生成class文件
470         createClassFile(javaFilePaths);
471         // 删除java源文件
472         deleteJavaFile(javaFilePaths);
473         // 打jar包
c12dae 474         String jarSavePath = pkgJar(dirPath.getAbsolutePath());
D 475         //备份jar包,发布时使用
476         File jarFile = new File(jarSavePath);
477         if (jarFile.exists()) {
558ffc 478             File jarBakFile = new File(mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar");
c12dae 479             FileUtil.copy(jarFile, jarBakFile, true);
D 480         }else {
481             log.error("jar文件不存在,无法备份。" + jarSavePath);
482         }
483
449017 484         // 本次更新日志
558ffc 485         ProjectPackageHistoryEntity projectPackageHistoryEntity = new ProjectPackageHistoryEntity();
D 486         projectPackageHistoryEntity.setId(historyId);
487         projectPackageHistoryEntity.setProjectId(projectId);
488         projectPackageHistoryEntity.setFileName(zipFileName);
489         projectPackageHistoryEntity.setLog(logs);
490         projectPackageHistoryEntity.setVersion(version);
491         projectPackageHistoryEntity.setModelNames(entities.stream().map(MpkFileDTO::getPyName).collect(Collectors.joining(",")));
492         projectPackageHistoryEntity.setCreateTime(new Date());
449017 493         // 生成更新日志
558ffc 494         createLog(projectId, projectName, dirPath.getAbsolutePath(), projectPackageHistoryEntity, version);
449017 495         // 打zip包
558ffc 496         String zipPath = mpkTenantBakFilePath + File.separator + zipFileName;
8b3ee3 497         ZipUtil.zip(dirPath.getAbsolutePath(), zipPath);
449017 498         byte[] bytes = FileUtil.readBytes(zipPath);
D 499         // 记录打包日志
558ffc 500         projectPackageHistoryEntity.setFilePath(zipPath);
D 501         projectPackageHistoryService.insert(projectPackageHistoryEntity);
449017 502         // 插入打包历史-模型关联表
D 503         List<ProjectPackageHistoryModelEntity> historyModelList = new ArrayList<>(entities.size());
504         entities.forEach(e -> {
505             ProjectPackageHistoryModelEntity entity = new ProjectPackageHistoryModelEntity();
506             entity.setId(UUID.randomUUID().toString());
507             entity.setProjectId(projectId);
508             entity.setPackageHistoryId(historyId);
509             entity.setPyName(e.getPyName());
067d7a 510             entity.setPyChineseName(e.getPyChineseName());
449017 511             entity.setPkgName(e.getPkgName());
D 512             entity.setPyModule(e.getPyModule());
513             entity.setRemark(e.getRemark());
0255ea 514             List<ModelMethodDTO> methods = e.getModelMethods();
449017 515             if (!CollectionUtils.isEmpty(methods)) {
D 516                 entity.setMethodInfo(JSON.toJSONString(methods));
517             }
518             historyModelList.add(entity);
519         });
558ffc 520         projectPackageHistoryModelService.insertList(historyModelList);
449017 521         // 删除临时文件
D 522         FileUtils.deleteDirectory(dirPath);
523         return bytes;
524     }
525
1fea3e 526     private void createDllFile(String dirPath, List<String> cppFilePaths, String dllSavePath) {
D 527         try {
528             String paths = cppFilePaths.stream().collect(Collectors.joining(" "));
529             String command = "cl /LD " + paths + " /EHsc /o " + dllSavePath + " /link " + "IAIL.MDK.Mid.Windows.lib";
530             log.info("执行cmd命令生成dll:" + command);
531             ProcessBuilder builder = new ProcessBuilder("cmd", "/c", command);
532             builder.directory(new File(dirPath + File.separator + MdkConstant.LIBS));
533             Process process = builder.start();
534             // 获取命令输出结果
535             InputStream inputStream = process.getInputStream();
536             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBK
537             String line;
538             while ((line = reader.readLine()) != null) {
539                 log.info(line);
540             }
541             // 等待命令执行完成
542             process.waitFor();
543         } catch (Exception e) {
912a1e 544             throw new RuntimeException("执行cmd命令生成dll异常",e);
f7932f 545         }
D 546     }
547
449017 548     @Override
8b3ee3 549     public Map<String, String> savePyFile(MultipartFile file) throws IOException {
558ffc 550         Long tenantId = TenantContextHolder.getTenantId();
D 551         // 备份文件 租户隔离
552         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
a8c6a6 553         File bakDir = new File(mpkTenantBakFilePath);
D 554         if (!bakDir.exists()) {
555             bakDir.mkdirs();
556         }
557         //临时文件夹
558         File tempDir = null;
559         try {
560             tempDir = Files.createTempDirectory("pyFileTmp").toFile();
561             log.info("生成临时文件夹," + tempDir.getAbsolutePath());
562         } catch (IOException e) {
563             throw new RuntimeException("创建临时文件夹异常",e);
449017 564         }
D 565         String fileName = file.getOriginalFilename();
a8c6a6 566         String pyName = fileName.substring(0, fileName.lastIndexOf("."));
0425a3 567         String pyName_uuTime = pyName + "_" + new Date().getTime();
D 568
569         File pydBakFile = new File(bakDir.getAbsolutePath() + File.separator + pyName_uuTime + ".pyd");
a8c6a6 570         try {
D 571             // py文件存入临时文件夹
572             File saveFile = new File(tempDir.getAbsolutePath() + File.separator + fileName);
573             saveFile.createNewFile();
574             file.transferTo(saveFile);
575
576             // 临时文件夹中生成pyd文件
577             // 生成setup.py文件
0425a3 578             createSetUpFile(tempDir.getAbsolutePath(),fileName,pyName_uuTime);
a8c6a6 579             // 执行cmd命令编译pyd文件
D 580             createPydFile(tempDir.getAbsolutePath());
581
582             // 临时文件夹中pyd文件移到dir下,修改为uuid.pyd
0425a3 583             File pydFile = new File(tempDir.getAbsolutePath() + File.separator + pyName_uuTime + MdkConstant.PYD_SUFFIX);
a8c6a6 584             if (!pydFile.exists()) {
D 585                 throw new RuntimeException("编译pyd文件失败!");
586             }
587             log.info("备份pyd文件," + pydBakFile.getAbsolutePath());
588             FileUtil.copy(pydFile,pydBakFile,true);
589         } catch (Exception e) {
590             throw new RuntimeException("编译pyd文件异常");
591         } finally {
592             if (tempDir.exists()) {
593                 tempDir.delete();
594             }
595         }
449017 596
8b3ee3 597         Map<String, String> result = new HashMap<>(2);
a8c6a6 598         result.put("filePath", pydBakFile.getAbsolutePath());
D 599         result.put("fileName", pyName);
449017 600
D 601         return result;
602     }
603
a8c6a6 604     private void createPydFile(String dir) {
D 605         try {
606             String command = "python setup.py build_ext --inplace";
607             log.info("执行cmd命令编译pyd:" + command);
608             ProcessBuilder builder = new ProcessBuilder("cmd", "/c", command);
609             builder.directory(new File(dir));  // 设置工作目录
610             builder.redirectErrorStream(true);  // 将错误输出和标准输出合并
611             Process process = builder.start();
612             // 获取命令输出结果
613             InputStream inputStream = process.getInputStream();
614             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBK
615             String line;
616             while ((line = reader.readLine()) != null) {
617                 log.info(line);
618             }
619             // 等待命令执行完成
620             process.waitFor();
621         } catch (Exception e) {
622             throw new RuntimeException("执行cmd命令生成dll异常", e);
623         }
624     }
625
626     private void createSetUpFile(String dir, String pyFileName, String pyName) {
627         // 生成setup.py文件
628         HashMap<String,Object> map = new HashMap<>();
629         map.put("fileName",pyFileName);
630         map.put("pyName",pyName);
631         GenUtils.drawTemplate("setup.py.vm",map,new File(dir + File.separator + MdkConstant.SETUP_PY));
632     }
633
c12dae 634     @Override
D 635     public CommonResult<String> publish(Map<String, Object> params) {
636         String historyId = (String) params.get("historyId");
637         String projectId = (String) params.get("projectId");
638
639         // 判断新的dll和jar文件是否存在
558ffc 640         String jarFileBakPath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar";
D 641         String dllFileBakPath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll";
c12dae 642         if (!FileUtil.exist(jarFileBakPath)) {
D 643             throw new RuntimeException("jar文件不存在," + jarFileBakPath);
644         }
645         if (!FileUtil.exist(dllFileBakPath)) {
646             throw new RuntimeException("dll文件不存在" + dllFileBakPath);
647         }
648
649         try {
650             // 卸载之前的dll和jar
651             DllUtils.removeClassLoaderCache(projectId);
652             // 删除之前的dll和jar备份文件
653             DllUtils.removeOldFile(mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH,projectId);
654         } catch (Exception e) {
655             throw new RuntimeException("卸载之前的dll和jar异常",e);
656         }
657
658         // 备份新的dll和jar
659         String jarFilePath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar";
660         String dllFilePath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll";
661         FileUtil.copy(jarFileBakPath,jarFilePath,true);
662         FileUtil.copy(dllFileBakPath,dllFilePath,true);
663
664         URLClassLoader urlClassLoader = null;
665         try {
666             // 加载新的jar
667             urlClassLoader = DllUtils.loadJar(jarFilePath);
668         } catch (Exception e) {
669             throw new RuntimeException("加载新的jar异常",e);
670         }
671
672         try {
673             // 加载新的dll
674             DllUtils.loadDll(urlClassLoader.loadClass("iail.mdk.model.common.Environment"),dllFilePath);
675         } catch (Exception e) {
676             DllUtils.unloadJar(urlClassLoader);
677             throw new RuntimeException("加载新的dll异常",e);
678         }
679         // 都加载成功后加入缓存
680         DllUtils.addClassLoaderCache(projectId,urlClassLoader);
681
682         return CommonResult.success();
683     }
684
558ffc 685     private void createLog(String projectId, String projectName, String dirPath, ProjectPackageHistoryEntity projectPackageHistoryEntity, String version) {
8b3ee3 686         Map<String, Object> map = new HashMap<>();
687         map.put("projectId", projectId);
558ffc 688         List<ProjectPackageHistoryEntity> list = projectPackageHistoryService.list(map);
D 689         list.add(projectPackageHistoryEntity);
449017 690         // 按照日期分组再排序
558ffc 691         HashMap<String, List<ProjectPackageHistoryEntity>> dataMap = list.stream().collect(
449017 692                 Collectors.groupingBy(e -> DateUtils.format(e.getCreateTime(), DateUtils.DATE_PATTERN_POINT),
8b3ee3 693                         LinkedHashMap::new,
558ffc 694                         Collectors.collectingAndThen(Collectors.toList(), e -> e.stream().sorted(Comparator.comparing(ProjectPackageHistoryEntity::getCreateTime)).collect(Collectors.toList()))));
449017 695
D 696         Map<String, Object> data = new HashMap<>();
8b3ee3 697         data.put("dataMap", dataMap);
698         data.put("projectName", projectName);
699         data.put("version", version);
700         data.put("now", DateUtils.format(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
449017 701
D 702         File logFile = new File(dirPath + File.separator + "更新日志.txt");
8b3ee3 703         GenUtils.drawTemplate("log.txt.vm", data, logFile);
449017 704     }
D 705
3009e2 706     private String pkgJar(String dirPath) {
D 707         try {
708             String jarSavePath = dirPath + File.separator + MdkConstant.LIBS + File.separator + "IAILMDK.jar";
709             StringBuilder sb = new StringBuilder();
710             sb.append("jar -cvf");
711             sb.append(" ").append(jarSavePath);
712             sb.append(" -C ").append(dirPath).append(File.separator).append("IAILMDK").append(File.separator).append(" .");
713             log.info("执行cmd命令打jar包:" + sb);
714             Process process = RuntimeUtil.exec(sb.toString());
715             process.waitFor();
716             return jarSavePath;
717         } catch (InterruptedException e) {
912a1e 718             throw new RuntimeException("执行cmd命令打jar包异常",e);
3009e2 719         }
449017 720     }
D 721
722     private void deleteJavaFile(List<String> javaFilePaths) {
723         for (String javaFilePath : javaFilePaths) {
724             FileUtil.del(javaFilePath);
725         }
726     }
727
3009e2 728     private void createClassFile(List<String> javaFilePaths){
D 729         try {
730             StringBuilder sb = new StringBuilder();
731             sb.append("javac -encoding utf-8");
732             for (String path : javaFilePaths) {
733                 sb.append(" ").append(path);
734             }
735             log.info("执行cmd命令生成class:" + sb);
736             Process process = RuntimeUtil.exec(sb.toString());
737             process.waitFor();
738         } catch (InterruptedException e) {
912a1e 739             throw new RuntimeException("执行cmd命令生成class异常",e);
449017 740         }
D 741     }
742 }