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));