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"; 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('activate', () => { if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } }); // ------------- 进程通信 ------------- ipcMain.on('open-gazebo', (event, arg) => { console.log('Received open-gazebo event'); exec('gazebo', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); }); ipcMain.on('open-rviz', (event, arg) => { console.log('Received open-rviz event'); exec('rviz', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); }); ipcMain.on('close-gazebo', (event, arg) => { console.log('Received close-gazebo event'); exec('pkill -f gzserver & pkill -f gzclient', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); }); ipcMain.on('close-rviz', (event, arg) => { console.log('Received close-rviz event'); exec('pkill -f rviz', (error, stdout, stderr) => { if (error) { console.error(`exec error: ${error}`); return; } console.log(`stdout: ${stdout}`); console.error(`stderr: ${stderr}`); }); }); 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.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('导入算法镜像文件:', 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' }); } }); }); ipcMain.on('generate-world', (event, {rosbag_path}) => { // 使用 spawn 启动脚本 const serviceProcess = spawn('bash', ["/home/cicv/work/pji_desktop/simulation/run_map2gazebo.sh"], { detached: true }); // 设置为后台进程 serviceProcess.unref(); // 监听输出 serviceProcess.stdout.on('data', (data) => { console.log(`第一个脚本的输出: ${data}`); // 根据第一个脚本的输出判断其是否准备好 if (data.toString().includes('Service map2gazebo started')) { startSecondScript(); } }); // 监听错误 serviceProcess.stderr.on('data', (data) => { console.error(`执行第一个脚本时出错: ${data}`); }); // 监听关闭 serviceProcess.on('close', (data) => { console.log(`第一个脚本已关闭: ${data}`); }); function startSecondScript() { // 启动第二个脚本 const script2 = exec('bash /home/cicv/work/pji_desktop/simulation/play_rosbag.sh ' + rosbag_path, (error, stdout, stderr) => { if (error) { console.error(`执行第二个脚本时出错: ${error}`); event.sender.send('generate-world-result', { success: false, output: error }); return; } console.log(`第二个脚本的输出: ${stdout}`); event.sender.send('generate-world-result', { success: true, output: stdout }); }); script2.on('exit', (code) => { console.log(`第二个脚本已退出,退出码: ${code}`); }); } }); 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('generate-world-result', { success: false, output: error }); return; } console.log(`第二个脚本的输出: ${stdout}`); event.sender.send('start-container-result', { success: true, output: stdout }); }); script2.on('exit', (code) => { console.log(`第二个脚本已退出,退出码: ${code}`); }); } }); ipcMain.handle('run-simulation', (event, {obstacle_flag, default_start_flag, default_end_flag, start_point, end_point}) => { const command = 'bash /home/cicv/work/pji_desktop/simulation/run_simulation.sh ' + 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 }); // return { success: false, message: error.message } // } else { // console.log(`stdout: ${stdout}`); // console.error(`stderr: ${stderr}`); // return { success: true, message: 'Run simulation successfully' } // } // }); // 同步 try { const output = execSync(command) console.log("output", output.toString()); return { success: false, message: error.message } } catch (error) { console.error(`exec error: ${error}`); return { success: true, message: 'Run simulation successfully' } } }); 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' }); } });