mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
130 lines
3.4 KiB
JavaScript
130 lines
3.4 KiB
JavaScript
import { app, BrowserWindow, dialog } from 'electron';
|
|
import { spawn } from 'node:child_process';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, resolve } from 'node:path';
|
|
import { get } from 'node:http';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = dirname(__filename);
|
|
const bundleRoot = resolve(__dirname, '..');
|
|
|
|
const nodecgRoot = process.env.NODECG_ROOT
|
|
? resolve(bundleRoot, process.env.NODECG_ROOT)
|
|
: resolve(bundleRoot, '..', '..');
|
|
|
|
const startUrl = process.env.ELECTRON_START_URL ?? 'http://localhost:9090/bundles/scoreko-dev/dashboard/example/main.html?standalone=true';
|
|
const nodecgPort = Number(process.env.NODECG_PORT ?? 9090);
|
|
const nodeBinary = process.env.NODE_BINARY ?? 'node';
|
|
const useElectronNodeForNodeCG = process.env.NODECG_USE_ELECTRON_NODE === '1';
|
|
|
|
/** @type {import('node:child_process').ChildProcess | undefined} */
|
|
let nodecgProcess;
|
|
|
|
function waitForServer(url, timeoutMs = 30_000) {
|
|
const started = Date.now();
|
|
|
|
return new Promise((resolvePromise, rejectPromise) => {
|
|
const attempt = () => {
|
|
const request = get(url, (response) => {
|
|
response.resume();
|
|
|
|
if (response.statusCode && response.statusCode >= 200 && response.statusCode < 500) {
|
|
resolvePromise();
|
|
return;
|
|
}
|
|
|
|
if (Date.now() - started > timeoutMs) {
|
|
rejectPromise(new Error('NodeCG did not respond in time.'));
|
|
return;
|
|
}
|
|
|
|
setTimeout(attempt, 500);
|
|
});
|
|
|
|
request.on('error', () => {
|
|
if (Date.now() - started > timeoutMs) {
|
|
rejectPromise(new Error('Could not connect to NodeCG.'));
|
|
return;
|
|
}
|
|
|
|
setTimeout(attempt, 500);
|
|
});
|
|
};
|
|
|
|
attempt();
|
|
});
|
|
}
|
|
|
|
function startNodeCG() {
|
|
const runtimeBinary = useElectronNodeForNodeCG ? process.execPath : nodeBinary;
|
|
|
|
nodecgProcess = spawn(runtimeBinary, ['index.js'], {
|
|
cwd: nodecgRoot,
|
|
stdio: 'inherit',
|
|
env: {
|
|
...process.env,
|
|
NODE_ENV: process.env.NODE_ENV ?? 'production',
|
|
PORT: String(nodecgPort)
|
|
}
|
|
});
|
|
|
|
nodecgProcess.on('exit', (code) => {
|
|
if (!app.isQuiting) {
|
|
dialog.showErrorBox(
|
|
'NodeCG exited',
|
|
`The NodeCG process ended unexpectedly with code ${code ?? 'unknown'}.`
|
|
);
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
nodecgProcess.on('error', (error) => {
|
|
dialog.showErrorBox(
|
|
'Could not start NodeCG',
|
|
`Could not run \"${runtimeBinary}\". ${useElectronNodeForNodeCG ? 'Disable NODECG_USE_ELECTRON_NODE or check your Electron setup.' : 'Set NODE_BINARY to your Node.js path.'}\n\nDetails: ${error.message}`
|
|
);
|
|
app.quit();
|
|
});
|
|
}
|
|
|
|
async function createWindow() {
|
|
const win = new BrowserWindow({
|
|
width: 1920,
|
|
height: 1080,
|
|
autoHideMenuBar: true,
|
|
backgroundColor: '#000000',
|
|
webPreferences: {
|
|
contextIsolation: true,
|
|
sandbox: true
|
|
}
|
|
});
|
|
|
|
await win.loadURL(startUrl);
|
|
}
|
|
|
|
app.on('before-quit', () => {
|
|
app.isQuiting = true;
|
|
|
|
if (nodecgProcess && !nodecgProcess.killed) {
|
|
nodecgProcess.kill('SIGTERM');
|
|
}
|
|
});
|
|
|
|
app.whenReady().then(async () => {
|
|
startNodeCG();
|
|
|
|
try {
|
|
await waitForServer(`http://127.0.0.1:${nodecgPort}`);
|
|
await createWindow();
|
|
} catch (error) {
|
|
dialog.showErrorBox('Could not start', error instanceof Error ? error.message : String(error));
|
|
app.quit();
|
|
}
|
|
});
|
|
|
|
app.on('window-all-closed', () => {
|
|
if (process.platform !== 'darwin') {
|
|
app.quit();
|
|
}
|
|
});
|