From 9d690814ca487268eb83def3ea4022899b674d96 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Sun, 30 Jul 2023 12:19:11 -0300 Subject: [PATCH] turn .publish() into a normal async function returning a promise. this simplifies the code and makes the API more intuitive. we used to need the event emitter thing because we were subscribing to the same relay to check if the event had been published, but that is not necessary now that we assume an OK response will always come. closes https://github.com/nbd-wtf/nostr-tools/issues/262 --- README.md | 8 +----- nip42.ts | 16 +++-------- pool.ts | 59 ++++++++++++++------------------------- relay.ts | 82 ++++++++++++++++++++++++++----------------------------- 4 files changed, 64 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index b6996db..cb85fd4 100644 --- a/README.md +++ b/README.md @@ -108,13 +108,7 @@ let event = { event.id = getEventHash(event) event.sig = getSignature(event, sk) -let pub = relay.publish(event) -pub.on('ok', () => { - console.log(`${relay.url} has accepted our event`) -}) -pub.on('failed', reason => { - console.log(`failed to publish to ${relay.url}: ${reason}`) -}) +await relay.publish(event) let events = await relay.list([{kinds: [0, 1]}]) let event = await relay.get({ diff --git a/nip42.ts b/nip42.ts index 93c7cdc..369545b 100644 --- a/nip42.ts +++ b/nip42.ts @@ -17,7 +17,9 @@ export const authenticate = async ({ }: { challenge: string relay: Relay - sign: (e: EventTemplate) => Promise> | Event + sign: ( + e: EventTemplate + ) => Promise> | Event }): Promise => { const e: EventTemplate = { kind: Kind.ClientAuth, @@ -28,15 +30,5 @@ export const authenticate = async ({ ], content: '' } - const pub = relay.auth(await sign(e)) - return new Promise((resolve, reject) => { - pub.on('ok', function ok() { - pub.off('ok', ok) - resolve() - }) - pub.on('failed', function fail(reason: string) { - pub.off('failed', fail) - reject(reason) - }) - }) + return relay.auth(await sign(e)) } diff --git a/pool.ts b/pool.ts index f13d1ac..b881c36 100644 --- a/pool.ts +++ b/pool.ts @@ -1,9 +1,8 @@ import { relayInit, - type Pub, type Relay, type Sub, - type SubscriptionOptions, + type SubscriptionOptions } from './relay.ts' import {normalizeURL} from './utils.ts' @@ -17,7 +16,13 @@ export class SimplePool { private getTimeout: number private seenOnEnabled: boolean = true - constructor(options: {eoseSubTimeout?: number; getTimeout?: number; seenOnEnabled?: boolean} = {}) { + constructor( + options: { + eoseSubTimeout?: number + getTimeout?: number + seenOnEnabled?: boolean + } = {} + ) { this._conn = {} this.eoseSubTimeout = options.eoseSubTimeout || 3400 this.getTimeout = options.getTimeout || 3400 @@ -46,7 +51,11 @@ export class SimplePool { return relay } - sub(relays: string[], filters: Filter[], opts?: SubscriptionOptions): Sub { + sub( + relays: string[], + filters: Filter[], + opts?: SubscriptionOptions + ): Sub { let _knownIds: Set = new Set() let modifiedOpts = {...(opts || {})} modifiedOpts.alreadyHaveEvent = (id, url) => { @@ -82,7 +91,7 @@ export class SimplePool { } if (!r) return let s = r.sub(filters, modifiedOpts) - s.on('event', (event) => { + s.on('event', event => { _knownIds.add(event.id as string) for (let cb of eventListeners.values()) cb(event) }) @@ -138,7 +147,7 @@ export class SimplePool { sub.unsub() resolve(null) }, this.getTimeout) - sub.on('event', (event) => { + sub.on('event', event => { resolve(event) clearTimeout(timeout) sub.unsub() @@ -155,7 +164,7 @@ export class SimplePool { let events: Event[] = [] let sub = this.sub(relays, filters, opts) - sub.on('event', (event) => { + sub.on('event', event => { events.push(event) }) @@ -167,39 +176,11 @@ export class SimplePool { }) } - publish(relays: string[], event: Event): Pub { - const pubPromises: Promise[] = relays.map(async relay => { - let r - try { - r = await this.ensureRelay(relay) - return r.publish(event) - } catch (_) { - return {on() {}, off() {}} - } + publish(relays: string[], event: Event): Promise[] { + return relays.map(async relay => { + let r = await this.ensureRelay(relay) + return r.publish(event) }) - - const callbackMap = new Map() - - return { - on(type, cb) { - relays.forEach(async (relay, i) => { - let pub = await pubPromises[i] - let callback = () => cb(relay) - callbackMap.set(cb, callback) - pub.on(type, callback) - }) - }, - - off(type, cb) { - relays.forEach(async (_, i) => { - let callback = callbackMap.get(cb) - if (callback) { - let pub = await pubPromises[i] - pub.off(type, callback) - } - }) - } - } } seenOn(id: string): string[] { diff --git a/relay.ts b/relay.ts index cd7b39e..63e7e59 100644 --- a/relay.ts +++ b/relay.ts @@ -3,7 +3,7 @@ import {verifySignature, validateEvent, type Event} from './event.ts' import {matchFilters, type Filter} from './filter.ts' import {getHex64, getSubscriptionId} from './fakejson.ts' -import { MessageQueue } from './utils.ts' +import {MessageQueue} from './utils.ts' type RelayEvent = { connect: () => void | Promise @@ -25,15 +25,24 @@ export type Relay = { status: number connect: () => Promise close: () => void - sub: (filters: Filter[], opts?: SubscriptionOptions) => Sub - list: (filters: Filter[], opts?: SubscriptionOptions) => Promise[]> - get: (filter: Filter, opts?: SubscriptionOptions) => Promise | null> + sub: ( + filters: Filter[], + opts?: SubscriptionOptions + ) => Sub + list: ( + filters: Filter[], + opts?: SubscriptionOptions + ) => Promise[]> + get: ( + filter: Filter, + opts?: SubscriptionOptions + ) => Promise | null> count: ( filters: Filter[], opts?: SubscriptionOptions ) => Promise - publish: (event: Event) => Pub - auth: (event: Event) => Pub + publish: (event: Event) => Promise + auth: (event: Event) => Promise off: ( event: T, listener: U @@ -43,12 +52,11 @@ export type Relay = { listener: U ) => void } -export type Pub = { - on: (type: 'ok' | 'failed', cb: any) => void - off: (type: 'ok' | 'failed', cb: any) => void -} export type Sub = { - sub: (filters: Filter[], opts: SubscriptionOptions) => Sub + sub: ( + filters: Filter[], + opts: SubscriptionOptions + ) => Sub unsub: () => void on: , U extends SubEvent[T]>( event: T, @@ -93,9 +101,8 @@ export function relayInit( } = {} var pubListeners: { [eventid: string]: { - ok: Array<() => void> - seen: Array<() => void> - failed: Array<(reason: string) => void> + resolve: (_: unknown) => void + reject: (err: Error) => void } } = {} @@ -196,10 +203,9 @@ export function relayInit( let ok: boolean = data[2] let reason: string = data[3] || '' if (id in pubListeners) { - if (ok) pubListeners[id].ok.forEach(cb => cb()) - else pubListeners[id].failed.forEach(cb => cb(reason)) - pubListeners[id].ok = [] // 'ok' only happens once per pub, so stop listeners here - pubListeners[id].failed = [] + let {resolve, reject} = pubListeners[id] + if (ok) resolve(null) + else reject(new Error(reason)) } return } @@ -294,26 +300,16 @@ export function relayInit( } function _publishEvent(event: Event, type: string) { - if (!event.id) throw new Error(`event ${event} has no id`) - let id = event.id - - trySend([type, event]) - - return { - on: (type: 'ok' | 'failed', cb: any) => { - pubListeners[id] = pubListeners[id] || { - ok: [], - failed: [] - } - pubListeners[id][type].push(cb) - }, - off: (type: 'ok' | 'failed', cb: any) => { - let listeners = pubListeners[id] - if (!listeners) return - let idx = listeners[type].indexOf(cb) - if (idx >= 0) listeners[type].splice(idx, 1) + return new Promise((resolve, reject) => { + if (!event.id) { + reject(new Error(`event ${event} has no id`)) + return } - } + + let id = event.id + trySend([type, event]) + pubListeners[id] = {resolve, reject} + }) } return { @@ -349,7 +345,7 @@ export function relayInit( clearTimeout(timeout) resolve(events) }) - s.on('event', (event) => { + s.on('event', event => { events.push(event) }) }), @@ -360,7 +356,7 @@ export function relayInit( s.unsub() resolve(null) }, getTimeout) - s.on('event', (event) => { + s.on('event', event => { s.unsub() clearTimeout(timeout) resolve(event) @@ -379,11 +375,11 @@ export function relayInit( resolve(event) }) }), - publish(event): Pub { - return _publishEvent(event, 'EVENT') + async publish(event): Promise { + await _publishEvent(event, 'EVENT') }, - auth(event): Pub { - return _publishEvent(event, 'AUTH') + async auth(event): Promise { + await _publishEvent(event, 'AUTH') }, connect, close(): void {