From f56f2ae709a6e9fdc7751878c93e30d7f911ce05 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sun, 17 Dec 2023 22:19:28 -0300 Subject: [PATCH] pool tests and pool.ts tweaks. --- pool.test.ts | 98 ++++++++++++++++++---------------------------------- pool.ts | 71 +++++++++++++++++++++---------------- 2 files changed, 76 insertions(+), 93 deletions(-) diff --git a/pool.test.ts b/pool.test.ts index 176fb66..1e89462 100644 --- a/pool.test.ts +++ b/pool.test.ts @@ -6,31 +6,21 @@ import { SimplePool } from './pool.ts' let pool = new SimplePool() -let relays = [ - 'wss://relay.damus.io/', - 'wss://relay.nostr.bg/', - 'wss://nostr.fmt.wiz.biz/', - 'wss://relay.nostr.band/', - 'wss://nos.lol/', -] - -afterAll(() => { - pool.close([...relays, 'wss://nostr.wine', 'wss://offchain.pub', 'wss://eden.nostr.land']) -}) +let relays = ['wss://relay.damus.io/', 'wss://relay.nostr.bg/', 'wss://nos.lol', 'wss://public.relaying.io'] test('removing duplicates when querying', async () => { let priv = generatePrivateKey() let pub = getPublicKey(priv) - let sub = pool.sub(relays, [{ authors: [pub] }]) - let received: Event[] = [] - - sub.on('event', event => { - // this should be called only once even though we're listening - // to multiple relays because the events will be catched and - // deduplicated efficiently (without even being parsed) - received.push(event) + pool.subscribeMany(relays, [{ authors: [pub] }], { + onevent(event: Event) { + // this should be called only once even though we're listening + // to multiple relays because the events will be catched and + // deduplicated efficiently (without even being parsed) + received.push(event) + }, }) + let received: Event[] = [] let event = finishEvent( { @@ -42,30 +32,31 @@ test('removing duplicates when querying', async () => { priv, ) - pool.publish(relays, event) + await Promise.any(pool.publish(relays, event)) await new Promise(resolve => setTimeout(resolve, 1500)) expect(received).toHaveLength(1) + expect(received[0]).toEqual(event) }) test('same with double querying', async () => { let priv = generatePrivateKey() let pub = getPublicKey(priv) - let sub1 = pool.sub(relays, [{ authors: [pub] }]) - let sub2 = pool.sub(relays, [{ authors: [pub] }]) + pool.subscribeMany(relays, [{ authors: [pub] }], { + onevent(event) { + received.push(event) + }, + }) + pool.subscribeMany(relays, [{ authors: [pub] }], { + onevent(event) { + received.push(event) + }, + }) let received: Event[] = [] - sub1.on('event', event => { - received.push(event) - }) - - sub2.on('event', event => { - received.push(event) - }) - let event = finishEvent( { created_at: Math.round(Date.now() / 1000), @@ -76,51 +67,30 @@ test('same with double querying', async () => { priv, ) - pool.publish(relays, event) - + await Promise.any(pool.publish(relays, event)) await new Promise(resolve => setTimeout(resolve, 1500)) expect(received).toHaveLength(2) }) -test('get()', async () => { - let event = await pool.get(relays, { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], - }) - - expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') -}) - test('list()', async () => { - let events = await pool.list( - [...relays, 'wss://offchain.pub', 'wss://eden.nostr.land'], - [ - { - authors: ['3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'], - kinds: [1], - limit: 2, - }, - ], - ) + let events = await pool.querySync([...relays, 'wss://offchain.pub', 'wss://eden.nostr.land'], { + authors: ['3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d'], + kinds: [1], + limit: 2, + }) // the actual received number will be greater than 2, but there will be no duplicates + expect(events.length).toBeGreaterThan(2) const uniqueEventCount = new Set(events.map(evt => evt.id)).size - expect(events.length).toEqual(uniqueEventCount) - - let relaysForAllEvents = events.map(event => pool.seenOn(event.id)).reduce((acc, n) => acc.concat(n), []) - expect(relaysForAllEvents.length).toBeGreaterThanOrEqual(events.length) + expect(events).toHaveLength(uniqueEventCount) }) -test('seenOnEnabled: false', async () => { - const poolWithoutSeenOn = new SimplePool({ seenOnEnabled: false }) - - const event = await poolWithoutSeenOn.get(relays, { - ids: ['d7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027'], +test('get()', async () => { + let event = await pool.get(relays, { + ids: ['9fa1c618fcaad6357e074417b07ed132b083ed30e13113ebb10fcda7137442fe'], }) - expect(event).toHaveProperty('id', 'd7dd5eb3ab747e16f8d0212d53032ea2a7cadef53837e5a6c66d42849fcb9027') - - const relaysForEvent = poolWithoutSeenOn.seenOn(event!.id) - - expect(relaysForEvent).toHaveLength(0) + expect(event).not.toBeNull() + expect(event).toHaveProperty('id', '9fa1c618fcaad6357e074417b07ed132b083ed30e13113ebb10fcda7137442fe') }) diff --git a/pool.ts b/pool.ts index e37b6e5..9dd2628 100644 --- a/pool.ts +++ b/pool.ts @@ -4,9 +4,10 @@ import { normalizeURL } from './utils.ts' import type { Event } from './event.ts' import { type Filter } from './filter.ts' -export type SubscribeManyParams = Omit & { - eoseSubTimeout: number +export type SubscribeManyParams = Omit & { + eoseSubTimeout?: number onclose?: (reasons: string[]) => void + id?: string } export class SimplePool { @@ -43,15 +44,6 @@ export class SimplePool { } const _knownIds = new Set() - params.alreadyHaveEvent = (id: string) => { - if (params.alreadyHaveEvent?.(id)) { - return true - } - const have = _knownIds.has(id) - _knownIds.add(id) - return have - } - const subs: Subscription[] = [] // batch all EOSEs into a single @@ -78,12 +70,21 @@ export class SimplePool { } } + const localAlreadyHaveEventHandler = (id: string) => { + if (params.alreadyHaveEvent?.(id)) { + return true + } + const have = _knownIds.has(id) + _knownIds.add(id) + return have + } + // open a subscription in all given relays await Promise.all( - relays.map(normalizeURL).map(async (url, i) => { - if (relays.indexOf(url) !== i) { + relays.map(normalizeURL).map(async (url, i, arr) => { + if (arr.indexOf(url) !== i) { // duplicate - handleClose(i, 'duplicate') + handleClose(i, 'duplicate url') return } @@ -99,6 +100,7 @@ export class SimplePool { ...params, oneose: handleEose, onclose: reason => handleClose(i, reason), + alreadyHaveEvent: localAlreadyHaveEventHandler, }) subs.push(subscription) @@ -122,38 +124,49 @@ export class SimplePool { const sub = await this.subscribeMany(relays, filters, { ...params, oneose() { - sub.close() + setTimeout(() => { + sub.close() + }, 0) }, }) return sub } - get( + async querySync( relays: string[], filter: Filter, - params: Pick, - ): Promise { - return new Promise(async (resolve, reject) => { - const sub = await this.subscribeManyEose(relays, [filter], { + params?: Pick, + ): Promise { + return new Promise(async resolve => { + const events: Event[] = [] + await this.subscribeManyEose(relays, [filter], { ...params, onevent(event: Event) { - resolve(event) - sub.close() + events.push(event) }, - onclose(reasons: string[]) { - const err = new Error('subscriptions closed') - err.cause = reasons - reject(err) + onclose(_: string[]) { + resolve(events) }, }) }) } + async get( + relays: string[], + filter: Filter, + params?: Pick, + ): Promise { + filter.limit = 1 + const events = await this.querySync(relays, filter, params) + events.sort((a, b) => b.created_at - a.created_at) + return events[0] || null + } + publish(relays: string[], event: Event): Promise[] { - return relays.map(normalizeURL).map(async (url, i) => { - if (relays.indexOf(url) !== i) { + return relays.map(normalizeURL).map(async (url, i, arr) => { + if (arr.indexOf(url) !== i) { // duplicate - return Promise.reject('duplicate') + return Promise.reject('duplicate url') } let r = await this.ensureRelay(url)