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 {resolve} from "node:dns"; import {execSync} from "node:child_process"; import * as url from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); 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('ready', () => { // // 异步 // // }) app.on('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // ------------- 进程通信 ------------- 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 }) => { try { // console.log("url", url) // console.log("response", response) const filePath = path.join(savePath, fileName); // 查找文件是否存在 const fileExists = fs.existsSync(filePath) if (fileExists && !overwriteFlag) { // 已存在且不覆盖 return {success: true, filePath} } else { // 不存在 const response = await axios.get(url, {responseType: 'stream'}); // 写入文件 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; } // 读取文件 // fs.readFile(filePath, async (err, data) => { // if(err) { // console.log("Error reading file:", err); // event.reply('upload-file-response', { success: false, message: err.message }); // return; // } // // // 创建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) // event.reply('upload-file-response', { success: true, message: 'File uploaded successfully' }); // } catch (err) { // console.log("Error uploading file:", err); // event.reply('upload-file-response', { success: false, message: err.message }); // } // }) 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: '上传stl文件失败', details: '' }; } } // 导入算法镜像 ipcMain.on('docker-import', (event, filePath, tag) => { const command = 'bash /home/cicv/work/pji_desktop/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 }); return; } else { console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); event.reply('docker-import-response', { success: true, message: 'Docker image imported successfully' }); } }); }); // 生成world ipcMain.on('generate-world', (event, {rosbag_path}) => { const command = 'bash /home/cicv/work/pji_desktop/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', ["/home/cicv/work/pji_desktop/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 /home/cicv/work/pji_desktop/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 /home/cicv/work/pji_desktop/simulation/run_simulation.sh ' + random_flag + ' ' + count + ' ' + obstacle_flag + ' ' + default_start_flag + ' ' + default_end_flag + ' ' + start_point + ' ' + end_point; console.log('command:', command); exec(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' }); } } }); }); // 读取并上传算法评价结果 ipcMain.handle('process-evaluation-files', async (event, {N, equipmentNo, sceneNo}) => { const result = [] const evalDir = "/home/cicv/work/pji_desktop/simulation/data/evaluation"; const bagDir = "/home/cicv/work/pji_desktop/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文件 const uploadPdfResult = await uploadFile(pdfFilePath, uploadPdfUrl); console.log("uploadPdfResult", uploadPdfResult); if (!uploadPdfResult.status) { break} // 上传bag文件 const uploadBagResult = await uploadFile(bagFilePath, uploadBagUrl); console.log("uploadBagUrl", uploadBagUrl); 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: [] } } })