main.js 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import {app, BrowserWindow, ipcMain, dialog} from 'electron';
  2. import {exec, spawn} from 'child_process';
  3. import path from 'path';
  4. import {fileURLToPath} from 'url';
  5. import fs from 'fs';
  6. import axios from 'axios';
  7. const __filename = fileURLToPath(import.meta.url);
  8. const __dirname = path.dirname(__filename);
  9. function createWindow() {
  10. const win = new BrowserWindow({
  11. width: 800,
  12. height: 600,
  13. webPreferences: {
  14. preload: path.join(__dirname, 'preload.js'), // 确保路径正确
  15. contextIsolation: true,
  16. enableRemoteModule: false,
  17. nodeIntegration: false,
  18. }
  19. });
  20. win.webContents.openDevTools(); // 打开开发者工具进行调试
  21. win.loadURL('http://localhost:5173'); // 开发环境
  22. // win.loadURL('http://36.110.106.156:81'); // 生产环境
  23. console.log('Window created and URL loaded');
  24. }
  25. app.whenReady().then(createWindow);
  26. app.on('window-all-closed', () => {
  27. if (process.platform !== 'darwin') {
  28. app.quit();
  29. }
  30. });
  31. app.on('activate', () => {
  32. if (BrowserWindow.getAllWindows().length === 0) {
  33. createWindow();
  34. }
  35. });
  36. // ------------- 进程通信 -------------
  37. ipcMain.on('open-gazebo', (event, arg) => {
  38. console.log('Received open-gazebo event');
  39. exec('gazebo', (error, stdout, stderr) => {
  40. if (error) {
  41. console.error(`exec error: ${error}`);
  42. return;
  43. }
  44. console.log(`stdout: ${stdout}`);
  45. console.error(`stderr: ${stderr}`);
  46. });
  47. });
  48. ipcMain.on('open-rviz', (event, arg) => {
  49. console.log('Received open-rviz event');
  50. exec('rviz', (error, stdout, stderr) => {
  51. if (error) {
  52. console.error(`exec error: ${error}`);
  53. return;
  54. }
  55. console.log(`stdout: ${stdout}`);
  56. console.error(`stderr: ${stderr}`);
  57. });
  58. });
  59. ipcMain.on('close-gazebo', (event, arg) => {
  60. console.log('Received close-gazebo event');
  61. exec('pkill -f gzserver & pkill -f gzclient', (error, stdout, stderr) => {
  62. if (error) {
  63. console.error(`exec error: ${error}`);
  64. return;
  65. }
  66. console.log(`stdout: ${stdout}`);
  67. console.error(`stderr: ${stderr}`);
  68. });
  69. });
  70. ipcMain.on('close-rviz', (event, arg) => {
  71. console.log('Received close-rviz event');
  72. exec('pkill -f rviz', (error, stdout, stderr) => {
  73. if (error) {
  74. console.error(`exec error: ${error}`);
  75. return;
  76. }
  77. console.log(`stdout: ${stdout}`);
  78. console.error(`stderr: ${stderr}`);
  79. });
  80. });
  81. ipcMain.handle('dialog:open', async (event, options = {}) => {
  82. const result = await dialog.showOpenDialog(BrowserWindow.getFocusedWindow() || BrowserWindow.getAllWindows()[0], options);
  83. return result.canceled ? null : result.filePaths;
  84. });
  85. ipcMain.on('docker-import', (event, filePath, tag) => {
  86. const command = 'bash /home/cicv/work/pji_desktop/docker_import/run_docker_import.sh ' + filePath + ' pji_nav ' + tag
  87. console.log('导入算法镜像文件:', command);
  88. exec(command, (error, stdout, stderr) => {
  89. if (error) {
  90. console.error(`exec error: ${error}`);
  91. event.reply('docker-import-response', { success: false, message: error.message });
  92. return;
  93. } else {
  94. console.log(`stdout: ${stdout}`);
  95. console.error(`stderr: ${stderr}`);
  96. event.reply('docker-import-response', { success: true, message: 'Docker image imported successfully' });
  97. }
  98. });
  99. });
  100. ipcMain.on('generate-world', (event, {rosbag_path}) => {
  101. // 使用 spawn 启动脚本
  102. const serviceProcess = spawn('bash', ["/home/cicv/work/pji_desktop/simulation/run_map2gazebo.sh"], { detached: true });
  103. // 设置为后台进程
  104. serviceProcess.unref();
  105. // 监听输出
  106. serviceProcess.stdout.on('data', (data) => {
  107. console.log(`第一个脚本的输出: ${data}`);
  108. // 根据第一个脚本的输出判断其是否准备好
  109. if (data.toString().includes('Service map2gazebo started')) {
  110. startSecondScript();
  111. }
  112. });
  113. // 监听错误
  114. serviceProcess.stderr.on('data', (data) => {
  115. console.error(`执行第一个脚本时出错: ${data}`);
  116. });
  117. // 监听关闭
  118. serviceProcess.on('close', (data) => {
  119. console.log(`第一个脚本已关闭: ${data}`);
  120. });
  121. function startSecondScript() {
  122. // 启动第二个脚本
  123. const script2 = exec('bash /home/cicv/work/pji_desktop/simulation/play_rosbag.sh ' + rosbag_path, (error, stdout, stderr) => {
  124. if (error) {
  125. console.error(`执行第二个脚本时出错: ${error}`);
  126. event.sender.send('generate-world-result', { success: false, output: error });
  127. return;
  128. }
  129. console.log(`第二个脚本的输出: ${stdout}`);
  130. event.sender.send('generate-world-result', { success: true, output: stdout });
  131. });
  132. script2.on('exit', (code) => {
  133. console.log(`第二个脚本已退出,退出码: ${code}`);
  134. });
  135. }
  136. });
  137. ipcMain.handle('download-file', async (event, { url, fileName, savePath }) => {
  138. try {
  139. const response = await axios.get(url, { responseType: 'stream' });
  140. // console.log("url", url)
  141. // console.log("response", response)
  142. const filePath = path.join(savePath, fileName);
  143. // 写入文件
  144. const writer = fs.createWriteStream(filePath);
  145. return new Promise((resolve, reject) => {
  146. response.data.pipe(writer);
  147. let error = null;
  148. writer.on('error', err => {
  149. error = err;
  150. writer.close();
  151. reject(err);
  152. });
  153. writer.on('close', () => {
  154. if (!error) {
  155. resolve({ success: true, filePath }); // 返回成功信息
  156. } else {
  157. reject({ success: false, error: error.message }); // 返回错误信息
  158. }
  159. });
  160. });
  161. } catch (error) {
  162. // console.error('下载文件出错:', error);
  163. throw error;
  164. }
  165. });
  166. // 监听从渲染进程传来的删除文件请求
  167. ipcMain.on('delete-file', (event, {fileName, savePath}) => {
  168. const filePath = path.join(savePath, fileName);
  169. // 检查文件是否存在
  170. if (fs.existsSync(filePath)) {
  171. // 文件存在,尝试删除
  172. fs.unlink(filePath, (err) => {
  173. if (err) {
  174. event.reply('delete-file-response', { success: false, message: err.message });
  175. } else {
  176. event.reply('delete-file-response', { success: true, message: 'File deleted successfully' });
  177. }
  178. });
  179. } else {
  180. // 文件不存在
  181. event.reply('delete-file-response', { success: false, message: 'File does not exist' });
  182. }
  183. });