aboutsummaryrefslogtreecommitdiffstats
path: root/feed/service.js
blob: 304b40f4d9dae6e8a22841aade555932ce086632 (plain) (blame)
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;
}