Infer relay event types from filter

This commit is contained in:
Alex Gleason
2023-05-06 18:31:47 -05:00
committed by fiatjaf_
parent 1cbb62e6b9
commit d0bd599ce8
2 changed files with 36 additions and 42 deletions

26
pool.ts
View File

@@ -2,7 +2,7 @@ import {Relay, relayInit} from './relay'
import {normalizeURL} from './utils' import {normalizeURL} from './utils'
import {Filter} from './filter' import {Filter} from './filter'
import {Event} from './event' import {Event} from './event'
import {SubscriptionOptions, Sub, Pub, CountPayload} from './relay' import {SubscriptionOptions, Sub, Pub} from './relay'
export class SimplePool { export class SimplePool {
private _conn: {[url: string]: Relay} private _conn: {[url: string]: Relay}
@@ -39,7 +39,7 @@ export class SimplePool {
return relay return relay
} }
sub(relays: string[], filters: Filter[], opts?: SubscriptionOptions): Sub { 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) => {
@@ -73,7 +73,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: 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)
}) })
@@ -118,18 +118,18 @@ export class SimplePool {
return greaterSub return greaterSub
} }
get( get<K extends number = number>(
relays: string[], relays: string[],
filter: Filter, filter: Filter<K>,
opts?: SubscriptionOptions opts?: SubscriptionOptions
): Promise<Event | null> { ): Promise<Event<K> | null> {
return new Promise(resolve => { return new Promise(resolve => {
let sub = this.sub(relays, [filter], opts) let sub = this.sub(relays, [filter], opts)
let timeout = setTimeout(() => { let timeout = setTimeout(() => {
sub.unsub() sub.unsub()
resolve(null) resolve(null)
}, this.getTimeout) }, this.getTimeout)
sub.on('event', (event: Event) => { sub.on('event', (event) => {
resolve(event) resolve(event)
clearTimeout(timeout) clearTimeout(timeout)
sub.unsub() sub.unsub()
@@ -137,16 +137,16 @@ export class SimplePool {
}) })
} }
list( list<K extends number = number>(
relays: string[], relays: string[],
filters: Filter[], filters: Filter<K>[],
opts?: SubscriptionOptions opts?: SubscriptionOptions
): Promise<Event[]> { ): Promise<Event<K>[]> {
return new Promise(resolve => { return new Promise(resolve => {
let events: Event[] = [] let events: Event<K>[] = []
let sub = this.sub(relays, filters, opts) let sub = this.sub(relays, filters, opts)
sub.on('event', (event: Event) => { sub.on('event', (event) => {
events.push(event) events.push(event)
}) })
@@ -158,7 +158,7 @@ export class SimplePool {
}) })
} }
publish(relays: string[], event: Event): Pub { publish(relays: string[], event: Event<number>): Pub {
const pubPromises: Promise<Pub>[] = relays.map(async relay => { const pubPromises: Promise<Pub>[] = relays.map(async relay => {
let r let r
try { try {

View File

@@ -14,8 +14,8 @@ type RelayEvent = {
export type CountPayload = { export type CountPayload = {
count: number count: number
} }
type SubEvent = { type SubEvent<K extends number> = {
event: (event: Event) => void | Promise<void> event: (event: Event<K>) => void | Promise<void>
count: (payload: CountPayload) => void | Promise<void> count: (payload: CountPayload) => void | Promise<void>
eose: () => void | Promise<void> eose: () => void | Promise<void>
} }
@@ -24,15 +24,15 @@ export type Relay = {
status: number status: number
connect: () => Promise<void> connect: () => Promise<void>
close: () => void close: () => void
sub: (filters: Filter[], opts?: SubscriptionOptions) => Sub sub: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Sub<K>
list: (filters: Filter[], opts?: SubscriptionOptions) => Promise<Event[]> list: <K extends number = number>(filters: Filter<K>[], opts?: SubscriptionOptions) => Promise<Event<K>[]>
get: (filter: Filter, opts?: SubscriptionOptions) => Promise<Event | null> 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) => Pub publish: (event: Event<number>) => Pub
auth: (event: Event) => Pub auth: (event: Event<number>) => Pub
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
@@ -46,14 +46,14 @@ export type Pub = {
on: (type: 'ok' | 'failed', cb: any) => void on: (type: 'ok' | 'failed', cb: any) => void
off: (type: 'ok' | 'failed', cb: any) => void off: (type: 'ok' | 'failed', cb: any) => void
} }
export type Sub = { export type Sub<K extends number = number> = {
sub: (filters: Filter[], opts: SubscriptionOptions) => Sub sub: <K extends number = number>(filters: Filter<K>[], opts: SubscriptionOptions) => Sub<K>
unsub: () => void unsub: () => void
on: <T extends keyof SubEvent, U extends SubEvent[T]>( on: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(
event: T, event: T,
listener: U listener: U
) => void ) => void
off: <T extends keyof SubEvent, U extends SubEvent[T]>( off: <T extends keyof SubEvent<K>, U extends SubEvent<K>[T]>(
event: T, event: T,
listener: U listener: U
) => void ) => void
@@ -88,7 +88,7 @@ export function relayInit(
var openSubs: {[id: string]: {filters: Filter[]} & SubscriptionOptions} = {} var openSubs: {[id: string]: {filters: Filter[]} & SubscriptionOptions} = {}
var listeners = newListeners() var listeners = newListeners()
var subListeners: { var subListeners: {
[subid: string]: {[TK in keyof SubEvent]: SubEvent[TK][]} [subid: string]: {[TK in keyof SubEvent<any>]: SubEvent<any>[TK][]}
} = {} } = {}
var pubListeners: { var pubListeners: {
[eventid: string]: { [eventid: string]: {
@@ -245,15 +245,15 @@ export function relayInit(
} }
} }
const sub = ( const sub = <K extends number = number>(
filters: Filter[], filters: Filter<K>[],
{ {
verb = 'REQ', verb = 'REQ',
skipVerification = false, skipVerification = false,
alreadyHaveEvent = null, alreadyHaveEvent = null,
id = Math.random().toString().slice(2) id = Math.random().toString().slice(2)
}: SubscriptionOptions = {} }: SubscriptionOptions = {}
): Sub => { ): Sub<K> => {
let subid = id let subid = id
openSubs[subid] = { openSubs[subid] = {
@@ -276,10 +276,7 @@ export function relayInit(
delete subListeners[subid] delete subListeners[subid]
trySend(['CLOSE', subid]) trySend(['CLOSE', subid])
}, },
on: <T extends keyof SubEvent, U extends SubEvent[T]>( on: (type, cb) => {
type: T,
cb: U
): void => {
subListeners[subid] = subListeners[subid] || { subListeners[subid] = subListeners[subid] || {
event: [], event: [],
count: [], count: [],
@@ -287,10 +284,7 @@ export function relayInit(
} }
subListeners[subid][type].push(cb) subListeners[subid][type].push(cb)
}, },
off: <T extends keyof SubEvent, U extends SubEvent[T]>( off: (type, cb): void => {
type: T,
cb: U
): void => {
let listeners = subListeners[subid] let listeners = subListeners[subid]
let idx = listeners[type].indexOf(cb) let idx = listeners[type].indexOf(cb)
if (idx >= 0) listeners[type].splice(idx, 1) if (idx >= 0) listeners[type].splice(idx, 1)
@@ -298,7 +292,7 @@ export function relayInit(
} }
} }
function _publishEvent(event: Event, type: string) { function _publishEvent(event: Event<number>, type: string) {
if (!event.id) throw new Error(`event ${event} has no id`) if (!event.id) throw new Error(`event ${event} has no id`)
let id = event.id let id = event.id
@@ -341,10 +335,10 @@ export function relayInit(
let index = listeners[type].indexOf(cb) let index = listeners[type].indexOf(cb)
if (index !== -1) listeners[type].splice(index, 1) if (index !== -1) listeners[type].splice(index, 1)
}, },
list: (filters: Filter[], opts?: SubscriptionOptions): Promise<Event[]> => list: (filters, opts?: SubscriptionOptions) =>
new Promise(resolve => { new Promise(resolve => {
let s = sub(filters, opts) let s = sub(filters, opts)
let events: Event[] = [] let events: Event<any>[] = []
let timeout = setTimeout(() => { let timeout = setTimeout(() => {
s.unsub() s.unsub()
resolve(events) resolve(events)
@@ -354,18 +348,18 @@ export function relayInit(
clearTimeout(timeout) clearTimeout(timeout)
resolve(events) resolve(events)
}) })
s.on('event', (event: Event) => { s.on('event', (event) => {
events.push(event) events.push(event)
}) })
}), }),
get: (filter: Filter, opts?: SubscriptionOptions): Promise<Event | null> => get: (filter, opts?: SubscriptionOptions) =>
new Promise(resolve => { new Promise(resolve => {
let s = sub([filter], opts) let s = sub([filter], opts)
let timeout = setTimeout(() => { let timeout = setTimeout(() => {
s.unsub() s.unsub()
resolve(null) resolve(null)
}, getTimeout) }, getTimeout)
s.on('event', (event: Event) => { s.on('event', (event) => {
s.unsub() s.unsub()
clearTimeout(timeout) clearTimeout(timeout)
resolve(event) resolve(event)