aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/index.ts
blob: 226a895f7a0ec0e332fa89723003e2dedcab59ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import { createIpcServer } from "./server";
import { createCdpBridge, type SendToClient } from "./bridge";
import { DAEMON_IDLE_TIMEOUT_MS } from "./protocol";

async function main() {
  console.log("[pi-browser-daemon] Starting...");

  const ipcServer = createIpcServer();
  const cdpBridge = createCdpBridge();

  ipcServer.onMessage((msg, client) => {
    if (msg.type !== "request") return;

    const send: SendToClient = (cid, resp) => {
      ipcServer.send(cid, resp);
    };

    cdpBridge.handleRequest(msg, client.id, send);
  });

  cdpBridge.onEvent((event, targetClientIds) => {
    for (const cid of targetClientIds) {
      ipcServer.send(cid, event);
    }
  });

  ipcServer.onDisconnect((client) => {
    cdpBridge.removeClient(client.id);
  });

  cdpBridge.onClose(() => {
    console.log("[pi-browser-daemon] Chrome disconnected");
    ipcServer.broadcast({
      type: "control",
      action: "shutdown",
      reason: "chrome_disconnected",
    });
  });

  let idleTimer: ReturnType<typeof setTimeout> | null = null;

  const resetIdleTimer = (): void => {
    if (idleTimer) clearTimeout(idleTimer);
    if (ipcServer.clientCount() === 0) {
      idleTimer = setTimeout(() => {
        console.log("[pi-browser-daemon] Idle timeout — no clients for " +
          `${DAEMON_IDLE_TIMEOUT_MS / 60000} minutes. Shutting down.`);
        shutdown();
      }, DAEMON_IDLE_TIMEOUT_MS);
    }
  };

  const cancelIdleTimer = (): void => {
    if (idleTimer) { clearTimeout(idleTimer); idleTimer = null; }
  };

  ipcServer.onConnect(() => { cancelIdleTimer(); });
  ipcServer.onDisconnect(() => { resetIdleTimer(); });

  try {
    await ipcServer.start();
    console.log("[pi-browser-daemon] IPC server listening");
  } catch (e) {
    console.error("[pi-browser-daemon] Failed to start IPC server:", e);
    process.exit(1);
  }

  await cdpBridge.start();

  resetIdleTimer();

  const shutdown = async () => {
    console.log("[pi-browser-daemon] Shutting down...");
    await cdpBridge.stop();
    await ipcServer.stop();
    process.exit(0);
  };

  process.on("SIGINT", shutdown);
  process.on("SIGTERM", shutdown);
}

main().catch((e) => {
  console.error("[pi-browser-daemon] Fatal:", e);
  process.exit(1);
});