// The notifier as a child of the bus host. Started with fork(); the reader // capability arrives over IPC in `{op: 'start'}` and never touches argv, // stdout or the environment. Replies `{ok: true}` once the binding, the // token file and the journal check out, or `{ok: false, error}` and exits // 3. `{op: 'stop'}`, SIGTERM or the host going away stop it after the poll // in flight. import { Client } from "../../bus/src/client.mjs"; import { openDirect } from "../../discord/src/notify.mjs"; import { createNotifier, runLoop } from "./notifier.mjs"; const log = (line) => process.stderr.write(`mosaic-notify: ${line}\n`); let loop = null; let started = false; let stopping = false; async function stop(code) { if (stopping) return; stopping = true; try { await loop?.stop(); } catch { code = 1; } process.exitCode = code; if (process.connected) process.disconnect(); } if (!process.send) { process.stderr.write("trusted-host-required\n"); process.exitCode = 2; } else { const timer = setTimeout(() => stop(2), 10000); process.on("message", (m) => { if (m?.op === "stop") return stop(0); if (m?.op !== "start" || started) return; started = true; clearTimeout(timer); try { const client = new Client({ path: m.path, cap: m.cap }); const direct = openDirect({ dataRoot: m.dataRoot, name: m.binding, ...(m.base ? { base: m.base } : {}), log }); const notifier = createNotifier({ business: m.business, dataRoot: m.dataRoot, inbox: () => client.call("inbox"), direct, log }); loop = runLoop(notifier, { pollMs: m.pollMs ?? undefined, log }); process.send({ ok: true }); } catch (e) { // DiscordError and CliError messages name files, never a token or id. process.send({ ok: false, error: e?.message ?? "notifier-refused" }, () => stop(3)); } }); process.on("disconnect", () => stop(stopping ? process.exitCode : 2)); process.on("SIGTERM", () => stop(0)); process.on("SIGINT", () => {}); }