Files
welshman/packages/network/Executor.ts
T
2024-03-25 14:22:33 -07:00

80 lines
2.4 KiB
TypeScript

import type {Event, Filter} from 'nostr-tools'
import type {Emitter} from '@coracle.social/lib'
import type {Connection} from './Connection'
import type {Message} from './Socket'
export type Target = Emitter & {
connections: Connection[]
send: (...args: Message) => void
cleanup: () => void
}
type EventCallback = (url: string, event: Event) => void
type EoseCallback = (url: string) => void
type AuthCallback = (url: string, challenge: string) => void
type OkCallback = (url: string, id: string, ...extra: any[]) => void
type ErrorCallback = (url: string, id: string, ...extra: any[]) => void
type SubscribeOpts = {onEvent?: EventCallback, onEose?: EoseCallback}
type PublishOpts = {verb?: string, onOk?: OkCallback, onError?: ErrorCallback}
type AuthOpts = {onAuth: AuthCallback, onOk: OkCallback}
const createSubId = (prefix: string) => [prefix, Math.random().toString().slice(2, 10)].join('-')
export class Executor {
constructor(readonly target: Target) {}
subscribe(filters: Filter[], {onEvent, onEose}: SubscribeOpts = {}) {
let closed = false
const id = createSubId('REQ')
const eventListener = (url: string, subid: string, e: Event) => subid === id && onEvent?.(url, e)
const eoseListener = (url: string, subid: string) => subid === id && onEose?.(url)
this.target.on('EVENT', eventListener)
this.target.on('EOSE', eoseListener)
this.target.send("REQ", id, ...filters)
return {
unsubscribe: () => {
if (!closed) {
this.target.send("CLOSE", id)
this.target.off('EVENT', eventListener)
this.target.off('EOSE', eoseListener)
}
closed = true
},
}
}
publish(event: Event, {verb = 'EVENT', onOk, onError}: PublishOpts = {}) {
const okListener = (url: string, id: string, ...payload: any[]) => id === event.id && onOk?.(url, id, ...payload)
const errorListener = (url: string, id: string, ...payload: any[]) => id === event.id && onError?.(url, id, ...payload)
this.target.on('OK', okListener)
this.target.on('ERROR', errorListener)
this.target.send(verb, event)
return {
unsubscribe: () => {
this.target.off('OK', okListener)
this.target.off('ERROR', errorListener)
}
}
}
handleAuth({onAuth, onOk}: AuthOpts) {
this.target.on('AUTH', onAuth)
this.target.on('OK', onOk)
return {
unsubscribe: () => {
this.target.off('AUTH', onAuth)
this.target.off('OK', onOk)
}
}
}
}