|
|
@@ -0,0 +1,178 @@
|
|
|
+const { app, BrowserWindow, dialog } = require('electron');
|
|
|
+const { spawn } = require('child_process');
|
|
|
+const path = require('path');
|
|
|
+const http = require('http');
|
|
|
+const fs = require('fs');
|
|
|
+
|
|
|
+let mainWindow;
|
|
|
+let serverProcess;
|
|
|
+const PORT = 3000;
|
|
|
+
|
|
|
+function getBinaryPath() {
|
|
|
+ const isDev = process.env.NODE_ENV === 'development';
|
|
|
+ const platform = process.platform;
|
|
|
+
|
|
|
+ if (isDev) {
|
|
|
+ const binaryName = platform === 'win32' ? 'new-api.exe' : 'new-api';
|
|
|
+ return path.join(__dirname, '..', binaryName);
|
|
|
+ }
|
|
|
+
|
|
|
+ let binaryName;
|
|
|
+ switch (platform) {
|
|
|
+ case 'win32':
|
|
|
+ binaryName = 'new-api.exe';
|
|
|
+ break;
|
|
|
+ case 'darwin':
|
|
|
+ binaryName = 'new-api';
|
|
|
+ break;
|
|
|
+ case 'linux':
|
|
|
+ binaryName = 'new-api';
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ binaryName = 'new-api';
|
|
|
+ }
|
|
|
+
|
|
|
+ return path.join(process.resourcesPath, 'bin', binaryName);
|
|
|
+}
|
|
|
+
|
|
|
+function startServer() {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const binaryPath = getBinaryPath();
|
|
|
+ const isDev = process.env.NODE_ENV === 'development';
|
|
|
+
|
|
|
+ console.log('Starting server from:', binaryPath);
|
|
|
+
|
|
|
+ const env = { ...process.env, PORT: PORT.toString() };
|
|
|
+
|
|
|
+ let dataDir;
|
|
|
+ if (isDev) {
|
|
|
+ dataDir = path.join(__dirname, '..', 'data');
|
|
|
+ } else {
|
|
|
+ const userDataPath = app.getPath('userData');
|
|
|
+ dataDir = path.join(userDataPath, 'data');
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!fs.existsSync(dataDir)) {
|
|
|
+ fs.mkdirSync(dataDir, { recursive: true });
|
|
|
+ }
|
|
|
+
|
|
|
+ env.SQLITE_PATH = path.join(dataDir, 'new-api.db');
|
|
|
+
|
|
|
+ const workingDir = isDev
|
|
|
+ ? path.join(__dirname, '..')
|
|
|
+ : process.resourcesPath;
|
|
|
+
|
|
|
+ serverProcess = spawn(binaryPath, [], {
|
|
|
+ env,
|
|
|
+ cwd: workingDir
|
|
|
+ });
|
|
|
+
|
|
|
+ serverProcess.stdout.on('data', (data) => {
|
|
|
+ console.log(`Server: ${data}`);
|
|
|
+ });
|
|
|
+
|
|
|
+ serverProcess.stderr.on('data', (data) => {
|
|
|
+ console.error(`Server Error: ${data}`);
|
|
|
+ });
|
|
|
+
|
|
|
+ serverProcess.on('error', (err) => {
|
|
|
+ console.error('Failed to start server:', err);
|
|
|
+ reject(err);
|
|
|
+ });
|
|
|
+
|
|
|
+ serverProcess.on('close', (code) => {
|
|
|
+ console.log(`Server process exited with code ${code}`);
|
|
|
+ if (mainWindow && !mainWindow.isDestroyed()) {
|
|
|
+ mainWindow.close();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ waitForServer(resolve, reject);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function waitForServer(resolve, reject, retries = 30) {
|
|
|
+ if (retries === 0) {
|
|
|
+ reject(new Error('Server failed to start within timeout'));
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const req = http.get(`http://localhost:${PORT}`, (res) => {
|
|
|
+ console.log('Server is ready');
|
|
|
+ resolve();
|
|
|
+ });
|
|
|
+
|
|
|
+ req.on('error', () => {
|
|
|
+ setTimeout(() => waitForServer(resolve, reject, retries - 1), 1000);
|
|
|
+ });
|
|
|
+
|
|
|
+ req.end();
|
|
|
+}
|
|
|
+
|
|
|
+function createWindow() {
|
|
|
+ mainWindow = new BrowserWindow({
|
|
|
+ width: 1400,
|
|
|
+ height: 900,
|
|
|
+ webPreferences: {
|
|
|
+ preload: path.join(__dirname, 'preload.js'),
|
|
|
+ nodeIntegration: false,
|
|
|
+ contextIsolation: true
|
|
|
+ },
|
|
|
+ title: 'New API',
|
|
|
+ icon: path.join(__dirname, 'icon.png')
|
|
|
+ });
|
|
|
+
|
|
|
+ mainWindow.loadURL(`http://localhost:${PORT}`);
|
|
|
+
|
|
|
+ if (process.env.NODE_ENV === 'development') {
|
|
|
+ mainWindow.webContents.openDevTools();
|
|
|
+ }
|
|
|
+
|
|
|
+ mainWindow.on('closed', () => {
|
|
|
+ mainWindow = null;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+app.whenReady().then(async () => {
|
|
|
+ try {
|
|
|
+ await startServer();
|
|
|
+ createWindow();
|
|
|
+ } catch (err) {
|
|
|
+ console.error('Failed to start application:', err);
|
|
|
+ dialog.showErrorBox('Startup Error', `Failed to start server: ${err.message}`);
|
|
|
+ app.quit();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+app.on('window-all-closed', () => {
|
|
|
+ if (process.platform !== 'darwin') {
|
|
|
+ app.quit();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+app.on('activate', () => {
|
|
|
+ if (BrowserWindow.getAllWindows().length === 0) {
|
|
|
+ createWindow();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
+app.on('before-quit', (event) => {
|
|
|
+ if (serverProcess) {
|
|
|
+ event.preventDefault();
|
|
|
+
|
|
|
+ console.log('Shutting down server...');
|
|
|
+ serverProcess.kill('SIGTERM');
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ if (serverProcess) {
|
|
|
+ serverProcess.kill('SIGKILL');
|
|
|
+ }
|
|
|
+ app.exit();
|
|
|
+ }, 5000);
|
|
|
+
|
|
|
+ serverProcess.on('close', () => {
|
|
|
+ serverProcess = null;
|
|
|
+ app.exit();
|
|
|
+ });
|
|
|
+ }
|
|
|
+});
|