123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549 |
- import {app, BrowserWindow, ipcMain, dialog} from 'electron';
- import {exec, spawn} from 'child_process';
- import path from 'path';
- import {fileURLToPath} from 'url';
- import fs from 'fs';
- import axios from 'axios';
- import ProcessManager from './processManager.js'
- const processManager = new ProcessManager(); // 创建进程管理器实例
- const __filename = fileURLToPath(import.meta.url);
- const __dirname = path.dirname(__filename);
- const PJI_SCRIPT_PATH_PREFIX = "/home/cicv/work/pji_desktop/"
- // console.log("PJI_SCRIPT_PATH_PREFIX", PJI_SCRIPT_PATH_PREFIX)
- function createWindow() {
- const win = new BrowserWindow({
- width: 800,
- height: 600,
- webPreferences: {
- preload: path.join(__dirname, 'preload.js'), // 确保路径正确
- contextIsolation: true,
- enableRemoteModule: false,
- nodeIntegration: false,
- }
- });
- win.webContents.openDevTools(); // 打开开发者工具进行调试
- win.loadURL('http://localhost:5173'); // 开发环境
- // win.loadURL('http://36.110.106.156:81'); // 生产环境
- console.log('Window created and URL loaded');
- }
- app.whenReady().then(createWindow);
- app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') {
- app.quit();
- }
- });
- app.on('activate', () => {
- if (BrowserWindow.getAllWindows().length === 0) {
- createWindow();
- }
- });
- // // 禁用GPU加速
- // app.disableHardwareAcceleration()
- // ------------- 进程通信 -------------
- ipcMain.handle('dialog:open', async (event, options = {}) => {
- const result = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow() || BrowserWindow.getAllWindows()[0], options);
- return result.canceled ? null : result.filePaths;
- });
- // 下载文件
- ipcMain.handle('download-file', async (event, { url, fileName, savePath, overwriteFlag, dialogFlag, requestType, data }) => {
- try {
- let filePath
- let getPath
- // console.log("url", url)
- // console.log("response", response)
- if (dialogFlag) { // 弹出保存文件对话框
- console.log("savePath", savePath)
- // 获取保存路径
- getPath = await dialog.showSaveDialog({
- defaultPath: path.join(app.getPath('downloads'), fileName)
- })
- filePath = getPath.filePath
- if (getPath.canceled || filePath === "") {
- return { success: false, message: 'File path does not exist' }
- }
- } else {
- filePath = path.join(savePath, fileName);
- }
- console.log("filePath", filePath)
- // 查找文件是否存在
- const fileExists = fs.existsSync(filePath)
- if (fileExists && !overwriteFlag) { // 已存在且不覆盖
- return {success: true, filePath}
- } else { // 不存在
- console.log("url", url)
- let response
- if (requestType === "get") {
- console.log("get...")
- response = await axios.get(url, {responseType: 'stream'});
- } else {
- response = await axios.post(url, data, {responseType: 'stream'});
- }
- console.log("response", response)
- // 写入文件
- const writer = fs.createWriteStream(filePath);
- return new Promise((resolve, reject) => {
- response.data.pipe(writer);
- let error = null;
- writer.on('error', err => {
- error = err;
- writer.close();
- reject(err);
- });
- writer.on('close', () => {
- if (!error) {
- resolve({success: true, filePath}); // 返回成功信息
- } else {
- reject({success: false, error: error.message}); // 返回错误信息
- }
- });
- });
- }
- } catch (error) {
- console.error('下载文件出错:', error);
- throw error;
- }
- });
- // 删除文件
- ipcMain.on('delete-file', (event, {fileName, savePath}) => {
- const filePath = path.join(savePath, fileName);
- // 检查文件是否存在
- if (fs.existsSync(filePath)) {
- // 文件存在,尝试删除
- fs.unlink(filePath, (err) => {
- if (err) {
- event.reply('delete-file-response', { success: false, message: err.message });
- } else {
- event.reply('delete-file-response', { success: true, message: 'File deleted successfully' });
- }
- });
- } else {
- // 文件不存在
- event.reply('delete-file-response', { success: false, message: 'File does not exist' });
- }
- });
- // 上传文件
- ipcMain.on('upload-file', async (event, {filePath, uploadUrl}) => {
- if (!fs.existsSync(filePath)) {
- console.log("File does not exist");
- event.reply('upload-file-response', {success: false, message: 'File does not exist'});
- return;
- }
- try {
- const result = await uploadFile(filePath, uploadUrl);
- console.log("result", result);
- if (result.status) {
- event.reply('upload-file-response', { success: true, message: 'File uploaded successfully', details: result.details });
- } else {
- event.reply('upload-file-response', { success: false, message: 'Error uploading file', details: '' });
- }
- } catch (err) {
- event.reply('upload-file-response', { success: false, message: err.message, details: '' });
- }
- });
- async function uploadFile(filePath, uploadUrl) {
- const data = fs.readFileSync(filePath)
- // 创建formData对象
- const formData = new FormData();
- formData.append('file', new Blob([data]), path.basename(filePath));
- try {
- // 使用axios上传文件
- const response = await axios.post(uploadUrl, formData, {
- headers: {
- 'Content-Type': 'multipart/form-data'
- }
- })
- // console.log('response', response.data)
- return response.data
- } catch (err) {
- console.log("Error uploading file:", err);
- return { status: false, code: '', message: '上传件失败', details: '' };
- }
- }
- async function uploadFileWithRetry(filePath, uploadUrl, maxRetries = 3) {
- let attempt = 1;
- while (attempt <= maxRetries) {
- console.log("Uploading file - attempt:", attempt);
- try {
- const response = await uploadFile(filePath, uploadUrl);
- console.log("response", response);
- if (response.status) { // 上传成功
- return response;
- } else { // 上传失败
- console.log("Fail to upload file - attempt:", attempt);
- attempt++
- }
- } catch (error) {
- console.log("Error uploading file - attempt:", attempt);
- console.log("Error:", error);
- attempt++
- }
- }
- return { status: false, code: '', message: '上传文件失败', details: '' };
- }
- // 导入算法镜像
- ipcMain.on('docker-import', (event, filePath, tag) => {
- const command = 'bash ' + PJI_SCRIPT_PATH_PREFIX + 'docker_import/run_docker_import.sh ' + filePath + ' pji_nav ' + tag
- console.log('Docker import command:', command);
- exec(command, (error, stdout, stderr) => {
- if (error) {
- console.error(`exec error: ${error}`);
- event.reply('docker-import-response', { success: false, message: error.message });
- } else {
- console.log(`stdout: ${stdout}`);
- console.error(`stderr: ${stderr}`);
- event.reply('docker-import-response', { success: true, message: 'Docker image imported successfully' });
- }
- });
- });
- // 更新地图
- ipcMain.on('update-map', (event, {container_name, file_path}) => {
- const command = 'bash ' + PJI_SCRIPT_PATH_PREFIX + '/map_update/run_map_update.sh ' + container_name + ' ' + file_path;
- console.log('command:', command);
- processManager.startProcess('update-map', command, (error, stdout, stderr) => {
- if (error) {
- console.error(`exec error: ${error}`);
- // event.reply('update-map-response', { success: false, message: error.message });
- } else {
- console.log(`stdout: ${stdout}`);
- console.error(`stderr: ${stderr}`);
- if (stdout.toString().includes('Result JSON file created')) { // 判断结束标志
- event.reply('update-map-response', { success: true, message: 'Update map successfully' });
- } else {
- event.reply('update-map-response', { success: false, message: 'Error updating map' });
- }
- }
- });
- });
- // 生成world
- ipcMain.on('generate-world', (event, {rosbag_path}) => {
- const command = 'bash ' + PJI_SCRIPT_PATH_PREFIX + 'simulation/generate_world.sh ' + rosbag_path
- console.log('World generation command:', command);
- exec(command, (error, stdout, stderr) => {
- if (error) {
- console.error(`exec error: ${error}`);
- event.reply('generate-world-response', { success: false, message: error.message });
- } else {
- console.log(`stdout: ${stdout}`);
- console.error(`stderr: ${stderr}`);
- event.reply('generate-world-response', { success: true, message: 'World generated successfully' });
- }
- });
- });
- // 启动仿真环境
- ipcMain.on('start-container', (event, {zip_file_path, image_name, container_name}) => {
- // 使用 spawn 启动脚本
- const serviceProcess = spawn('bash', [PJI_SCRIPT_PATH_PREFIX + "simulation/data_preparation.sh", zip_file_path], { detached: true });
- // 设置为后台进程
- serviceProcess.unref();
- // 监听输出
- serviceProcess.stdout.on('data', (data) => {
- console.log(`第一个脚本的输出: ${data}`);
- // 根据第一个脚本的输出判断其是否准备好
- if (data.toString().includes('Data preparation done')) {
- startSecondScript();
- }
- });
- // 监听错误
- serviceProcess.stderr.on('data', (data) => {
- console.error(`执行第一个脚本时出错: ${data}`);
- });
- // 监听关闭
- serviceProcess.on('close', (data) => {
- console.log(`第一个脚本已关闭: ${data}`);
- });
- function startSecondScript() {
- let command = 'bash ' + PJI_SCRIPT_PATH_PREFIX + "/simulation/start_container.sh " + image_name + " " + container_name
- // 启动第二个脚本
- const script2 = exec(command, (error, stdout, stderr) => {
- if (error) {
- console.error(`执行第二个脚本时出错: ${error}`);
- event.sender.send('start-container-response', { success: false, output: error });
- return;
- }
- console.log(`第二个脚本的输出: ${stdout}`);
- event.sender.send('start-container-response', { success: true, output: stdout });
- });
- script2.on('exit', (code) => {
- console.log(`第二个脚本已退出,退出码: ${code}`);
- });
- }
- });
- // 执行仿真
- ipcMain.on('run-simulation', (event, {random_flag, count, obstacle_flag, default_start_flag, default_end_flag, start_point, end_point}) => {
- const command = 'bash ' + PJI_SCRIPT_PATH_PREFIX + 'simulation/run_simulation.sh ' + random_flag + ' ' + count + ' ' + obstacle_flag + ' ' +
- default_start_flag + ' ' + default_end_flag + ' ' + start_point + ' ' + end_point;
- console.log('command:', command);
- processManager.startProcess('run-simulation', command, (error, stdout, stderr) => {
- if (error) {
- console.error(`exec error: ${error}`);
- // event.reply('run-simulation-response', { success: false, message: error.message });
- } else {
- console.log(`stdout: ${stdout}`);
- console.error(`stderr: ${stderr}`);
- if (stdout.toString().includes('Evaluation finished')) { // 判断结束标志
- event.reply('run-simulation-response', { success: true, message: 'Run simulation successfully' });
- } else {
- event.reply('run-simulation-response', { success: false, message: 'Error running simulation' });
- }
- }
- });
- // 设置超时机制(
- const timeoutId = setTimeout(() => {
- if (!event.sender.isDestroyed()) {
- // 如果渲染进程仍然存在
- processManager.killProcess('run-simulation');
- event.reply('run-simulation-response', { success: false, message: 'Script running timeout' });
- }
- clearTimeout(timeoutId)
- }, 10*60*1000); // 10 分钟
- });
- // 读取并上传算法评价结果
- ipcMain.handle('process-evaluation-files', async (event, {N, equipmentNo, sceneNo}) => {
- const result = []
- const evalDir = PJI_SCRIPT_PATH_PREFIX + "simulation/data/evaluation";
- const bagDir = PJI_SCRIPT_PATH_PREFIX + "simulation/data/record_bag";
- console.log('N', N)
- // 记录时间戳
- const timeStamp = Date.now()
- console.log("timeStamp", timeStamp);
- // 遍历评价结果文件夹,读取并上传相关数据
- for (let i = 1; i <= N; i++) {
- const subDir = path.join(evalDir, `${i}/result`);
- console.log("subDir", subDir);
- // 文件路径 - report.json
- const jsonFilePath = path.join(subDir, "report.json");
- console.log("jsonFilePath", jsonFilePath);
- // 文件路径 - report.pdf
- const pdfFilePath = path.join(subDir, "report.pdf");
- console.log("pdfFilePath", pdfFilePath);
- // 文件路径 - test-${i}.bag
- const bagFilePath = path.join(bagDir, `test-${i}.bag`);
- console.log("bagFilePath", bagFilePath);
- const uploadPdfUrl = "http://127.0.0.1:8888/simulation/upload/pdf?equipmentNo=" + equipmentNo + "&sceneNo=" + sceneNo +
- "&timeStamp=" + timeStamp + "&round=" + i;
- const uploadBagUrl = "http://127.0.0.1:8888/simulation/upload/bag?equipmentNo=" + equipmentNo + "&sceneNo=" + sceneNo +
- "&timeStamp=" + timeStamp + "&round=" + i;
- try {
- // 读取json文件
- const jsonData = fs.readFileSync(jsonFilePath, "utf-8");
- const parsedData = JSON.parse(jsonData);
- console.log("parsedData", parsedData);
- // 上传pdf文件
- // 查找pdf文件是否存在
- let pdfFileExists = fs.existsSync(pdfFilePath)
- // pdf文件不存在
- if (!pdfFileExists) break
- // pdf文件存在
- const uploadPdfResult = await uploadFileWithRetry(pdfFilePath, uploadPdfUrl);
- console.log("uploadPdfResult", uploadPdfResult);
- if (!uploadPdfResult.status) {
- break
- }
- // 上传bag文件
- // 查找bag文件是否存在
- let bagFileExists = fs.existsSync(bagFilePath)
- // bag文件不存在
- if (!bagFileExists) break
- // bag文件存在
- const uploadBagResult = await uploadFile(bagFilePath, uploadBagUrl);
- console.log("uploadBagResult", uploadBagResult);
- if (!uploadBagResult.status) { break}
- // 整合结果
- result.push({
- "round": i,
- "jsonData": parsedData,
- "uploadPdfKey": uploadPdfResult.details,
- "uploadBagKey": uploadBagResult.details,
- "timeStamp": timeStamp
- })
- } catch (error) {
- console.log("error", error);
- return { success: false, message: "Error uploading evaluation results", data: [] }
- }
- }
- // 判断数据上传是否完整
- if (result.length === N) {
- return { success: true, message: "Evaluation results uploaded successfully", data: result }
- } else {
- return { success: false, message: "Error uploading evaluation results", data: [] }
- }
- })
- async function uploadMapResult(filePath, uploadUrl) {
- // 查找文件是否存在
- let fileExists = fs.existsSync(filePath)
- let uploadResult = await uploadFileWithRetry(filePath, uploadUrl);
- if (!fileExists) return { success: false, message: "Error uploading map results", data: [] }
- // console.log("uploadResult", uploadResult);
- if (!uploadResult.status) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- return { success: true, message: "", data: uploadResult }
- }
- // 读取并上传地图更新结果
- ipcMain.handle('process-map-update-files', async (event, {equipmentNo, timeStamp}) => {
- let result = {}
- equipmentNo = "pji-test"
- timeStamp = Date.now()
- // 记录时间戳
- console.log("timeStamp", timeStamp);
- const dataDir = PJI_SCRIPT_PATH_PREFIX + "map_update/data";
- const mapBufDir = PJI_SCRIPT_PATH_PREFIX + "map_update/data/bag_folder/mapBuf";
- const resultDir = PJI_SCRIPT_PATH_PREFIX + "map_update/data/bag_folder/result";
- const updateMapDir = PJI_SCRIPT_PATH_PREFIX + "map_update/data/bag_folder/update_map";
- // 读取result*.json
- // 文件路径 - result*.json
- const jsonPrefix = "result";
- let files = fs.readdirSync(resultDir);
- let matchedFile = files.find(file => file.startsWith(jsonPrefix))
- let jsonFilePath = ""
- if (matchedFile) {
- // 如果找到匹配的文件
- jsonFilePath = path.join(resultDir, matchedFile);
- }
- console.log("jsonFilePath", jsonFilePath);
- // 文件路径 - 更新前pgm
- const prePgmPath = path.join(mapBufDir, "map.pgm");
- console.log("prePgmPath", prePgmPath);
- // 文件路径 - 更新后pgm
- const pgmSuffix = ".pgm";
- files = fs.readdirSync(updateMapDir);
- matchedFile = files.find(file => file.endsWith(pgmSuffix))
- let updatePgmPath = ""
- if (matchedFile) {
- // 如果找到匹配的文件
- updatePgmPath = path.join(updateMapDir, matchedFile);
- }
- console.log("updatePgmPath", updatePgmPath);
- // 文件路径 - 更新前png
- const prePngPath = path.join(mapBufDir, "map_pre.png");
- console.log("prePngPath", prePngPath);
- // 文件路径 - 更新后png
- const updatePngPath = path.join(mapBufDir, "map_update.png");
- console.log("updatePngPath", updatePngPath);
- // 文件路径 - 更新地图压缩包
- const updateMapPath = path.join(dataDir, "update.zip");
- console.log("updateMapPath", updateMapPath);
- try {
- // 读取json文件
- const jsonData = fs.readFileSync(jsonFilePath, "utf-8");
- const parsedData = JSON.parse(jsonData);
- console.log("parsedData", parsedData);
- const mapId = parsedData["origin_pgm_id"];
- // 上传 更新前pgm
- let uploadUrl = "http://127.0.0.1:8888/map/upload/map?equipmentNo=" + equipmentNo + "&mapId=" + mapId +
- "&timeStamp=" + timeStamp ;
- // 上传文件
- // 上传 更新前pgm
- let res = await uploadMapResult(prePgmPath, uploadUrl);
- if (!res.success) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- let prePgmUrl = res.data.details
- console.log("prePgmUrl", prePgmUrl);
- // 上传 更新前png
- res = await uploadMapResult(prePngPath, uploadUrl);
- if (!res.success) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- let prePngUrl = res.data.details
- console.log("prePngUrl", prePngUrl);
- // 上传 更新后pgm
- res = await uploadMapResult(updatePgmPath, uploadUrl);
- if (!res.success) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- let updatePgmUrl = res.data.details
- console.log("updatePgmUrl", updatePgmUrl);
- // 上传 更新后png
- res = await uploadMapResult(updatePngPath, uploadUrl);
- if (!res.success) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- let updatePngUrl = res.data.details
- console.log("updatePngUrl", updatePngUrl);
- // 上传 更新地图压缩包
- res = await uploadMapResult(updateMapPath, uploadUrl);
- if (!res.success) {
- return { success: false, message: "Error uploading map results", data: [] }
- }
- let updateMapUrl = res.data.details
- console.log("updateMapUrl", updateMapUrl);
- result = {
- "jsonData": parsedData,
- "prePgmUrl": prePgmUrl,
- "prePngUrl": prePngUrl,
- "updatePgmUrl": updatePgmUrl,
- "updatePngUrl": updatePngUrl,
- "updateMapUrl": updateMapUrl,
- }
- return { success: true, message: "Evaluation results uploaded successfully", data: result }
- } catch (error) {
- console.log("error", error);
- }
- })
|