Static site hosting via tangled

Add memory cache limits and ws reconnect

+24 -4
src/knot-event-listener.js
···
import EventEmitter from "node:events";
export class KnotEventListener extends EventEmitter {
-
constructor({ knotDomain }) {
+
constructor({ knotDomain, reconnectTimeout = 10000 }) {
super();
this.knotDomain = knotDomain;
+
this.reconnectTimeout = reconnectTimeout;
+
this.connection = null;
}
async start() {
-
const ws = new WebSocket(`wss://${this.knotDomain}/events`);
-
ws.onmessage = (event) => this.handleMessage(event);
+
this.connection = new WebSocket(`wss://${this.knotDomain}/events`);
+
this.connection.onmessage = (event) => this.handleMessage(event);
+
this.connection.onerror = (event) => this.handleError(event);
+
this.connection.onclose = () => this.handleClose();
return new Promise((resolve) => {
-
ws.onopen = () => {
+
this.connection.onopen = () => {
console.log("Knot event listener connected to:", this.knotDomain);
resolve();
};
···
},
};
this.emit("refUpdate", event);
+
}
+
}
+
+
handleError(event) {
+
console.error("Knot event listener error:", event);
+
this.emit("error", event);
+
}
+
+
handleClose() {
+
console.log("Knot event listener closed");
+
this.emit("close");
+
if (this.reconnectTimeout) {
+
setTimeout(() => {
+
console.log("Knot event listener reconnecting...");
+
this.start();
+
}, this.reconnectTimeout).unref();
}
}
}
+17 -3
src/pages-service.js
···
import { KnotClient } from "./knot-client.js";
class FileCache {
-
constructor() {
+
constructor({ maxSize } = {}) {
this.cache = new Map();
+
this.maxSize = maxSize;
}
get(filename) {
···
set(filename, content) {
this.cache.set(filename, content);
+
// Evict oldest item if cache is full
+
if (this.maxSize && this.cache.size > this.maxSize) {
+
const oldestKey = this.cache.keys().next().value;
+
this.cache.delete(oldestKey);
+
}
}
clear() {
···
this.fileCache = null;
if (cache) {
console.log("Enabling cache for", this.ownerDid, this.repoName);
-
this.fileCache = new FileCache();
+
this.fileCache = new FileCache({ maxSize: 100 });
}
}
···
} else {
content = blob.contents;
}
-
this.fileCache?.set(filename, content);
+
if (this.fileCache && content) {
+
const contentSize = Buffer.isBuffer(content)
+
? content.length
+
: Buffer.byteLength(content, "utf8");
+
// Cache unless content is too large (5MB)
+
if (contentSize < 5 * 1024 * 1024) {
+
this.fileCache.set(filename, content);
+
}
+
}
return content;
}