43 lines
1.3 KiB
TypeScript
43 lines
1.3 KiB
TypeScript
import { spawn } from 'node:child_process';
|
|
import path from 'node:path';
|
|
import { readPidfile, isProcessAlive } from '@visionl/daemon/dist/pidfile.js';
|
|
import { VisionLClient } from '@visionl/core';
|
|
|
|
const POLL_INTERVAL_MS = 100;
|
|
const MAX_WAIT_MS = 3000;
|
|
|
|
export async function ensureDaemonRunning(port: number): Promise<VisionLClient> {
|
|
const client = new VisionLClient(`http://127.0.0.1:${port}`);
|
|
|
|
if (await client.health()) {
|
|
return client;
|
|
}
|
|
|
|
const pidInfo = readPidfile();
|
|
if (pidInfo && isProcessAlive(pidInfo.pid)) {
|
|
if (await client.health()) {
|
|
return client;
|
|
}
|
|
}
|
|
|
|
// Spawn the browser-enabled daemon entry (boot.js) so that page/content/
|
|
// action routes are registered. Spawning server.js directly would start a
|
|
// browser-less daemon that only serves /health.
|
|
const daemonEntryPath = path.resolve(__dirname, '../../daemon/dist/boot.js');
|
|
spawn('node', [daemonEntryPath], {
|
|
env: { ...process.env, VISIONL_PORT: String(port) },
|
|
stdio: 'ignore',
|
|
detached: true,
|
|
}).unref();
|
|
|
|
const startTime = Date.now();
|
|
while (Date.now() - startTime < MAX_WAIT_MS) {
|
|
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
if (await client.health()) {
|
|
return client;
|
|
}
|
|
}
|
|
|
|
throw new Error('DAEMON_UNREACHABLE');
|
|
}
|