Rework outbox loader

This commit is contained in:
Jon Staab
2025-08-04 09:55:15 -07:00
parent c6434028a6
commit 2edbd44f64
4 changed files with 44 additions and 77 deletions
+16 -3
View File
@@ -11,6 +11,7 @@ export * from "./profiles.js"
export * from "./pins.js" export * from "./pins.js"
export * from "./relays.js" export * from "./relays.js"
export * from "./relaySelections.js" export * from "./relaySelections.js"
export * from "./inboxRelaySelections.js"
export * from "./search.js" export * from "./search.js"
export * from "./session.js" export * from "./session.js"
export * from "./storage.js" export * from "./storage.js"
@@ -23,14 +24,16 @@ export * from "./user.js"
export * from "./wot.js" export * from "./wot.js"
export * from "./zappers.js" export * from "./zappers.js"
import {derived} from "svelte/store"
import {sortBy, throttleWithValue, tryCatch} from "@welshman/lib" import {sortBy, throttleWithValue, tryCatch} from "@welshman/lib"
import {verifyEvent, isEphemeralKind, isDVMKind} from "@welshman/util" import {verifyEvent, isEphemeralKind, isDVMKind, RelayMode, getRelaysFromList} from "@welshman/util"
import {routerContext} from "@welshman/router" import {routerContext} from "@welshman/router"
import {Pool, SocketEvent, isRelayEvent} from "@welshman/net" import {Pool, SocketEvent, isRelayEvent} from "@welshman/net"
import {pubkey} from "./session.js" import {pubkey} from "./session.js"
import {repository, tracker} from "./core.js" import {repository, tracker} from "./core.js"
import {getPubkeyRelays} from "./relaySelections.js"
import {Relay, relays, loadRelay, trackRelayStats, getRelayQuality} from "./relays.js" import {Relay, relays, loadRelay, trackRelayStats, getRelayQuality} from "./relays.js"
import {relaySelectionsByPubkey} from "./relaySelections.js"
import {inboxRelaySelectionsByPubkey} from "./inboxRelaySelections.js"
// Sync relays with our database // Sync relays with our database
@@ -50,7 +53,7 @@ Pool.get().subscribe(socket => {
}) })
}) })
// Configure the router // Configure the router and add a few other relay utils
const _relayGetter = (fn?: (relay: Relay) => any) => const _relayGetter = (fn?: (relay: Relay) => any) =>
throttleWithValue(200, () => { throttleWithValue(200, () => {
@@ -65,6 +68,16 @@ const _relayGetter = (fn?: (relay: Relay) => any) =>
.map(r => r.url) .map(r => r.url)
}) })
export const getPubkeyRelays = (pubkey: string, mode?: RelayMode) =>
mode === RelayMode.Inbox
? getRelaysFromList(inboxRelaySelectionsByPubkey.get().get(pubkey))
: getRelaysFromList(relaySelectionsByPubkey.get().get(pubkey), mode)
export const derivePubkeyRelays = (pubkey: string, mode?: RelayMode) =>
mode === RelayMode.Inbox
? derived(inboxRelaySelectionsByPubkey, $m => getRelaysFromList($m.get(pubkey)))
: derived(relaySelectionsByPubkey, $m => getRelaysFromList($m.get(pubkey), mode))
routerContext.getUserPubkey = () => pubkey.get() routerContext.getUserPubkey = () => pubkey.get()
routerContext.getPubkeyRelays = getPubkeyRelays routerContext.getPubkeyRelays = getPubkeyRelays
routerContext.getRelayQuality = getRelayQuality routerContext.getRelayQuality = getRelayQuality
+2 -2
View File
@@ -3,7 +3,7 @@ import {readProfile, displayProfile, displayPubkey, PROFILE} from "@welshman/uti
import {PublishedProfile} from "@welshman/util" import {PublishedProfile} from "@welshman/util"
import {deriveEventsMapped, collection, withGetter} from "@welshman/store" import {deriveEventsMapped, collection, withGetter} from "@welshman/store"
import {repository} from "./core.js" import {repository} from "./core.js"
import {makeOutboxLoader} from "./relaySelections.js" import {makeOutboxLoaderWithIndexers} from "./relaySelections.js"
export const profiles = withGetter( export const profiles = withGetter(
deriveEventsMapped<PublishedProfile>(repository, { deriveEventsMapped<PublishedProfile>(repository, {
@@ -21,7 +21,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: makeOutboxLoaderWithIndexers(PROFILE),
}) })
export const displayProfileByPubkey = (pubkey: string | undefined) => export const displayProfileByPubkey = (pubkey: string | undefined) =>
+24 -66
View File
@@ -1,50 +1,35 @@
import {derived} from "svelte/store"
import {batcher} from "@welshman/lib" import {batcher} from "@welshman/lib"
import {INBOX_RELAYS, RELAYS, asDecryptedEvent, readList, getRelaysFromList} from "@welshman/util" import {RELAYS, asDecryptedEvent, readList, TrustedEvent, PublishedList} from "@welshman/util"
import {TrustedEvent, PublishedList, RelayMode} from "@welshman/util"
import {request} from "@welshman/net"
import {deriveEventsMapped, collection} from "@welshman/store" import {deriveEventsMapped, collection} from "@welshman/store"
import {load, LoadOptions} from "@welshman/net"
import {Router} from "@welshman/router" import {Router} from "@welshman/router"
import {repository} from "./core.js" import {repository} from "./core.js"
export type OutboxLoaderRequest = { export type LoadUsingOutboxOptions = Omit<LoadOptions, "relays">
pubkey: string
relays: string[]
kind: number
}
export const loadUsingOutbox = batcher(200, (requests: OutboxLoaderRequest[]) => { export const loadUsingOutbox = batcher(200, (optionses: LoadUsingOutboxOptions[]) => {
const router = Router.get() const pubkeys = optionses.flatMap(o => o.filters.flatMap(f => f.authors || []))
const kinds = new Set<number>() const relays = Router.get().FromPubkeys(pubkeys).getUrls()
const authors = new Set<string>()
const scenarios = [router.Index()]
for (const {pubkey, kind} of requests) { return optionses.map(options => load({...options, relays}))
kinds.add(kind)
authors.add(pubkey)
scenarios.push(router.FromPubkey(pubkey))
}
const relays = router.merge(scenarios).getUrls()
const filters = [{authors: Array.from(authors), kinds: Array.from(kinds)}]
const promise = request({filters, relays, autoClose: true})
return requests.map(async ({kind, pubkey, relays}) => {
const promises = [promise]
// If the caller explicitly provided relays, make sure we check them
if (relays.length > 0) {
const filters = [{authors: [pubkey], kinds: [kind]}]
promises.push(request({filters, relays, autoClose: true}))
}
await Promise.all(promises)
})
}) })
export const makeOutboxLoader = (kind: number) => (pubkey: string, relays: string[]) => export const makeOutboxLoader = (kind: number) => (pubkey: string, relays: string[]) => {
loadUsingOutbox({pubkey, relays, kind}) const filters = [{authors: [pubkey], kinds: [kind]}]
return Promise.all([load({relays, filters}), loadUsingOutbox({filters})])
}
export const makeOutboxLoaderWithIndexers =
(kind: number) => (pubkey: string, relays: string[]) => {
const filters = [{authors: [pubkey], kinds: [kind]}]
return Promise.all([
load({relays, filters}),
loadUsingOutbox({filters}),
load({relays: Router.get().Index().getUrls(), filters}),
])
}
export const relaySelections = deriveEventsMapped<PublishedList>(repository, { export const relaySelections = deriveEventsMapped<PublishedList>(repository, {
filters: [{kinds: [RELAYS]}], filters: [{kinds: [RELAYS]}],
@@ -60,32 +45,5 @@ export const {
name: "relaySelections", name: "relaySelections",
store: relaySelections, store: relaySelections,
getKey: relaySelections => relaySelections.event.pubkey, getKey: relaySelections => relaySelections.event.pubkey,
load: makeOutboxLoader(RELAYS), load: makeOutboxLoaderWithIndexers(RELAYS),
})
export const getPubkeyRelays = (pubkey: string, mode?: RelayMode) =>
mode === RelayMode.Inbox
? getRelaysFromList(inboxRelaySelectionsByPubkey.get().get(pubkey))
: getRelaysFromList(relaySelectionsByPubkey.get().get(pubkey), mode)
export const derivePubkeyRelays = (pubkey: string, mode?: RelayMode) =>
mode === RelayMode.Inbox
? derived(inboxRelaySelectionsByPubkey, $m => getRelaysFromList($m.get(pubkey)))
: derived(relaySelectionsByPubkey, $m => getRelaysFromList($m.get(pubkey), mode))
export const inboxRelaySelections = deriveEventsMapped<PublishedList>(repository, {
filters: [{kinds: [INBOX_RELAYS]}],
itemToEvent: item => item.event,
eventToItem: (event: TrustedEvent) => readList(asDecryptedEvent(event)),
})
export const {
indexStore: inboxRelaySelectionsByPubkey,
deriveItem: deriveInboxRelaySelections,
loadItem: loadInboxRelaySelections,
} = collection({
name: "inboxRelaySelections",
store: inboxRelaySelections,
getKey: inboxRelaySelections => inboxRelaySelections.event.pubkey,
load: makeOutboxLoader(INBOX_RELAYS),
}) })
+2 -6
View File
@@ -6,12 +6,8 @@ import {followsByPubkey, loadFollows} from "./follows.js"
import {loadPins, pinsByPubkey} from "./pins.js" import {loadPins, pinsByPubkey} from "./pins.js"
import {mutesByPubkey, loadMutes} from "./mutes.js" import {mutesByPubkey, loadMutes} from "./mutes.js"
import {blossomServersByPubkey, loadBlossomServers} from "./blossom.js" import {blossomServersByPubkey, loadBlossomServers} from "./blossom.js"
import { import {relaySelectionsByPubkey, loadRelaySelections} from "./relaySelections.js"
relaySelectionsByPubkey, import {inboxRelaySelectionsByPubkey, loadInboxRelaySelections} from "./inboxRelaySelections.js"
inboxRelaySelectionsByPubkey,
loadRelaySelections,
loadInboxRelaySelections,
} from "./relaySelections.js"
import {wotGraph} from "./wot.js" import {wotGraph} from "./wot.js"
export type UserDataLoader = (pubkey: string, relays?: string[], force?: boolean) => unknown export type UserDataLoader = (pubkey: string, relays?: string[], force?: boolean) => unknown