diff --git a/src/client.ts b/src/client.ts index e014d163..b73c4adb 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,12 +1,33 @@ -import { Author, findReplyTag, matchFilter, RelayPool } from '@/deps.ts'; +import { Author, findReplyTag, matchFilter, RelayPool, TTLCache } from '@/deps.ts'; import { type Event, type SignedEvent } from '@/event.ts'; -import { poolRelays } from './config.ts'; +import { poolRelays, publishRelays } from './config.ts'; import { eventDateComparator, nostrNow } from './utils.ts'; const db = await Deno.openKv(); -const pool = new RelayPool(poolRelays); + +type Pool = InstanceType; + +/** HACK: Websockets in Deno are finnicky... get a new pool every 30 minutes. */ +const poolCache = new TTLCache<0, Pool>({ + ttl: 30 * 60 * 1000, + max: 2, + dispose: (pool) => { + console.log('Closing pool.'); + pool.close(); + }, +}); + +function getPool(): Pool { + const cached = poolCache.get(0); + if (cached !== undefined) return cached; + + console.log('Creating new pool.'); + const pool = new RelayPool(poolRelays); + poolCache.set(0, pool); + return pool; +} type Filter = { ids?: string[]; @@ -29,7 +50,7 @@ function getFilter(filter: Filter, opts: GetFilterOpts = {} let tid: number; const results: SignedEvent[] = []; - const unsub = pool.subscribe( + const unsub = getPool().subscribe( [filter], poolRelays, (event: SignedEvent | null) => { @@ -69,7 +90,7 @@ function getFilter(filter: Filter, opts: GetFilterOpts = {} /** Get a Nostr event by its ID. */ const getEvent = async (id: string, kind?: K): Promise | undefined> => { - const event = await (pool.getEventById(id, poolRelays, 0) as Promise); + const event = await (getPool().getEventById(id, poolRelays, 0) as Promise); if (event) { if (event.id !== id) return undefined; if (kind && event.kind !== kind) return undefined; @@ -79,7 +100,7 @@ const getEvent = async (id: string, kind?: K): Promis /** Get a Nostr `set_medatadata` event for a user's pubkey. */ const getAuthor = async (pubkey: string): Promise | undefined> => { - const author = new Author(pool, poolRelays, pubkey); + const author = new Author(getPool(), poolRelays, pubkey); const event: SignedEvent<0> | null = await new Promise((resolve) => author.metaData(resolve, 0)); return event?.pubkey === pubkey ? event : undefined; }; @@ -88,7 +109,7 @@ const getAuthor = async (pubkey: string): Promise | undefined> => const getFollows = async (pubkey: string): Promise | undefined> => { const [event] = await getFilter({ authors: [pubkey], kinds: [3] }, { timeout: 5000 }); - // TODO: figure out a better, more generic & flexible way to handle event (and timeouts?) + // TODO: figure out a better, more generic & flexible way to handle event cache (and timeouts?) // Prewarm cache in GET `/api/v1/accounts/verify_credentials` if (event) { await db.set(['event3', pubkey], event); @@ -148,4 +169,14 @@ function getDescendants(eventId: string): Promise[]> { return getFilter({ kinds: [1], '#e': [eventId], limit: 200 }, { timeout: 2000 }) as Promise[]>; } -export { getAncestors, getAuthor, getDescendants, getEvent, getFeed, getFilter, getFollows, pool }; +/** Publish an event to the Nostr relay. */ +function publish(event: SignedEvent, relays = publishRelays): void { + console.log('Publishing event', event); + try { + getPool().publish(event, relays); + } catch (e) { + console.error(e); + } +} + +export { getAncestors, getAuthor, getDescendants, getEvent, getFeed, getFilter, getFollows, publish }; diff --git a/src/controllers/api/statuses.ts b/src/controllers/api/statuses.ts index b4d45901..e9521d81 100644 --- a/src/controllers/api/statuses.ts +++ b/src/controllers/api/statuses.ts @@ -1,8 +1,7 @@ import { type AppContext, AppController } from '@/app.ts'; -import { getAncestors, getDescendants, getEvent } from '@/client.ts'; +import { getAncestors, getDescendants, getEvent, publish } from '@/client.ts'; import { Kind, validator, z } from '@/deps.ts'; import { type Event } from '@/event.ts'; -import publish from '@/publisher.ts'; import { signEvent } from '@/sign.ts'; import { toStatus } from '@/transmute.ts'; diff --git a/src/publisher.ts b/src/publisher.ts deleted file mode 100644 index ad74556f..00000000 --- a/src/publisher.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { type SignedEvent } from '@/event.ts'; - -import { pool } from './client.ts'; -import { publishRelays } from './config.ts'; - -/** Publish an event to the Nostr relay. */ -function publish(event: SignedEvent, relays = publishRelays): void { - console.log('Publishing event', event); - try { - pool.publish(event, relays); - } catch (e) { - console.error(e); - } -} - -export default publish;