From 751c09035cf7a723b02cf06b4d28af56ece86261 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 23 Feb 2025 19:39:43 -0600 Subject: [PATCH] Pass DittoAPIStore to MastoAPI endpoints, DittoRelayStore to /relay --- packages/ditto/app.ts | 28 +++++++++---- packages/ditto/storages/DittoAPIStore.ts | 46 ++++++++++++---------- packages/ditto/storages/DittoRelayStore.ts | 2 +- scripts/db-populate-nip05.ts | 7 ++-- 4 files changed, 50 insertions(+), 33 deletions(-) diff --git a/packages/ditto/app.ts b/packages/ditto/app.ts index 0a9806d6..9f202786 100644 --- a/packages/ditto/app.ts +++ b/packages/ditto/app.ts @@ -148,6 +148,7 @@ import { rateLimitMiddleware } from '@/middleware/rateLimitMiddleware.ts'; import { uploaderMiddleware } from '@/middleware/uploaderMiddleware.ts'; import { translatorMiddleware } from '@/middleware/translatorMiddleware.ts'; import { logiMiddleware } from '@/middleware/logiMiddleware.ts'; +import { DittoRelayStore } from '@/storages/DittoRelayStore.ts'; export interface AppEnv extends DittoEnv { Variables: { @@ -188,32 +189,33 @@ const db = new DittoPolyPg(conf.databaseUrl, { await db.migrate(); -const store = new DittoPgStore({ +const pgstore = new DittoPgStore({ db, pubkey: await conf.signer.getPublicKey(), timeout: conf.db.timeouts.default, notify: conf.notifyEnabled, }); -const pool = new DittoPool({ conf, relay: store }); -const relay = new DittoAPIStore({ db, conf, relay: store, pool }); +const pool = new DittoPool({ conf, relay: pgstore }); +const relaystore = new DittoRelayStore({ db, conf, relay: pgstore }); +const apistore = new DittoAPIStore({ relay: relaystore, pool }); -await seedZapSplits(relay); +await seedZapSplits(apistore); if (conf.firehoseEnabled) { startFirehose({ pool, - store: relay, + store: relaystore, concurrency: conf.firehoseConcurrency, kinds: conf.firehoseKinds, }); } if (conf.cronEnabled) { - cron({ conf, db, relay }); + cron({ conf, db, relay: relaystore }); } -const app = new DittoApp({ conf, db, relay }, { strict: false }); +const app = new DittoApp({ conf, db, relay: relaystore }, { strict: false }); /** User-provided files in the gitignored `public/` directory. */ const publicFiles = serveStatic({ root: './public/' }); @@ -240,7 +242,17 @@ app.use('/nodeinfo/*', metricsMiddleware, ratelimit, logiMiddleware); app.use('/oauth/*', metricsMiddleware, ratelimit, logiMiddleware); app.get('/api/v1/streaming', socketTokenMiddleware, metricsMiddleware, ratelimit, streamingController); -app.get('/relay', metricsMiddleware, ratelimit, relayController); + +app.get( + '/relay', + (c, next) => { + c.set('relay', relaystore); + return next(); + }, + metricsMiddleware, + ratelimit, + relayController, +); app.use( cspMiddleware(), diff --git a/packages/ditto/storages/DittoAPIStore.ts b/packages/ditto/storages/DittoAPIStore.ts index 42e08011..6df5ebba 100644 --- a/packages/ditto/storages/DittoAPIStore.ts +++ b/packages/ditto/storages/DittoAPIStore.ts @@ -1,54 +1,60 @@ -import { DittoConf } from '@ditto/conf'; -import { DittoDB } from '@ditto/db'; import { logi } from '@soapbox/logi'; -import { NostrEvent, NRelay } from '@nostrify/nostrify'; +import { NostrEvent, NostrFilter, NostrRelayCLOSED, NostrRelayEOSE, NostrRelayEVENT, NRelay } from '@nostrify/nostrify'; -import { DittoRelayStore } from '@/storages/DittoRelayStore.ts'; import { errorJson } from '@/utils/log.ts'; import { purifyEvent } from '@/utils/purify.ts'; interface DittoAPIStoreOpts { - db: DittoDB; - conf: DittoConf; pool: NRelay; relay: NRelay; - fetch?: typeof fetch; } /** * Store used by Ditto's Mastodon API implementation. * It extends the RelayStore to publish events to the wider Nostr network. */ -export class DittoAPIStore extends DittoRelayStore { - _opts: DittoAPIStoreOpts; +export class DittoAPIStore implements NRelay { + private ns = 'ditto.api.store'; - private _ns = 'ditto.relay.store'; + constructor(private opts: DittoAPIStoreOpts) {} - constructor(opts: DittoAPIStoreOpts) { - super(opts); - this._opts = opts; + req( + filters: NostrFilter[], + opts?: { signal?: AbortSignal }, + ): AsyncIterable { + const { relay } = this.opts; + return relay.req(filters, opts); } - override async event(event: NostrEvent, opts?: { signal?: AbortSignal }): Promise { - const { pool } = this._opts; + query(filters: NostrFilter[], opts?: { signal?: AbortSignal }): Promise { + const { relay } = this.opts; + return relay.query(filters, opts); + } + + async event(event: NostrEvent, opts?: { signal?: AbortSignal }): Promise { + const { pool, relay } = this.opts; const { id, kind } = event; - await super.event(event, opts); + await relay.event(event, opts); (async () => { try { // `purifyEvent` is important, or you will suffer. await pool.event(purifyEvent(event), opts); } catch (e) { - logi({ level: 'error', ns: this._ns, source: 'publish', id, kind, error: errorJson(e) }); + logi({ level: 'error', ns: this.ns, source: 'publish', id, kind, error: errorJson(e) }); } })(); } - override async close(): Promise { - const { pool } = this._opts; + async close(): Promise { + const { pool, relay } = this.opts; await pool.close(); - await super.close(); + await relay.close(); + } + + [Symbol.asyncDispose](): Promise { + return this.close(); } } diff --git a/packages/ditto/storages/DittoRelayStore.ts b/packages/ditto/storages/DittoRelayStore.ts index 1553d422..7b935d96 100644 --- a/packages/ditto/storages/DittoRelayStore.ts +++ b/packages/ditto/storages/DittoRelayStore.ts @@ -60,7 +60,7 @@ export class DittoRelayStore implements NRelay { private faviconCache: SimpleLRU; private nip05Cache: SimpleLRU; - private ns = 'ditto.api.store'; + private ns = 'ditto.relay.store'; constructor(private opts: DittoRelayStoreOpts) { const { conf, db } = this.opts; diff --git a/scripts/db-populate-nip05.ts b/scripts/db-populate-nip05.ts index 46e0686d..c1015f9f 100644 --- a/scripts/db-populate-nip05.ts +++ b/scripts/db-populate-nip05.ts @@ -1,18 +1,17 @@ import { Semaphore } from '@core/asyncutil'; import { NostrEvent } from '@nostrify/nostrify'; -import { MockRelay } from '@nostrify/nostrify/test'; import { DittoConf } from '@ditto/conf'; import { DittoPolyPg } from '@ditto/db'; -import { DittoAPIStore } from '../packages/ditto/storages/DittoAPIStore.ts'; import { DittoPgStore } from '../packages/ditto/storages/DittoPgStore.ts'; +import { DittoRelayStore } from '../packages/ditto/storages/DittoRelayStore.ts'; const conf = new DittoConf(Deno.env); const db = new DittoPolyPg(conf.databaseUrl); const pgstore = new DittoPgStore({ db, pubkey: await conf.signer.getPublicKey() }); -const apistore = new DittoAPIStore({ conf, db, relay: pgstore, pool: new MockRelay() }); +const relaystore = new DittoRelayStore({ conf, db, relay: pgstore }); const sem = new Semaphore(5); @@ -28,7 +27,7 @@ for await (const row of query.stream(100)) { sem.lock(async () => { const event: NostrEvent = { ...row, created_at: Number(row.created_at) }; - await apistore.updateAuthorData(event, AbortSignal.timeout(3000)); + await relaystore.updateAuthorData(event, AbortSignal.timeout(3000)); }); }