1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import { SimplePool } from 'nostr-tools/pool';
import { readFile, mkdir, writeFile, rename } from 'node:fs/promises';
import { dirname } from 'node:path';
import { buildSnapshot, createSnapshotCache, PUBLIC_FEED_RELAYS } from './cache.js';
export async function startFeedCache() {
const file = process.env.FEED_CACHE_FILE || new URL('../db/public-feed.json', import.meta.url).pathname;
let initial = null;
try {
const data = JSON.parse(await readFile(file, 'utf8'));
if (data.version === 1 && Number.isFinite(data.generatedAt) && Array.isArray(data.notes) && data.notes.length && Array.isArray(data.profiles)) initial = data;
} catch {}
// SimplePool verifies signatures and matches filters before accepting events.
const pool = new SimplePool();
const cache = createSnapshotCache({
initial,
build: () => buildSnapshot((filter) => pool.querySync(PUBLIC_FEED_RELAYS, filter, { maxWait: 4500 })),
save: async (data) => {
await mkdir(dirname(file), { recursive: true });
await writeFile(file + '.tmp', JSON.stringify(data));
await rename(file + '.tmp', file);
},
onError: (e) => console.warn('[public feed]', e.message),
});
cache.read(); // warm before the first visitor, reusing the persisted snapshot
const timer = setInterval(() => cache.read(), 15_000);
timer.unref();
return cache;
}
|