Re-work feed requests

This commit is contained in:
Jon Staab
2025-04-24 13:49:02 -07:00
parent 4031564c6c
commit 3d1a6a106e
9 changed files with 207 additions and 183 deletions
+6 -104
View File
@@ -1,103 +1,8 @@
import {nthEq, partition, race, now} from "@welshman/lib"
import {createEvent, getPubkeyTagValues, TrustedEvent} from "@welshman/util"
import {request, Tracker} from "@welshman/net"
import {Scope, FeedController, RequestOpts, FeedOptions, DVMOpts, Feed} from "@welshman/feeds"
import {Router, addMinimalFallbacks, getFilterSelections} from "@welshman/router"
import {makeDvmRequest} from "@welshman/dvm"
import {makeSecret, Nip01Signer} from "@welshman/signer"
import {Scope, FeedController, FeedControllerOptions, Feed} from "@welshman/feeds"
import {pubkey, signer} from "./session.js"
import {loadRelaySelections} from "./relaySelections.js"
import {wotGraph, maxWot, getFollows, getNetwork, getFollowers} from "./wot.js"
import {repository} from "./core.js"
export type FeedRequestHandlerOptions = {
signal?: AbortSignal
}
export const makeFeedRequestHandler =
({signal}: FeedRequestHandlerOptions) =>
async ({filters = [{}], relays = [], onEvent}: RequestOpts) => {
const tracker = new Tracker()
if (relays.length > 0) {
await request({tracker, signal, relays, filters, onEvent, autoClose: true})
} else {
const promises: Promise<TrustedEvent[]>[] = []
const [withSearch, withoutSearch] = partition(f => Boolean(f.search), filters)
if (withSearch.length > 0) {
promises.push(
request({
signal,
tracker,
onEvent,
threshold: 0.1,
autoClose: true,
filters: withSearch,
relays: Router.get().Search().getUrls(),
}),
)
}
if (withoutSearch.length > 0) {
promises.push(
...getFilterSelections(filters).flatMap(({relays, filters}) =>
request({tracker, signal, onEvent, relays, filters, threshold: 0.8, autoClose: true}),
),
)
}
// Break out selections by relay so we can complete early after a certain number
// of requests complete for faster load times
await race(withSearch.length > 0 ? 0.1 : 0.8, promises)
// Wait until after we've queried the network to access our local cache. This results in less
// snappy response times, but is necessary to prevent stale stuff that the user has already seen
// from showing up at the top of the feed
for (const event of repository.query(filters)) {
onEvent(event)
}
}
}
export const requestDVM = async ({kind, onEvent, ...request}: DVMOpts) => {
// Make sure we know what relays to use for target dvms
if (request.tags && !request.relays) {
for (const pubkey of getPubkeyTagValues(request.tags)) {
await loadRelaySelections(pubkey)
}
}
const tags = request.tags || []
const $signer = signer.get() || new Nip01Signer(makeSecret())
const pubkey = await $signer.getPubkey()
const relays =
request.relays ||
Router.get().FromPubkeys(getPubkeyTagValues(tags)).policy(addMinimalFallbacks).getUrls()
if (!tags.some(nthEq(0, "expiration"))) {
tags.push(["expiration", String(now() + 60)])
}
if (!tags.some(nthEq(0, "relays"))) {
tags.push(["relays", ...relays])
}
if (!tags.some(nthEq(1, "user"))) {
tags.push(["param", "user", pubkey])
}
if (!tags.some(nthEq(1, "max_results"))) {
tags.push(["param", "max_results", "200"])
}
await makeDvmRequest({
relays,
event: await $signer.sign(createEvent(kind, {tags})),
onResult: onEvent,
})
}
export const getPubkeysForScope = (scope: string) => {
const $pubkey = pubkey.get()
@@ -133,16 +38,13 @@ export const getPubkeysForWOTRange = (min: number, max: number) => {
return pubkeys
}
type _FeedOptions = Partial<Omit<FeedOptions, "feed">> & {feed: Feed}
type MakeFeedControllerOptions = Partial<Omit<FeedControllerOptions, "feed">> & {feed: Feed}
export const createFeedController = (options: _FeedOptions) => {
const request = makeFeedRequestHandler(options)
return new FeedController({
request,
requestDVM,
export const makeFeedController = (options: MakeFeedControllerOptions) =>
new FeedController({
repository,
getPubkeysForScope,
getPubkeysForWOTRange,
signer: signer.get(),
...options,
})
}
+3 -2
View File
@@ -10,8 +10,9 @@ const query = (filters: Filter[]) =>
export const hasNegentropy = (url: string) => {
const p = relaysByUrl.get().get(url)?.profile
if (p?.supported_nips?.includes(77)) return true
if (p?.software?.includes("strfry") && !p?.version?.match(/^0\./)) return true
if (p?.negentropy) return true
if (p?.supported_nips?.includes?.(77)) return true
if (p?.software?.includes?.("strfry") && !p?.version?.match(/^0\./)) return true
return false
}