aboutsummaryrefslogtreecommitdiffstats
path: root/feed/server.js
diff options
context:
space:
mode:
Diffstat (limited to 'feed/server.js')
-rw-r--r--feed/server.js19
1 files changed, 15 insertions, 4 deletions
diff --git a/feed/server.js b/feed/server.js
index 12ff850..9566447 100644
--- a/feed/server.js
+++ b/feed/server.js
@@ -2,26 +2,34 @@ import { SimplePool } from 'nostr-tools/pool';
import { startFeedCache } from './service.js';
import { snapshotResponse } from './cache.js';
import { NOTE_PATH, buildThread, createThreadCache, createIndexSource, notePageResponse } from './note-page.js';
+import { PROFILE_PATH, buildProfile, createPrimal, createNameResolver, profilePageResponse } from './profile-page.js';
const cache = await startFeedCache();
// SimplePool verifies signatures and matches filters before accepting events.
const pool = new SimplePool();
// Every relay's answer, or maxWait — but an ask by id is done the moment
-// every id has turned up, rather than waiting out the slowest relay.
-const query = (relays, filter, maxWait) => new Promise((resolve) => {
+// every id has turned up, rather than waiting out the slowest relay. With
+// `idle`, the answer is also done once events have been arriving and then
+// stop for that long: one relay that never says EOSE no longer holds a
+// profile page for the whole maxWait.
+const query = (relays, filter, maxWait, { idle = 0 } = {}) => new Promise((resolve) => {
const got = new Map();
- let done = false, sub = null;
- const finish = () => { if (done) return; done = true; try { sub && sub.close(); } catch {} resolve([...got.values()]); };
+ let done = false, sub = null, quiet = null;
+ const finish = () => { if (done) return; done = true; clearTimeout(quiet); try { sub && sub.close(); } catch {} resolve([...got.values()]); };
sub = pool.subscribeManyEose(relays, filter, {
maxWait,
onevent(e) {
got.set(e.id, e);
if (filter.ids && filter.ids.every((id) => got.has(id))) finish();
+ if (idle) { clearTimeout(quiet); quiet = setTimeout(finish, idle); }
},
onclose: finish,
});
if (done) try { sub.close(); } catch {}
});
const threads = createThreadCache({ build: (ref) => buildThread(ref, query) });
+const primal = createPrimal();
+const profiles = createThreadCache({ build: (ref) => buildProfile(ref, { query, primal }) });
+const resolveName = createNameResolver({ url: process.env.NAMES_URL || 'https://names.coinos.io' });
const index = createIndexSource(process.env.INDEX_URL || 'http://bitcoin-wallet/index.html');
const server = Bun.serve({
hostname: process.env.HOST || '127.0.0.1',
@@ -33,6 +41,9 @@ const server = Bun.serve({
if (NOTE_PATH.test(path) && ['GET', 'HEAD'].includes(req.method)) {
try { return await notePageResponse(req, { index, threads }); } catch { return new Response('Unavailable', { status: 502 }); }
}
+ if (PROFILE_PATH.test(path) && ['GET', 'HEAD'].includes(req.method)) {
+ try { return await profilePageResponse(req, { index, profiles, resolveName }); } catch { return new Response('Unavailable', { status: 502 }); }
+ }
return new Response('Not found', { status: 404 });
},
});