mirror of
https://github.com/nbd-wtf/nostr-tools.git
synced 2026-01-25 03:38:52 +00:00
optionally take an AbortSignal on subscriptions.
This commit is contained in:
@@ -23,6 +23,7 @@ export type AbstractPoolConstructorOptions = AbstractRelayConstructorOptions & {
|
|||||||
|
|
||||||
export type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {
|
export type SubscribeManyParams = Omit<SubscriptionParams, 'onclose'> & {
|
||||||
maxWait?: number
|
maxWait?: number
|
||||||
|
abort?: AbortSignal
|
||||||
onclose?: (reasons: string[]) => void
|
onclose?: (reasons: string[]) => void
|
||||||
onauth?: (event: EventTemplate) => Promise<VerifiedEvent>
|
onauth?: (event: EventTemplate) => Promise<VerifiedEvent>
|
||||||
id?: string
|
id?: string
|
||||||
@@ -50,7 +51,13 @@ export class AbstractSimplePool {
|
|||||||
this.automaticallyAuth = opts.automaticallyAuth
|
this.automaticallyAuth = opts.automaticallyAuth
|
||||||
}
|
}
|
||||||
|
|
||||||
async ensureRelay(url: string, params?: { connectionTimeout?: number }): Promise<AbstractRelay> {
|
async ensureRelay(
|
||||||
|
url: string,
|
||||||
|
params?: {
|
||||||
|
connectionTimeout?: number
|
||||||
|
abort?: AbortSignal
|
||||||
|
},
|
||||||
|
): Promise<AbstractRelay> {
|
||||||
url = normalizeURL(url)
|
url = normalizeURL(url)
|
||||||
|
|
||||||
let relay = this.relays.get(url)
|
let relay = this.relays.get(url)
|
||||||
@@ -66,7 +73,6 @@ export class AbstractSimplePool {
|
|||||||
this.relays.delete(url)
|
this.relays.delete(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (params?.connectionTimeout) relay.connectionTimeout = params.connectionTimeout
|
|
||||||
this.relays.set(url, relay)
|
this.relays.set(url, relay)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +83,10 @@ export class AbstractSimplePool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await relay.connect()
|
await relay.connect({
|
||||||
|
timeout: params?.connectionTimeout,
|
||||||
|
abort: params?.abort,
|
||||||
|
})
|
||||||
|
|
||||||
return relay
|
return relay
|
||||||
}
|
}
|
||||||
@@ -176,6 +185,7 @@ export class AbstractSimplePool {
|
|||||||
try {
|
try {
|
||||||
relay = await this.ensureRelay(url, {
|
relay = await this.ensureRelay(url, {
|
||||||
connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,
|
connectionTimeout: params.maxWait ? Math.max(params.maxWait * 0.8, params.maxWait - 1000) : undefined,
|
||||||
|
abort: params.abort,
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleClose(i, (err as any)?.message || String(err))
|
handleClose(i, (err as any)?.message || String(err))
|
||||||
@@ -198,6 +208,7 @@ export class AbstractSimplePool {
|
|||||||
},
|
},
|
||||||
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
||||||
eoseTimeout: params.maxWait,
|
eoseTimeout: params.maxWait,
|
||||||
|
abort: params.abort,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -209,6 +220,7 @@ export class AbstractSimplePool {
|
|||||||
},
|
},
|
||||||
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
alreadyHaveEvent: localAlreadyHaveEventHandler,
|
||||||
eoseTimeout: params.maxWait,
|
eoseTimeout: params.maxWait,
|
||||||
|
abort: params.abort,
|
||||||
})
|
})
|
||||||
|
|
||||||
subs.push(subscription)
|
subs.push(subscription)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ export class AbstractRelay {
|
|||||||
public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)
|
public onauth: undefined | ((evt: EventTemplate) => Promise<VerifiedEvent>)
|
||||||
|
|
||||||
public baseEoseTimeout: number = 4400
|
public baseEoseTimeout: number = 4400
|
||||||
public connectionTimeout: number = 4400
|
|
||||||
public publishTimeout: number = 4400
|
public publishTimeout: number = 4400
|
||||||
public pingFrequency: number = 29000
|
public pingFrequency: number = 29000
|
||||||
public pingTimeout: number = 20000
|
public pingTimeout: number = 20000
|
||||||
@@ -43,7 +42,6 @@ export class AbstractRelay {
|
|||||||
public openSubs: Map<string, Subscription> = new Map()
|
public openSubs: Map<string, Subscription> = new Map()
|
||||||
public enablePing: boolean | undefined
|
public enablePing: boolean | undefined
|
||||||
public enableReconnect: boolean
|
public enableReconnect: boolean
|
||||||
private connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
|
||||||
private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
private reconnectTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||||
private pingIntervalHandle: ReturnType<typeof setInterval> | undefined
|
private pingIntervalHandle: ReturnType<typeof setInterval> | undefined
|
||||||
private reconnectAttempts: number = 0
|
private reconnectAttempts: number = 0
|
||||||
@@ -70,9 +68,12 @@ export class AbstractRelay {
|
|||||||
this.enableReconnect = opts.enableReconnect || false
|
this.enableReconnect = opts.enableReconnect || false
|
||||||
}
|
}
|
||||||
|
|
||||||
static async connect(url: string, opts: AbstractRelayConstructorOptions): Promise<AbstractRelay> {
|
static async connect(
|
||||||
|
url: string,
|
||||||
|
opts: AbstractRelayConstructorOptions & Parameters<AbstractRelay['connect']>[0],
|
||||||
|
): Promise<AbstractRelay> {
|
||||||
const relay = new AbstractRelay(url, opts)
|
const relay = new AbstractRelay(url, opts)
|
||||||
await relay.connect()
|
await relay.connect(opts)
|
||||||
return relay
|
return relay
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,23 +132,31 @@ export class AbstractRelay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async connect(): Promise<void> {
|
public async connect(opts?: { timeout?: number; abort?: AbortSignal }): Promise<void> {
|
||||||
|
let connectionTimeoutHandle: ReturnType<typeof setTimeout> | undefined
|
||||||
|
|
||||||
if (this.connectionPromise) return this.connectionPromise
|
if (this.connectionPromise) return this.connectionPromise
|
||||||
|
|
||||||
this.challenge = undefined
|
this.challenge = undefined
|
||||||
this.authPromise = undefined
|
this.authPromise = undefined
|
||||||
this.connectionPromise = new Promise((resolve, reject) => {
|
this.connectionPromise = new Promise((resolve, reject) => {
|
||||||
this.connectionTimeoutHandle = setTimeout(() => {
|
if (opts?.timeout) {
|
||||||
reject('connection timed out')
|
connectionTimeoutHandle = setTimeout(() => {
|
||||||
this.connectionPromise = undefined
|
reject('connection timed out')
|
||||||
this.onclose?.()
|
this.connectionPromise = undefined
|
||||||
this.closeAllSubscriptions('relay connection timed out')
|
this.onclose?.()
|
||||||
}, this.connectionTimeout)
|
this.closeAllSubscriptions('relay connection timed out')
|
||||||
|
}, opts.timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opts?.abort) {
|
||||||
|
opts.abort.onabort = reject
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
this.ws = new this._WebSocket(this.url)
|
this.ws = new this._WebSocket(this.url)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
clearTimeout(this.connectionTimeoutHandle)
|
clearTimeout(connectionTimeoutHandle)
|
||||||
reject(err)
|
reject(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -157,7 +166,7 @@ export class AbstractRelay {
|
|||||||
clearTimeout(this.reconnectTimeoutHandle)
|
clearTimeout(this.reconnectTimeoutHandle)
|
||||||
this.reconnectTimeoutHandle = undefined
|
this.reconnectTimeoutHandle = undefined
|
||||||
}
|
}
|
||||||
clearTimeout(this.connectionTimeoutHandle)
|
clearTimeout(connectionTimeoutHandle)
|
||||||
this._connected = true
|
this._connected = true
|
||||||
|
|
||||||
const isReconnection = this.reconnectAttempts > 0
|
const isReconnection = this.reconnectAttempts > 0
|
||||||
@@ -183,13 +192,13 @@ export class AbstractRelay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.ws.onerror = ev => {
|
this.ws.onerror = ev => {
|
||||||
clearTimeout(this.connectionTimeoutHandle)
|
clearTimeout(connectionTimeoutHandle)
|
||||||
reject((ev as any).message || 'websocket error')
|
reject((ev as any).message || 'websocket error')
|
||||||
this.handleHardClose('relay connection errored')
|
this.handleHardClose('relay connection errored')
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ws.onclose = ev => {
|
this.ws.onclose = ev => {
|
||||||
clearTimeout(this.connectionTimeoutHandle)
|
clearTimeout(connectionTimeoutHandle)
|
||||||
reject((ev as any).message || 'websocket closed')
|
reject((ev as any).message || 'websocket closed')
|
||||||
this.handleHardClose('relay connection closed')
|
this.handleHardClose('relay connection closed')
|
||||||
}
|
}
|
||||||
@@ -437,6 +446,11 @@ export class AbstractRelay {
|
|||||||
): Subscription {
|
): Subscription {
|
||||||
const sub = this.prepareSubscription(filters, params)
|
const sub = this.prepareSubscription(filters, params)
|
||||||
sub.fire()
|
sub.fire()
|
||||||
|
|
||||||
|
if (params.abort) {
|
||||||
|
params.abort.onabort = () => sub.close(String(params.abort!.reason || '<aborted>'))
|
||||||
|
}
|
||||||
|
|
||||||
return sub
|
return sub
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,6 +577,7 @@ export type SubscriptionParams = {
|
|||||||
alreadyHaveEvent?: (id: string) => boolean
|
alreadyHaveEvent?: (id: string) => boolean
|
||||||
receivedEvent?: (relay: AbstractRelay, id: string) => void
|
receivedEvent?: (relay: AbstractRelay, id: string) => void
|
||||||
eoseTimeout?: number
|
eoseTimeout?: number
|
||||||
|
abort?: AbortSignal
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CountResolver = {
|
export type CountResolver = {
|
||||||
|
|||||||
Reference in New Issue
Block a user