From 55c69af4c5bdc93f923e4c6c8e521eab2b7fc2b0 Mon Sep 17 00:00:00 2001 From: Ashelyn Rose Date: Sat, 10 May 2025 00:34:10 -0600 Subject: Persist scrollback --- .gitignore | 1 + index.js | 30 ++++++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e46e79c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.scrollback diff --git a/index.js b/index.js index d91d459..294ad72 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,5 @@ const path = require('node:path') -const {promises: {readFile}, createReadStream} = require('node:fs') +const {promises: {readFile}, readFileSync, createReadStream, createWriteStream} = require('node:fs') const {createServer} = require('node:http') const {createHash, randomBytes} = require('node:crypto') const Readline = require('node:readline'); @@ -12,18 +12,44 @@ const readline = Readline.createInterface({ prompt: '> ', }); - const MAX_EVENTS = 100 +// Event emitter and buffer for late joiners const chatEvents = new EventEmitter() +let bufferDirty = true let eventBuffer = [] chatEvents.on('event', ev => { eventBuffer = [...eventBuffer, ev].slice(0, MAX_EVENTS) + bufferDirty = true readline.clearLine() console.log(JSON.stringify(ev)) readline.prompt() }) +// Populate buffer on startup +const scrollbackFile = path.join(__dirname, '.scrollback') +try { + eventBuffer = readFileSync(scrollbackFile, {encoding: 'utf8'}).split('\n') + .map(line => { + try { + return JSON.parse(line) + } catch { + return null + } + }).filter(event => !!event) + bufferDirty = false +} catch { } + +// Sync buffer to disk every second +setInterval(async () => { + if (!bufferDirty) return + + const fileStream = createWriteStream(scrollbackFile, {flags: 'w', encoding: 'utf8'}) + for (const event of eventBuffer) { + await new Promise(res => fileStream.write(JSON.stringify(event) + '\n', 'utf8', res)) + } +}, 1000) + let currentUsers = {} readline.on('line', (line) => { -- cgit 1.4.1