mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2025-12-08 16:28:49 +00:00
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
This commit is contained in:
@@ -108,13 +108,7 @@ let event = {
|
|||||||
event.id = getEventHash(event)
|
event.id = getEventHash(event)
|
||||||
event.sig = getSignature(event, sk)
|
event.sig = getSignature(event, sk)
|
||||||
|
|
||||||
let pub = relay.publish(event)
|
await 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}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
let events = await relay.list([{kinds: [0, 1]}])
|
let events = await relay.list([{kinds: [0, 1]}])
|
||||||
let event = await relay.get({
|
let event = await relay.get({
|
||||||
|
|||||||
16
nip42.ts
16
nip42.ts
@@ -17,7 +17,9 @@ export const authenticate = async ({
|
|||||||
}: {
|
}: {
|
||||||
challenge: string
|
challenge: string
|
||||||
relay: Relay
|
relay: Relay
|
||||||
sign: <K extends number = number>(e: EventTemplate<K>) => Promise<Event<K>> | Event<K>
|
sign: <K extends number = number>(
|
||||||
|
e: EventTemplate<K>
|
||||||
|
) => Promise<Event<K>> | Event<K>
|
||||||
}): Promise<void> => {
|
}): Promise<void> => {
|
||||||
const e: EventTemplate = {
|
const e: EventTemplate = {
|
||||||
kind: Kind.ClientAuth,
|
kind: Kind.ClientAuth,
|
||||||
@@ -28,15 +30,5 @@ export const authenticate = async ({
|
|||||||
],
|
],
|
||||||
content: ''
|
content: ''
|
||||||
}
|
}
|
||||||
const pub = relay.auth(await sign(e))
|
return 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)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
59
pool.ts
59
pool.ts
@@ -1,9 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
relayInit,
|
relayInit,
|
||||||
type Pub,
|
|
||||||
type Relay,
|
type Relay,
|
||||||
type Sub,
|
type Sub,
|
||||||
type SubscriptionOptions,
|
type SubscriptionOptions
|
||||||
} from './relay.ts'
|
} from './relay.ts'
|
||||||
import {normalizeURL} from './utils.ts'
|
import {normalizeURL} from './utils.ts'
|
||||||
|
|
||||||
@@ -17,7 +16,13 @@ export class SimplePool {
|
|||||||
private getTimeout: number
|
private getTimeout: number
|
||||||
private seenOnEnabled: boolean = true
|
private seenOnEnabled: boolean = true
|
||||||
|
|
||||||
constructor(options: {eoseSubTimeout?: number; getTimeout?: number; seenOnEnabled?: boolean} = {}) {
|
constructor(
|
||||||
|
options: {
|
||||||
|
eoseSubTimeout?: number
|
||||||
|
getTimeout?: number
|
||||||
|
seenOnEnabled?: boolean
|
||||||
|
} = {}
|
||||||
|
) {
|
||||||
this._conn = {}
|
this._conn = {}
|
||||||
this.eoseSubTimeout = options.eoseSubTimeout || 3400
|
this.eoseSubTimeout = options.eoseSubTimeout || 3400
|
||||||
this.getTimeout = options.getTimeout || 3400
|
this.getTimeout = options.getTimeout || 3400
|
||||||
@@ -46,7 +51,11 @@ export class SimplePool {
|
|||||||
return relay
|
return relay
|
||||||
}
|
}
|
||||||
|
|
||||||
sub<K extends number = number>(relays: string[], filters: Filter<K>[], opts?: SubscriptionOptions): Sub<K> {
|
sub<K extends number = number>(
|
||||||
|
relays: string[],
|
||||||
|
filters: Filter<K>[],
|
||||||
|
opts?: SubscriptionOptions
|
||||||
|
): Sub<K> {
|
||||||
let _knownIds: Set<string> = new Set()
|
let _knownIds: Set<string> = new Set()
|
||||||
let modifiedOpts = {...(opts || {})}
|
let modifiedOpts = {...(opts || {})}
|
||||||
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
modifiedOpts.alreadyHaveEvent = (id, url) => {
|
||||||
@@ -82,7 +91,7 @@ export class SimplePool {
|
|||||||
}
|
}
|
||||||
if (!r) return
|
if (!r) return
|
||||||
let s = r.sub(filters, modifiedOpts)
|
let s = r.sub(filters, modifiedOpts)
|
||||||
s.on('event', (event) => {
|
s.on('event', event => {
|
||||||
_knownIds.add(event.id as string)
|
_knownIds.add(event.id as string)
|
||||||
for (let cb of eventListeners.values()) cb(event)
|
for (let cb of eventListeners.values()) cb(event)
|
||||||
})
|
})
|
||||||
@@ -138,7 +147,7 @@ export class SimplePool {
|
|||||||
sub.unsub()
|
sub.unsub()
|
||||||
resolve(null)
|
resolve(null)
|
||||||
}, this.getTimeout)
|
}, this.getTimeout)
|
||||||
sub.on('event', (event) => {
|
sub.on('event', event => {
|
||||||
resolve(event)
|
resolve(event)
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
sub.unsub()
|
sub.unsub()
|
||||||
@@ -155,7 +164,7 @@ export class SimplePool {
|
|||||||
let events: Event<K>[] = []
|
let events: Event<K>[] = []
|
||||||
let sub = this.sub(relays, filters, opts)
|
let sub = this.sub(relays, filters, opts)
|
||||||
|
|
||||||
sub.on('event', (event) => {
|
sub.on('event', event => {
|
||||||
events.push(event)
|
events.push(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -167,39 +176,11 @@ export class SimplePool {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
publish(relays: string[], event: Event<number>): Pub {
|
publish(relays: string[], event: Event<number>): Promise<void>[] {
|
||||||
const pubPromises: Promise<Pub>[] = relays.map(async relay => {
|
return relays.map(async relay => {
|
||||||
let r
|
let r = await this.ensureRelay(relay)
|
||||||
try {
|
return r.publish(event)
|
||||||
r = await this.ensureRelay(relay)
|
|
||||||
return r.publish(event)
|
|
||||||
} catch (_) {
|
|
||||||
return {on() {}, off() {}}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
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[] {
|
seenOn(id: string): string[] {
|
||||||
|
|||||||
82
relay.ts
82
relay.ts
@@ -3,7 +3,7 @@
|
|||||||
import {verifySignature, validateEvent, type Event} from './event.ts'
|
import {verifySignature, validateEvent, type Event} from './event.ts'
|
||||||
import {matchFilters, type Filter} from './filter.ts'
|
import {matchFilters, type Filter} from './filter.ts'
|
||||||
import {getHex64, getSubscriptionId} from './fakejson.ts'
|
import {getHex64, getSubscriptionId} from './fakejson.ts'
|
||||||
import { MessageQueue } from './utils.ts'
|
import {MessageQueue} from './utils.ts'
|
||||||
|
|
||||||
type RelayEvent = {
|
type RelayEvent = {
|
||||||
connect: () => void | Promise<void>
|
connect: () => void | Promise<void>
|
||||||
@@ -25,15 +25,24 @@ export type Relay = {
|
|||||||
status: number
|
status: number
|
||||||
connect: () => Promise<void>
|
connect: () => Promise<void>
|
||||||
close: () => void
|
close: () => void
|
||||||
sub: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Sub<K>
|
sub: <K extends number = number>(
|
||||||
list: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Promise<Event<K>[]>
|
filters: Filter<K>[],
|
||||||
get: <K extends number = number>(filter: Filter<K>, opts?: SubscriptionOptions) => Promise<Event<K> | null>
|
opts?: SubscriptionOptions
|
||||||
|
) => Sub<K>
|
||||||
|
list: <K extends number = number>(
|
||||||
|
filters: Filter<K>[],
|
||||||
|
opts?: SubscriptionOptions
|
||||||
|
) => Promise<Event<K>[]>
|
||||||
|
get: <K extends number = number>(
|
||||||
|
filter: Filter<K>,
|
||||||
|
opts?: SubscriptionOptions
|
||||||
|
) => Promise<Event<K> | null>
|
||||||
count: (
|
count: (
|
||||||
filters: Filter[],
|
filters: Filter[],
|
||||||
opts?: SubscriptionOptions
|
opts?: SubscriptionOptions
|
||||||
) => Promise<CountPayload | null>
|
) => Promise<CountPayload | null>
|
||||||
publish: (event: Event<number>) => Pub
|
publish: (event: Event<number>) => Promise<void>
|
||||||
auth: (event: Event<number>) => Pub
|
auth: (event: Event<number>) => Promise<void>
|
||||||
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(
|
off: <T extends keyof RelayEvent, U extends RelayEvent[T]>(
|
||||||
event: T,
|
event: T,
|
||||||
listener: U
|
listener: U
|
||||||
@@ -43,12 +52,11 @@ export type Relay = {
|
|||||||
listener: U
|
listener: U
|
||||||
) => void
|
) => void
|
||||||
}
|
}
|
||||||
export type Pub = {
|
|
||||||
on: (type: 'ok' | 'failed', cb: any) => void
|
|
||||||
off: (type: 'ok' | 'failed', cb: any) => void
|
|
||||||
}
|
|
||||||
export type Sub<K extends number = number> = {
|
export type Sub<K extends number = number> = {
|
||||||
sub: <K extends number = number>(filters: Filter<K>[], opts: SubscriptionOptions) => Sub<K>
|
sub: <K extends number = number>(
|
||||||
|
filters: Filter<K>[],
|
||||||
|
opts: SubscriptionOptions
|
||||||
|
) => Sub<K>
|
||||||
unsub: () => void
|
unsub: () => void
|
||||||
on: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(
|
on: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(
|
||||||
event: T,
|
event: T,
|
||||||
@@ -93,9 +101,8 @@ export function relayInit(
|
|||||||
} = {}
|
} = {}
|
||||||
var pubListeners: {
|
var pubListeners: {
|
||||||
[eventid: string]: {
|
[eventid: string]: {
|
||||||
ok: Array<() => void>
|
resolve: (_: unknown) => void
|
||||||
seen: Array<() => void>
|
reject: (err: Error) => void
|
||||||
failed: Array<(reason: string) => void>
|
|
||||||
}
|
}
|
||||||
} = {}
|
} = {}
|
||||||
|
|
||||||
@@ -196,10 +203,9 @@ export function relayInit(
|
|||||||
let ok: boolean = data[2]
|
let ok: boolean = data[2]
|
||||||
let reason: string = data[3] || ''
|
let reason: string = data[3] || ''
|
||||||
if (id in pubListeners) {
|
if (id in pubListeners) {
|
||||||
if (ok) pubListeners[id].ok.forEach(cb => cb())
|
let {resolve, reject} = pubListeners[id]
|
||||||
else pubListeners[id].failed.forEach(cb => cb(reason))
|
if (ok) resolve(null)
|
||||||
pubListeners[id].ok = [] // 'ok' only happens once per pub, so stop listeners here
|
else reject(new Error(reason))
|
||||||
pubListeners[id].failed = []
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -294,26 +300,16 @@ export function relayInit(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _publishEvent(event: Event<number>, type: string) {
|
function _publishEvent(event: Event<number>, type: string) {
|
||||||
if (!event.id) throw new Error(`event ${event} has no id`)
|
return new Promise((resolve, reject) => {
|
||||||
let id = event.id
|
if (!event.id) {
|
||||||
|
reject(new Error(`event ${event} has no id`))
|
||||||
trySend([type, event])
|
return
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
let id = event.id
|
||||||
|
trySend([type, event])
|
||||||
|
pubListeners[id] = {resolve, reject}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -349,7 +345,7 @@ export function relayInit(
|
|||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve(events)
|
resolve(events)
|
||||||
})
|
})
|
||||||
s.on('event', (event) => {
|
s.on('event', event => {
|
||||||
events.push(event)
|
events.push(event)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
@@ -360,7 +356,7 @@ export function relayInit(
|
|||||||
s.unsub()
|
s.unsub()
|
||||||
resolve(null)
|
resolve(null)
|
||||||
}, getTimeout)
|
}, getTimeout)
|
||||||
s.on('event', (event) => {
|
s.on('event', event => {
|
||||||
s.unsub()
|
s.unsub()
|
||||||
clearTimeout(timeout)
|
clearTimeout(timeout)
|
||||||
resolve(event)
|
resolve(event)
|
||||||
@@ -379,11 +375,11 @@ export function relayInit(
|
|||||||
resolve(event)
|
resolve(event)
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
publish(event): Pub {
|
async publish(event): Promise<void> {
|
||||||
return _publishEvent(event, 'EVENT')
|
await _publishEvent(event, 'EVENT')
|
||||||
},
|
},
|
||||||
auth(event): Pub {
|
async auth(event): Promise<void> {
|
||||||
return _publishEvent(event, 'AUTH')
|
await _publishEvent(event, 'AUTH')
|
||||||
},
|
},
|
||||||
connect,
|
connect,
|
||||||
close(): void {
|
close(): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user