Refactor dvm request and outbox loader

This commit is contained in:
Jon Staab
2025-04-11 09:21:55 -07:00
parent 837fd1ab66
commit 7e44fa414c
8 changed files with 42 additions and 55 deletions
+5 -9
View File
@@ -2,7 +2,7 @@ import {nthEq, partition, race, now} from "@welshman/lib"
import {createEvent, getPubkeyTagValues, TrustedEvent} from "@welshman/util" import {createEvent, getPubkeyTagValues, TrustedEvent} from "@welshman/util"
import {request, Tracker} from "@welshman/net" import {request, Tracker} from "@welshman/net"
import {Scope, FeedController, RequestOpts, FeedOptions, DVMOpts, Feed} from "@welshman/feeds" import {Scope, FeedController, RequestOpts, FeedOptions, DVMOpts, Feed} from "@welshman/feeds"
import {makeDvmRequest, DVMEvent} from "@welshman/dvm" import {makeDvmRequest} from "@welshman/dvm"
import {makeSecret, Nip01Signer} from "@welshman/signer" import {makeSecret, Nip01Signer} from "@welshman/signer"
import {pubkey, signer} from "./session.js" import {pubkey, signer} from "./session.js"
import {Router, addMinimalFallbacks, getFilterSelections} from "./router.js" import {Router, addMinimalFallbacks, getFilterSelections} from "./router.js"
@@ -91,14 +91,10 @@ export const requestDVM = async ({kind, onEvent, ...request}: DVMOpts) => {
tags.push(["param", "max_results", "200"]) tags.push(["param", "max_results", "200"])
} }
const event = await $signer.sign(createEvent(kind, {tags})) await makeDvmRequest({
const req = makeDvmRequest({event, relays}) relays,
event: await $signer.sign(createEvent(kind, {tags})),
await new Promise<void>(resolve => { onResult: onEvent,
req.emitter.on(DVMEvent.Result, (url, event) => {
onEvent(event)
resolve()
})
}) })
} }
+1 -1
View File
@@ -19,5 +19,5 @@ export const {
name: "follows", name: "follows",
store: follows, store: follows,
getKey: follows => follows.event.pubkey, getKey: follows => follows.event.pubkey,
load: makeOutboxLoader([FOLLOWS]) load: makeOutboxLoader(FOLLOWS)
}) })
+1 -1
View File
@@ -25,5 +25,5 @@ export const {
name: "mutes", name: "mutes",
store: mutes, store: mutes,
getKey: mute => mute.event.pubkey, getKey: mute => mute.event.pubkey,
load: makeOutboxLoader([MUTES]) load: makeOutboxLoader(MUTES)
}) })
+1 -1
View File
@@ -19,5 +19,5 @@ export const {
name: "pins", name: "pins",
store: pins, store: pins,
getKey: pins => pins.event.pubkey, getKey: pins => pins.event.pubkey,
load: makeOutboxLoader([PINS]) load: makeOutboxLoader(PINS)
}) })
+1 -1
View File
@@ -22,7 +22,7 @@ export const {
name: "profiles", name: "profiles",
store: profiles, store: profiles,
getKey: profile => profile.event.pubkey, getKey: profile => profile.event.pubkey,
load: makeOutboxLoader([PROFILE]), load: makeOutboxLoader(PROFILE),
}) })
export const displayProfileByPubkey = (pubkey: string | undefined) => export const displayProfileByPubkey = (pubkey: string | undefined) =>
+20 -18
View File
@@ -37,28 +37,30 @@ export const getWriteRelayUrls = (list?: List): string[] =>
export type OutboxLoaderRequest = { export type OutboxLoaderRequest = {
pubkey: string pubkey: string
relays: string[] relays: string[]
kind: number
} }
export const makeOutboxLoader = (kinds: number[]) => { export const loadUsingOutbox = batcher(200, (requests: OutboxLoaderRequest[]) => {
const loadOutboxRequest = batcher(200, (requests: OutboxLoaderRequest[]) => { const router = Router.get()
const router = Router.get() const authors: string[] = []
const authors: string[] = [] const scenarios = [router.Index()]
const scenarios = [router.Index()] const kinds = new Set<number>()
for (const {pubkey, relays} of requests) { for (const {pubkey, relays, kind} of requests) {
authors.push(pubkey) kinds.add(kind)
scenarios.push(router.FromPubkey(pubkey), router.FromRelays(relays)) authors.push(pubkey)
} scenarios.push(router.FromPubkey(pubkey), router.FromRelays(relays))
}
const filters = [{authors, kinds}] const relays = router.merge(scenarios).getUrls()
const relays = router.merge(scenarios).getUrls() const filters = [{authors, kinds: Array.from(kinds)}]
const promise = request({filters, relays, autoClose: true}) const promise = request({filters, relays, autoClose: true})
return requests.map(always(promise)) return requests.map(always(promise))
}) })
return (pubkey: string, relays: string[]) => loadOutboxRequest({pubkey, relays}) export const makeOutboxLoader = (kind: number) =>
} (pubkey: string, relays: string[]) => loadUsingOutbox({pubkey, relays, kind})
export const relaySelections = deriveEventsMapped<PublishedList>(repository, { export const relaySelections = deriveEventsMapped<PublishedList>(repository, {
filters: [{kinds: [RELAYS]}], filters: [{kinds: [RELAYS]}],
@@ -74,7 +76,7 @@ export const {
name: "relaySelections", name: "relaySelections",
store: relaySelections, store: relaySelections,
getKey: relaySelections => relaySelections.event.pubkey, getKey: relaySelections => relaySelections.event.pubkey,
load: makeOutboxLoader([RELAYS]), load: makeOutboxLoader(RELAYS),
}) })
export const inboxRelaySelections = deriveEventsMapped<PublishedList>(repository, { export const inboxRelaySelections = deriveEventsMapped<PublishedList>(repository, {
@@ -91,5 +93,5 @@ export const {
name: "inboxRelaySelections", name: "inboxRelaySelections",
store: inboxRelaySelections, store: inboxRelaySelections,
getKey: inboxRelaySelections => inboxRelaySelections.event.pubkey, getKey: inboxRelaySelections => inboxRelaySelections.event.pubkey,
load: makeOutboxLoader([INBOX_RELAYS]), load: makeOutboxLoader(INBOX_RELAYS),
}) })
+12 -23
View File
@@ -2,51 +2,42 @@ import {Emitter, now} from "@welshman/lib"
import {TrustedEvent, SignedEvent, Filter} from "@welshman/util" import {TrustedEvent, SignedEvent, Filter} from "@welshman/util"
import {request, publish, AdapterContext} from "@welshman/net" import {request, publish, AdapterContext} from "@welshman/net"
export enum DVMEvent {
Progress = "progress",
Result = "result",
}
export type DVMRequestOptions = { export type DVMRequestOptions = {
event: SignedEvent event: SignedEvent
relays: string[] relays: string[]
timeout?: number timeout?: number
autoClose?: boolean autoClose?: boolean
reportProgress?: boolean
context?: AdapterContext context?: AdapterContext
onResult?: (event: TrustedEvent, url: string) => void
onProgress?: (event: TrustedEvent, url: string) => void
} }
export type DVMRequest = { export const requestDvmResponse = (options: DVMRequestOptions) => {
options: DVMRequestOptions
emitter: Emitter
}
export const makeDvmRequest = (options: DVMRequestOptions) => {
const emitter = new Emitter()
const { const {
event, event,
relays, relays,
context, context,
timeout = 30_000, timeout = 30_000,
autoClose = true, autoClose = true,
reportProgress = true, onResult,
onProgress,
} = options } = options
const kind = event.kind + 1000 const kind = event.kind + 1000
const kinds = reportProgress ? [kind, 7000] : [kind] const kinds = onProgress ? [kind, 7000] : [kind]
const filters: Filter[] = [{kinds, since: now() - 60, "#e": [event.id]}] const filters: Filter[] = [{kinds, since: now() - 60, "#e": [event.id]}]
const abortController = new AbortController() const abortController = new AbortController()
const signal = AbortSignal.any([abortController.signal, AbortSignal.timeout(timeout)]) const signal = AbortSignal.any([abortController.signal, AbortSignal.timeout(timeout)])
request({ return request({
signal, signal,
relays, relays,
filters, filters,
context, context,
onEvent: (event: TrustedEvent, url: string) => { onEvent: (event: TrustedEvent, url: string) => {
if (event.kind === 7000) { if (event.kind === 7000) {
emitter.emit(DVMEvent.Progress, url, event) onProgress?.(event, url)
} else { } else {
emitter.emit(DVMEvent.Result, url, event) onResult?.(event, url)
if (autoClose) { if (autoClose) {
abortController.abort() abortController.abort()
@@ -54,9 +45,7 @@ export const makeDvmRequest = (options: DVMRequestOptions) => {
} }
}, },
}) })
publish({relays, event, timeout, context})
return {options, emitter} as DVMRequest
} }
export const makeDvmRequest = (options: DVMRequestOptions) =>
Promise.all([publish(options), requestDvmResponse(options)])
+1 -1
View File
@@ -297,7 +297,7 @@ export const makeLoader = (options: LoaderOptions) =>
} }
) )
return allRequests.map(r => resultsByRequest.get(r)) return allRequests.map(r => resultsByRequest.get(r)!)
}) })
export const load = makeLoader({delay: 200, timeout: 3000, threshold: 0.5}) export const load = makeLoader({delay: 200, timeout: 3000, threshold: 0.5})