/** * A stand-in gateway that stays connected and answers printer provisioning, * for scripts/e2e-provision.sh. * * With TELEMETRY_AFTER_PROVISION=1 it also reports each provisioned printer * (running, then failed a few seconds later), so the console has something to * alert on. * * With REPORT_IDLE= it reports that printer idle on * connect, so the scheduler treats it as free. A `start_print` command is * accepted, the file is downloaded from its presigned URL and hashed (the * hash is appended to the frames file, never the URL), and the printer then * reports running and finished, like a real print that goes well. * * Needs FARM_ID in the environment (the hello must name the token's farm). * * Usage: bun scripts/fake-gateway-serve.ts [refuse-access-code] * * Every provision_printer / remove_printer frame it receives is appended to * as one JSON line, so the script can prove the credential * arrived here. A provision whose access_code equals is * answered as a failure, like a printer that rejected the login. */ import { appendFileSync } from "node:fs"; const [url, jwt, seconds, framesFile, refuseCode] = process.argv.slice(2); if (!url || !jwt || !seconds || !framesFile) { console.error("usage: fake-gateway-serve.ts [refuse-code]"); process.exit(2); } const ws = new WebSocket(url, { headers: { authorization: `Bearer ${jwt}` } } as never); ws.onerror = () => { console.error("socket error"); process.exit(1); }; ws.onopen = () => { // farm_id is required by the hello schema; the backend checks it against the token's farm. ws.send(JSON.stringify({ type: "hello", gateway_id: "fake-gw", farm_id: process.env.FARM_ID })); if (process.env.REPORT_IDLE) { ws.send(JSON.stringify({ type: "telemetry", printers: [{ printer_id: process.env.REPORT_IDLE, name: "Fake", state: "IDLE", percent: 0, print_error: 0 }] })); } console.log("ready"); }; async function printFile(message: { command_id: string; printer_id: string; command: { job_id: string; file_name: string; url: string } }) { const report = (state: string, percent: number) => ws.send(JSON.stringify({ type: "telemetry", printers: [{ printer_id: message.printer_id, name: "Fake", state, percent, print_error: 0 }] })); const body = new Uint8Array(await (await fetch(message.command.url)).arrayBuffer()); const digest = new Bun.CryptoHasher("sha256").update(body).digest("hex"); appendFileSync(framesFile, JSON.stringify({ type: "downloaded", file_name: message.command.file_name, bytes: body.length, sha256: digest }) + "\n"); report("RUNNING", 20); setTimeout(() => report("RUNNING", 60), 1500); setTimeout(() => report("FINISH", 100), 3000); } ws.onmessage = (event) => { const message = JSON.parse(String(event.data)); if (message.type === "command" && message.command?.action === "start_print") { appendFileSync(framesFile, JSON.stringify({ type: "start_print", printer_id: message.printer_id, file_name: message.command.file_name, job_id: message.command.job_id }) + "\n"); ws.send(JSON.stringify({ type: "command_result", command_id: message.command_id, ok: true })); void printFile(message); return; } if (message.type !== "provision_printer" && message.type !== "remove_printer") return; appendFileSync(framesFile, JSON.stringify(message) + "\n"); if (message.type === "provision_printer" && process.env.TELEMETRY_AFTER_PROVISION === "1") { const id = message.printer.id; const report = (state: string) => ws.send(JSON.stringify({ type: "telemetry", printers: [{ printer_id: id, name: message.printer.name, state, percent: 40, print_error: 0 }] })); setTimeout(() => report("RUNNING"), 1500); setTimeout(() => report("RUNNING"), 3000); setTimeout(() => report("FAILED"), 4500); } const refused = message.type === "provision_printer" && refuseCode && message.printer.access_code === refuseCode; ws.send( JSON.stringify({ type: "command_result", command_id: message.request_id, ok: !refused, ...(refused ? { error: "could not connect to the printer: the access code was rejected" } : {}), }), ); }; setTimeout(() => process.exit(0), Number(seconds) * 1000);