diff --git a/src/storages.ts b/src/storages.ts index 045a362..db00b51 100644 --- a/src/storages.ts +++ b/src/storages.ts @@ -2,7 +2,9 @@ import { Conf } from '@/config.ts'; import { db } from '@/db.ts'; import { EventsDB } from '@/storages/events-db.ts'; import { Memorelay } from '@/storages/memorelay.ts'; +import { Optimizer } from '@/storages/optimizer.ts'; import { SearchStore } from '@/storages/search-store.ts'; +import { reqmeister } from '@/reqmeister.ts'; /** SQLite database to store events this Ditto server cares about. */ const eventsDB = new EventsDB(db); @@ -10,10 +12,17 @@ const eventsDB = new EventsDB(db); /** In-memory data store for cached events. */ const memorelay = new Memorelay({ max: 3000 }); +/** Main Ditto storage adapter */ +const optimizer = new Optimizer({ + db: eventsDB, + cache: memorelay, + client: reqmeister, +}); + /** Storage to use for remote search. */ const searchStore = new SearchStore({ relay: Conf.searchRelay, - fallback: eventsDB, + fallback: optimizer, }); -export { eventsDB, memorelay, searchStore }; +export { eventsDB, memorelay, optimizer, searchStore }; diff --git a/src/storages/optimizer.ts b/src/storages/optimizer.ts index 5bd4af8..e0d18fb 100644 --- a/src/storages/optimizer.ts +++ b/src/storages/optimizer.ts @@ -1,3 +1,4 @@ +import { Debug } from '@/deps.ts'; import { type DittoFilter, normalizeFilters } from '@/filter.ts'; import { EventSet } from '@/utils/event-set.ts'; @@ -10,6 +11,8 @@ interface OptimizerOpts { } class Optimizer implements EventStore { + #debug = Debug('ditto:optimizer'); + #db: EventStore; #cache: EventStore; #client: EventStore; @@ -33,6 +36,8 @@ class Optimizer implements EventStore { filters: DittoFilter[], opts: GetEventsOpts | undefined = {}, ): Promise[]> { + this.#debug('REQ', JSON.stringify(filters)); + const { limit = Infinity } = opts; filters = normalizeFilters(filters); @@ -45,6 +50,7 @@ class Optimizer implements EventStore { for (let i = 0; i < filters.length; i++) { const filter = filters[i]; if (filter.ids) { + this.#debug(`Filter[${i}] is an IDs filter; querying cache...`); const ids = new Set(filter.ids); for (const event of await this.#cache.getEvents([filter], opts)) { ids.delete(event.id); @@ -59,18 +65,27 @@ class Optimizer implements EventStore { if (!filters.length) return getResults(); // Query the database for events. + this.#debug('Querying database...'); for (const dbEvent of await this.#db.getEvents(filters, opts)) { results.add(dbEvent); if (results.size >= limit) return getResults(); } + // We already searched the DB, so stop if this is a search filter. + if (filters.some((filter) => typeof filter.search === 'string')) { + this.#debug(`Bailing early for search filter: "${filters[0]?.search}"`); + return getResults(); + } + // Query the cache again. + this.#debug('Querying cache...'); for (const cacheEvent of await this.#cache.getEvents(filters, opts)) { results.add(cacheEvent); if (results.size >= limit) return getResults(); } // Finally, query the client. + this.#debug('Querying client...'); for (const clientEvent of await this.#client.getEvents(filters, opts)) { results.add(clientEvent); if (results.size >= limit) return getResults(); diff --git a/src/storages/search-store.ts b/src/storages/search-store.ts index c5a0a3c..7dd2de8 100644 --- a/src/storages/search-store.ts +++ b/src/storages/search-store.ts @@ -57,7 +57,7 @@ class SearchStore implements EventStore { const authorIds = new Set([...events].map((event) => event.pubkey)); const authors = await this.getEvents([{ kinds: [0], authors: [...authorIds] }], opts); for (const event of events) { - event.author = authors.find((author) => author.id === event.pubkey); + event.author = authors.find((author) => author.pubkey === event.pubkey); } }