Files
stack/packages/cli/src/notifier-process.mjs
T

59 lines
2.4 KiB
JavaScript

// 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";
import { withProcessing, currentProcessing } from '../../processing-control/src/effects.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 processing = { work: fn => withProcessing(m.dataRoot, fn), guard: () => currentProcessing()?.guard() };
const direct = openDirect({ dataRoot: m.instanceRoot ?? m.dataRoot, name: m.binding, ...(m.base ? { base: m.base } : {}),
fetch: (url, init) => {
const scope = currentProcessing(); scope?.guard();
return fetch(url, { ...init, ...(scope ? { signal: scope.signal } : {}) });
}, log });
const notifier = createNotifier({ business: m.business, dataRoot: m.dataRoot, inbox: () => client.call("inbox"), direct, processing, 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", () => {});
}