diff options
| author | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-04-29 01:38:17 +0530 |
|---|---|---|
| committer | amankumarsingh77 <amankumarsingh7702@gmal.com> | 2026-04-29 01:38:17 +0530 |
| commit | 63b16957587fe20566129ffc5191f66f24a70872 (patch) | |
| tree | 8a40fa38e1ae5b4309b1e38d7a3779321f15db4e /src/protocol.ts | |
| parent | 5317b32976edce3ab8e2f11d7fb4ff3f16dcac6f (diff) | |
Replace socket daemon with direct CDP WebSocket connection
Drops the Unix socket subprocess in favor of talking CDP directly over
WebSocket from the extension. Removes the protocol's send/health helpers,
simplifies setup to just verifying Chrome's remote debugging port, and
tightens types in dynamic-tools. Bumps Node engine to >=22 and adds the
ws dependency.
Diffstat (limited to 'src/protocol.ts')
| -rw-r--r-- | src/protocol.ts | 134 |
1 files changed, 5 insertions, 129 deletions
diff --git a/src/protocol.ts b/src/protocol.ts index 8edc79d..1b8bf40 100644 --- a/src/protocol.ts +++ b/src/protocol.ts @@ -1,36 +1,10 @@ /** - * Protocol types and low-level socket communication for the browser-harness daemon. + * Protocol types for pi-browser-harness. * - * The daemon exposes a Unix socket at /tmp/bu-<NAME>.sock. - * Protocol: one JSON-line request → one JSON-line response per connection. + * Defines the shape of CDP communication and browser state. + * No socket transport — the daemon talks CDP directly over WebSocket. */ -import { createConnection } from "node:net"; - -// ── Request ────────────────────────────────────────────────────────────────── - -export interface DaemonRequest { - /** CDP method (e.g. "Page.navigate") — absent for meta requests */ - method?: string; - /** CDP parameters */ - params?: Record<string, unknown>; - /** CDP session ID — null/absent for browser-level (Target.*) calls */ - session_id?: string | null; - /** Meta command: "drain_events" | "set_session" | "pending_dialog" | "shutdown" */ - meta?: string; -} - -// ── Response ───────────────────────────────────────────────────────────────── - -export interface DaemonResponse { - result?: unknown; - error?: string; - events?: CDPEvent[]; - session_id?: string; - dialog?: DialogInfo; - ok?: boolean; -} - // ── CDP Event ──────────────────────────────────────────────────────────────── export interface CDPEvent { @@ -75,9 +49,9 @@ export type PageInfoResult = PageInfo | { dialog: DialogInfo }; export interface DaemonStatus { alive: boolean; sessionId: string | null; - pid: number | null; + pid: number | null; // deprecated — always null (no subprocess) namespace: string; - socketPath: string; + socketPath: string; // deprecated — always "" (no socket) remoteBrowserId?: string; } @@ -101,101 +75,3 @@ const INTERNAL_PREFIXES = [ export function isInternalUrl(url: string): boolean { return INTERNAL_PREFIXES.some((p) => url.startsWith(p)); } - -// ── Low-level socket send ──────────────────────────────────────────────────── - -/** - * Send a single JSON-line request to the daemon socket and read one JSON-line response. - * Opens a fresh connection per request (stateless, matches helpers.py _send pattern). - */ -export function sendRequest( - socketPath: string, - request: DaemonRequest, - timeoutMs = 15_000, -): Promise<DaemonResponse> { - return new Promise((resolve, reject) => { - const socket = createConnection(socketPath); - - const timer = setTimeout(() => { - socket.destroy(); - reject(new Error(`Daemon request timed out after ${timeoutMs}ms: ${JSON.stringify(request.method ?? request.meta)}`)); - }, timeoutMs); - - let buffer = ""; - - socket.on("connect", () => { - socket.write(JSON.stringify(request) + "\n"); - }); - - socket.on("data", (chunk: Buffer) => { - buffer += chunk.toString(); - // Response is one JSON line ending with \n - if (buffer.includes("\n")) { - clearTimeout(timer); - const line = buffer.split("\n")[0]; - try { - const response: DaemonResponse = JSON.parse(line); - socket.end(); - resolve(response); - } catch (e) { - socket.end(); - reject(new Error(`Failed to parse daemon response: ${line.slice(0, 200)}`)); - } - } - }); - - socket.on("error", (err: NodeJS.ErrnoException) => { - clearTimeout(timer); - socket.destroy(); - reject(new Error(`Daemon socket error (${socketPath}): ${err.message}`)); - }); - - socket.on("close", () => { - clearTimeout(timer); - if (buffer.length === 0) { - reject(new Error(`Daemon socket closed without response (${socketPath})`)); - } - }); - }); -} - -/** - * Quick check if the daemon socket accepts connections. - */ -export function daemonAlive(socketPath: string, timeoutMs = 1000): Promise<boolean> { - return new Promise((resolve) => { - const socket = createConnection(socketPath); - const timer = setTimeout(() => { - socket.destroy(); - resolve(false); - }, timeoutMs); - - socket.on("connect", () => { - clearTimeout(timer); - socket.end(); - resolve(true); - }); - - socket.on("error", () => { - clearTimeout(timer); - resolve(false); - }); - }); -} - -/** - * True health check: send Target.getTargets and verify "result" key in response. - * A stale daemon can accept socket connections but have a dead CDP websocket. - */ -export async function healthProbe(socketPath: string): Promise<boolean> { - try { - const response = await sendRequest( - socketPath, - { method: "Target.getTargets", params: {} }, - 3000, - ); - return "result" in response && response.result !== undefined; - } catch { - return false; - } -} |
