Files
seedit/scripts/verify-executable.js
plebeius d65e2d43b7 refactor: migrate from electron-builder to Electron Forge and use kubo npm package
Migrated build system from electron-builder to Electron Forge with new configuration in forge.config.js. Replaced manual IPFS binary downloads with kubo npm package, updating start-ipfs.js to resolve binaries from node_modules. Simplified CI workflows to use new build scripts and verification helpers. Added scripts to find and verify executables in Forge output directory.
2026-01-29 14:39:27 +08:00

137 lines
3.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Verify that a packaged Electron executable starts correctly.
* This script launches the executable and checks that the RPC port (9138) becomes available.
*/
import { spawn } from 'child_process';
import { existsSync } from 'fs';
import { createServer } from 'net';
const executablePath = process.argv[2];
const rpcPort = 9138;
const timeout = 30000; // 30 seconds
if (!executablePath) {
console.error('Usage: node scripts/verify-executable.js <executable-path>');
process.exit(1);
}
if (!existsSync(executablePath)) {
console.error(`Error: Executable not found: ${executablePath}`);
process.exit(1);
}
console.log(`Starting executable: ${executablePath}`);
console.log(`Checking for RPC port ${rpcPort}...`);
// Start the executable
const appProcess = spawn(executablePath, [], {
detached: false,
stdio: 'pipe',
});
let appExited = false;
let portAvailable = false;
let timeoutId;
// Check if port is in use (app is running)
function checkPort() {
return new Promise((resolve) => {
const server = createServer();
server.listen(rpcPort, '127.0.0.1', () => {
server.close();
resolve(false); // Port is available (not in use yet)
});
server.on('error', (err) => {
if (err.code === 'EADDRINUSE') {
resolve(true); // Port is in use (app is running - success!)
} else {
resolve(false);
}
});
});
}
// Monitor app process
appProcess.on('exit', (code, signal) => {
appExited = true;
if (code !== null && code !== 0) {
console.error(`App exited with code ${code}`);
cleanup();
process.exit(1);
}
});
appProcess.stderr.on('data', (data) => {
const text = data.toString();
// Filter out common harmless errors
if (!text.includes('Gtk') && !text.includes('libnotify')) {
console.error('stderr:', text);
}
});
// Poll for port availability
async function pollPort() {
const maxAttempts = 30; // 30 attempts over 30 seconds
let attempts = 0;
const interval = setInterval(async () => {
attempts++;
const inUse = await checkPort();
if (inUse) {
portAvailable = true;
console.log(`✓ RPC port ${rpcPort} is in use (app is running)`);
clearInterval(interval);
clearTimeout(timeoutId);
cleanup();
process.exit(0);
}
if (attempts >= maxAttempts || appExited) {
clearInterval(interval);
clearTimeout(timeoutId);
if (!portAvailable) {
console.error(`✗ RPC port ${rpcPort} did not become available within ${timeout / 1000} seconds`);
cleanup();
process.exit(1);
}
}
}, 1000);
}
// Set overall timeout
timeoutId = setTimeout(() => {
if (!portAvailable) {
console.error(`✗ Timeout: RPC port ${rpcPort} did not become available within ${timeout / 1000} seconds`);
cleanup();
process.exit(1);
}
}, timeout);
function cleanup() {
try {
if (appProcess && !appProcess.killed) {
appProcess.kill();
// Also try to kill any child processes
if (appProcess.pid) {
try {
process.kill(appProcess.pid, 'SIGTERM');
} catch (e) {
// Ignore errors
}
}
}
} catch (e) {
// Ignore cleanup errors
}
}
// Handle process termination
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
// Start polling
pollPort();