From cb80770fc75de1ef163fb7ddf3d996400afac73e Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 12 Feb 2024 10:48:26 -0600 Subject: [PATCH] Upgrade NSpec, update `count` interface --- src/controllers/nostr/relay.ts | 2 +- src/deps.ts | 3 +-- src/pipeline.ts | 16 ++++++++++------ src/storages/events-db.test.ts | 8 ++++---- src/storages/events-db.ts | 9 ++++++--- src/storages/optimizer.ts | 8 -------- src/storages/pool-store.ts | 8 -------- src/storages/reqmeister.ts | 8 -------- src/storages/search-store.ts | 10 +--------- src/utils/SimpleLRU.ts | 4 ++-- 10 files changed, 25 insertions(+), 51 deletions(-) diff --git a/src/controllers/nostr/relay.ts b/src/controllers/nostr/relay.ts index 53d51ba..56b6e51 100644 --- a/src/controllers/nostr/relay.ts +++ b/src/controllers/nostr/relay.ts @@ -96,7 +96,7 @@ function connectStream(socket: WebSocket) { /** Handle COUNT. Return the number of events matching the filters. */ async function handleCount([_, subId, ...rest]: ClientCOUNT): Promise { - const count = await eventsDB.count(prepareFilters(rest)); + const { count } = await eventsDB.count(prepareFilters(rest)); send(['COUNT', subId, { count, approximate: false }]); } diff --git a/src/deps.ts b/src/deps.ts index 385d84f..e209018 100644 --- a/src/deps.ts +++ b/src/deps.ts @@ -85,7 +85,6 @@ export { default as Debug } from 'https://gitlab.com/soapbox-pub/stickynotes/-/r export { LNURL, type LNURLDetails, - type MapCache, NCache, NIP05, type NostrEvent, @@ -93,6 +92,6 @@ export { NSet, type NStore, type NStoreOpts, -} from 'https://gitlab.com/soapbox-pub/NSpec/-/raw/8ce84d9acd9925f51b51c00374eae81a5031559b/mod.ts'; +} from 'https://gitlab.com/soapbox-pub/NSpec/-/raw/v0.1.0/mod.ts'; export type * as TypeFest from 'npm:type-fest@^4.3.0'; diff --git a/src/pipeline.ts b/src/pipeline.ts index f326258..4037a97 100644 --- a/src/pipeline.ts +++ b/src/pipeline.ts @@ -46,7 +46,7 @@ async function handleEvent(event: DittoEvent, signal: AbortSignal): Promise { - const preexisting = (await cache.count([{ ids: [event.id] }])) > 0; + const preexisting = (await cache.count([{ ids: [event.id] }])).count > 0; cache.event(event); reqmeister.event(event, { signal }); return preexisting; @@ -72,10 +72,10 @@ async function storeEvent(event: DittoEvent, opts: StoreEventOpts): Promise 0; + )).count > 0; if (isDeleted) { return Promise.reject(new RelayError('blocked', 'event was deleted')); @@ -145,13 +145,17 @@ function trackRelays(event: NostrEvent) { } /** Queue related events to fetch. */ -function fetchRelatedEvents(event: DittoEvent, signal: AbortSignal) { +async function fetchRelatedEvents(event: DittoEvent, signal: AbortSignal) { if (!event.user) { reqmeister.req({ kinds: [0], authors: [event.pubkey] }, { signal }).catch(() => {}); } + for (const [name, id, relay] of event.tags) { - if (name === 'e' && !cache.count([{ ids: [id] }])) { - reqmeister.req({ ids: [id] }, { relays: [relay] }).catch(() => {}); + if (name === 'e') { + const { count } = await cache.count([{ ids: [id] }]); + if (!count) { + reqmeister.req({ ids: [id] }, { relays: [relay] }).catch(() => {}); + } } } } diff --git a/src/storages/events-db.test.ts b/src/storages/events-db.test.ts index 896770f..32aee80 100644 --- a/src/storages/events-db.test.ts +++ b/src/storages/events-db.test.ts @@ -10,9 +10,9 @@ import { EventsDB } from './events-db.ts'; const eventsDB = new EventsDB(db); Deno.test('count filters', async () => { - assertEquals(await eventsDB.count([{ kinds: [1] }]), 0); + assertEquals((await eventsDB.count([{ kinds: [1] }])).count, 0); await eventsDB.event(event1); - assertEquals(await eventsDB.count([{ kinds: [1] }]), 1); + assertEquals((await eventsDB.count([{ kinds: [1] }])).count, 1); }); Deno.test('insert and filter events', async () => { @@ -55,11 +55,11 @@ Deno.test('query events with local filter', async () => { }); Deno.test('inserting replaceable events', async () => { - assertEquals(await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }]), 0); + assertEquals((await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }])).count, 0); await eventsDB.event(event0); await assertRejects(() => eventsDB.event(event0)); - assertEquals(await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }]), 1); + assertEquals((await eventsDB.count([{ kinds: [0], authors: [event0.pubkey] }])).count, 1); const changeEvent = { ...event0, id: '123', created_at: event0.created_at + 1 }; await eventsDB.event(changeEvent); diff --git a/src/storages/events-db.ts b/src/storages/events-db.ts index 11dbdf7..4f286d8 100644 --- a/src/storages/events-db.ts +++ b/src/storages/events-db.ts @@ -345,9 +345,9 @@ class EventsDB implements NStore { } /** Get number of events that would be returned by filters. */ - async count(filters: DittoFilter[], opts: NStoreOpts = {}): Promise { + async count(filters: DittoFilter[], opts: NStoreOpts = {}): Promise<{ count: number; approximate: boolean }> { if (opts.signal?.aborted) return Promise.reject(abortError()); - if (!filters.length) return Promise.resolve(0); + if (!filters.length) return Promise.resolve({ count: 0, approximate: false }); this.#debug('COUNT', JSON.stringify(filters)); const query = this.getEventsQuery(filters); @@ -357,7 +357,10 @@ class EventsDB implements NStore { .select((eb) => eb.fn.count('id').as('count')) .execute(); - return Number(count); + return { + count: Number(count), + approximate: false, + }; } } diff --git a/src/storages/optimizer.ts b/src/storages/optimizer.ts index 10d509a..67c838c 100644 --- a/src/storages/optimizer.ts +++ b/src/storages/optimizer.ts @@ -94,14 +94,6 @@ class Optimizer implements NStore { return getResults(); } - - count(_filters: DittoFilter[]): Promise { - return Promise.reject(new Error('COUNT not implemented.')); - } - - remove(_filters: DittoFilter[]): Promise { - return Promise.reject(new Error('DELETE not implemented.')); - } } export { Optimizer }; diff --git a/src/storages/pool-store.ts b/src/storages/pool-store.ts index 2fe9e56..c98cdab 100644 --- a/src/storages/pool-store.ts +++ b/src/storages/pool-store.ts @@ -92,14 +92,6 @@ class PoolStore implements NStore { opts.signal?.addEventListener('abort', onAbort); }); } - - count() { - return Promise.reject(new Error('COUNT not implemented')); - } - - remove() { - return Promise.reject(new Error('Cannot delete events from relays. Create a kind 5 event instead.')); - } } export { PoolStore }; diff --git a/src/storages/reqmeister.ts b/src/storages/reqmeister.ts index f43de71..d696654 100644 --- a/src/storages/reqmeister.ts +++ b/src/storages/reqmeister.ts @@ -133,14 +133,6 @@ class Reqmeister extends EventEmitter<{ [filterId: string]: (event: NostrEvent) return Promise.all(promises); } - - count(_filters: NostrFilter[]): Promise { - return Promise.reject(new Error('COUNT not implemented.')); - } - - remove(_filters: NostrFilter[]): Promise { - return Promise.reject(new Error('DELETE not implemented.')); - } } export { Reqmeister }; diff --git a/src/storages/search-store.ts b/src/storages/search-store.ts index 639b8f0..6e348d0 100644 --- a/src/storages/search-store.ts +++ b/src/storages/search-store.ts @@ -1,6 +1,6 @@ import { NiceRelay } from 'https://gitlab.com/soapbox-pub/nostr-machina/-/raw/5f4fb59c90c092e5aa59c01e6556a4bec264c167/mod.ts'; -import { Debug, type NostrEvent, type NostrFilter, NSet, type NStore, type NStoreOpts } from '@/deps.ts'; +import { Debug, type NostrEvent, NSet, type NStore, type NStoreOpts } from '@/deps.ts'; import { normalizeFilters } from '@/filter.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; import { type DittoFilter } from '@/interfaces/DittoFilter.ts'; @@ -68,14 +68,6 @@ class SearchStore implements NStore { return this.#fallback.query(filters, opts); } } - - count(_filters: NostrFilter[]): Promise { - return Promise.reject(new Error('COUNT not implemented.')); - } - - remove(_filters: NostrFilter[]): Promise { - return Promise.reject(new Error('DELETE not implemented.')); - } } export { SearchStore }; diff --git a/src/utils/SimpleLRU.ts b/src/utils/SimpleLRU.ts index c8af347..26f51fc 100644 --- a/src/utils/SimpleLRU.ts +++ b/src/utils/SimpleLRU.ts @@ -1,6 +1,6 @@ // deno-lint-ignore-file ban-types -import { LRUCache, type MapCache } from '@/deps.ts'; +import { LRUCache } from '@/deps.ts'; type FetchFn = (key: K, opts: O) => Promise; @@ -12,7 +12,7 @@ export class SimpleLRU< K extends {}, V extends {}, O extends {} = FetchFnOpts, -> implements MapCache { +> { protected cache: LRUCache; constructor(fetchFn: FetchFn, opts: LRUCache.Options) {