// route-adapter's one pass — the module's own code (novox/hq ADR 0039), run as a step (ADR 0052) // and run *again* whenever what it reads changes. // // **A step, not a loop.** Everything this module does is a function of two files the mesh writes: // the contributions at `receives.route`, and its settings. The manifest's container is `run-once` // and names both under `restart-on`, so the host runs it once and runs it again the moment either // changes — which is the mechanism already in the catalogue for "a fact arrived, do it again" // (novox/hq ADR 0099). A watcher of its own would be a second way to notice the same event, and it // would keep running after the module was unassigned. // // It connects to no broker: this is an offline file operation on the machine it runs on, and // `mesh-tools run` gives it exactly that. import { readFile } from "node:fs/promises"; import { reconcile, routesFrom, settingsFrom } from "./adapter.js"; const receives = process.env.MESH_RECEIVES ?? "/var/lib/route-adapter/routes/mesh.json"; const configFile = process.env.MESH_ROUTE_ADAPTER_CONFIG ?? "/run/config/config.json"; // The settings the node laid over the module's defaults. Absent is not an error — the mesh always // writes the file, and a node that overrode nothing leaves it holding the defaults. const settings = settingsFrom(await readJSON(configFile)); // The contributions. Absent is also not an error here: the host writes this file before it starts // the container, and the empty case — nothing contributed — means every route this module wrote is // to be taken away, which is a real instruction and not a reason to stop. const { routes, skipped } = routesFrom(await readJSON(receives), settings.machine); for (const why of skipped) { console.warn(`[route-adapter] ${why}`); } const pass = await reconcile(routes, settings); for (const why of pass.skipped) { console.warn(`[route-adapter] ${why}`); } console.log( `[route-adapter] ${routes.length} route(s) contributed; ` + `wrote ${pass.written.length} and removed ${pass.removed.length} in ${settings.dynamic}` + (pass.written.length > 0 ? `: ${pass.written.join(", ")}` : "") + (pass.removed.length > 0 ? `; gone: ${pass.removed.join(", ")}` : ""), ); async function readJSON(path: string): Promise { const raw = await readFile(path, "utf8").catch(() => undefined); if (raw === undefined) { return undefined; } return JSON.parse(raw) as unknown; }