main.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. const { app, BrowserWindow, dialog } = require('electron');
  2. const { spawn } = require('child_process');
  3. const path = require('path');
  4. const http = require('http');
  5. const fs = require('fs');
  6. let mainWindow;
  7. let serverProcess;
  8. const PORT = 3000;
  9. function getBinaryPath() {
  10. const isDev = process.env.NODE_ENV === 'development';
  11. const platform = process.platform;
  12. if (isDev) {
  13. const binaryName = platform === 'win32' ? 'new-api.exe' : 'new-api';
  14. return path.join(__dirname, '..', binaryName);
  15. }
  16. let binaryName;
  17. switch (platform) {
  18. case 'win32':
  19. binaryName = 'new-api.exe';
  20. break;
  21. case 'darwin':
  22. binaryName = 'new-api';
  23. break;
  24. case 'linux':
  25. binaryName = 'new-api';
  26. break;
  27. default:
  28. binaryName = 'new-api';
  29. }
  30. return path.join(process.resourcesPath, 'bin', binaryName);
  31. }
  32. function startServer() {
  33. return new Promise((resolve, reject) => {
  34. const binaryPath = getBinaryPath();
  35. const isDev = process.env.NODE_ENV === 'development';
  36. console.log('Starting server from:', binaryPath);
  37. const env = { ...process.env, PORT: PORT.toString() };
  38. let dataDir;
  39. if (isDev) {
  40. dataDir = path.join(__dirname, '..', 'data');
  41. } else {
  42. const userDataPath = app.getPath('userData');
  43. dataDir = path.join(userDataPath, 'data');
  44. }
  45. if (!fs.existsSync(dataDir)) {
  46. fs.mkdirSync(dataDir, { recursive: true });
  47. }
  48. env.SQLITE_PATH = path.join(dataDir, 'new-api.db');
  49. const workingDir = isDev
  50. ? path.join(__dirname, '..')
  51. : process.resourcesPath;
  52. serverProcess = spawn(binaryPath, [], {
  53. env,
  54. cwd: workingDir
  55. });
  56. serverProcess.stdout.on('data', (data) => {
  57. console.log(`Server: ${data}`);
  58. });
  59. serverProcess.stderr.on('data', (data) => {
  60. console.error(`Server Error: ${data}`);
  61. });
  62. serverProcess.on('error', (err) => {
  63. console.error('Failed to start server:', err);
  64. reject(err);
  65. });
  66. serverProcess.on('close', (code) => {
  67. console.log(`Server process exited with code ${code}`);
  68. if (mainWindow && !mainWindow.isDestroyed()) {
  69. mainWindow.close();
  70. }
  71. });
  72. waitForServer(resolve, reject);
  73. });
  74. }
  75. function waitForServer(resolve, reject, retries = 30) {
  76. if (retries === 0) {
  77. reject(new Error('Server failed to start within timeout'));
  78. return;
  79. }
  80. const req = http.get(`http://localhost:${PORT}`, (res) => {
  81. console.log('Server is ready');
  82. resolve();
  83. });
  84. req.on('error', () => {
  85. setTimeout(() => waitForServer(resolve, reject, retries - 1), 1000);
  86. });
  87. req.end();
  88. }
  89. function createWindow() {
  90. mainWindow = new BrowserWindow({
  91. width: 1400,
  92. height: 900,
  93. webPreferences: {
  94. preload: path.join(__dirname, 'preload.js'),
  95. nodeIntegration: false,
  96. contextIsolation: true
  97. },
  98. title: 'New API',
  99. icon: path.join(__dirname, 'icon.png')
  100. });
  101. mainWindow.loadURL(`http://localhost:${PORT}`);
  102. if (process.env.NODE_ENV === 'development') {
  103. mainWindow.webContents.openDevTools();
  104. }
  105. mainWindow.on('closed', () => {
  106. mainWindow = null;
  107. });
  108. }
  109. app.whenReady().then(async () => {
  110. try {
  111. await startServer();
  112. createWindow();
  113. } catch (err) {
  114. console.error('Failed to start application:', err);
  115. dialog.showErrorBox('Startup Error', `Failed to start server: ${err.message}`);
  116. app.quit();
  117. }
  118. });
  119. app.on('window-all-closed', () => {
  120. if (process.platform !== 'darwin') {
  121. app.quit();
  122. }
  123. });
  124. app.on('activate', () => {
  125. if (BrowserWindow.getAllWindows().length === 0) {
  126. createWindow();
  127. }
  128. });
  129. app.on('before-quit', (event) => {
  130. if (serverProcess) {
  131. event.preventDefault();
  132. console.log('Shutting down server...');
  133. serverProcess.kill('SIGTERM');
  134. setTimeout(() => {
  135. if (serverProcess) {
  136. serverProcess.kill('SIGKILL');
  137. }
  138. app.exit();
  139. }, 5000);
  140. serverProcess.on('close', () => {
  141. serverProcess = null;
  142. app.exit();
  143. });
  144. }
  145. });