host.mjs · raw · all files

1// Bend Bank: the host2// ===================3//4// The bank is web.bend, compiled to web.mjs. This file only moves bytes:5// it replays the log into the bank at boot, then reads HTTP requests off6// each connection, in order; for each, it prefixes the time and a fresh7// random key, asks Web.serve for the answer, appends the input to the log8// when the bank changed (before answering), and writes the answer back.9// Bytes cross as latin1, one character per byte. Connections stay open10// for the next request (Caddy reuses them) until idle for 30 seconds.11// Usage: node host.mjs PORT LOG1213import net from "node:net";14import fs from "node:fs";15import crypto from "node:crypto";16import Bank from "./web.mjs";1718const [port, path] = [Number(process.argv[2]), process.argv[3]];19const room = 16384;2021// the bank after an input, and the answer22function serve(bank, input) {23  const reply = Bank["Web.serve"](bank, input);24  return [reply.bank.$ === "Some" ? reply.bank.value : null, reply.text];25}2627let bank = Bank["bank:Bank.genesis"]();28for (const line of fs.existsSync(path) ? fs.readFileSync(path, "latin1").split("\n") : []) {29  if (line) bank = serve(bank, JSON.parse(line))[0] ?? bank;30}31const log = fs.openSync(path, "a");3233net.createServer((sock) => {34  let buf = "";35  sock.setEncoding("latin1");36  sock.setTimeout(30000, () => sock.destroy());37  sock.on("error", () => {});38  sock.on("data", (chunk) => {39    buf += chunk;40    try {41      for (;;) {42        const size = buf.length > room ? null : Bank["Req.size"](buf);43        if (size === null || size.$ === "Some" && size.value > room) return sock.destroy();44        if (size.$ !== "Some" || buf.length < size.value) return;45        const time = Math.floor(Date.now() / 1000);46        const input = time + "\n" + crypto.randomBytes(16).toString("hex") + "\n" + buf.slice(0, size.value);47        buf = buf.slice(size.value);48        const [next, text] = serve(bank, input);49        if (next) {50          fs.writeSync(log, JSON.stringify(input) + "\n");51          bank = next;52        }53        sock.write(text, "latin1");54      }55    } catch (e) {56      console.error(e);57      sock.destroy();58    }59  });60}).listen({port, host: "127.0.0.1", backlog: 4096}, () => console.log("bank on " + port));