From b910569fc079e546789cf2a3f1c1537c62e2858e Mon Sep 17 00:00:00 2001 From: Jon Staab Date: Mon, 2 Sep 2024 15:57:40 -0700 Subject: [PATCH] Fix load bypassing freshness --- packages/app/src/collection.ts | 9 ++++--- packages/app/src/core.ts | 17 +++++++++++-- packages/app/src/follows.ts | 13 ++++------ packages/app/src/handles.ts | 12 ++------- packages/app/src/mutes.ts | 13 ++++------ packages/app/src/profiles.ts | 27 ++++++++++---------- packages/app/src/relaySelections.ts | 38 ++++++++++++++++++++++++----- packages/app/src/zappers.ts | 12 ++------- 8 files changed, 80 insertions(+), 61 deletions(-) diff --git a/packages/app/src/collection.ts b/packages/app/src/collection.ts index d444803..7a1f529 100644 --- a/packages/app/src/collection.ts +++ b/packages/app/src/collection.ts @@ -19,8 +19,11 @@ export const collection = ({ const pending = new Map>>() const loadItem = async (key: string, ...args: LoadArgs) => { - if (getFreshness(name, key) > now() - 3600) { - return indexStore.get().get(key) + const item = indexStore.get().get(key) + const delta = item ? 3600 : 300 + + if (getFreshness(name, key) > now() - delta) { + return item } if (pending.has(key)) { @@ -47,7 +50,7 @@ export const collection = ({ // If we don't yet have the item, or it's stale, trigger a request for it. The derived // store will update when it arrives - load(key, ...args) + loadItem(key, ...args) return derived(indexStore, $index => $index.get(key)) } diff --git a/packages/app/src/core.ts b/packages/app/src/core.ts index 248c895..24344f3 100644 --- a/packages/app/src/core.ts +++ b/packages/app/src/core.ts @@ -1,4 +1,3 @@ -import {first} from "@welshman/lib" import {Repository, Relay} from "@welshman/util" import type {TrustedEvent} from "@welshman/util" import {Tracker, subscribe as baseSubscribe} from "@welshman/net" @@ -6,9 +5,11 @@ import type {SubscribeRequest} from "@welshman/net" import {createEventStore} from "@welshman/store" export const env: { + BOOTSTRAP_RELAYS: string[] DUFFLEPUD_URL?: string [key: string]: any } = { + BOOTSTRAP_RELAYS: [], DUFFLEPUD_URL: undefined, } @@ -39,4 +40,16 @@ export const load = (request: SubscribeRequest) => sub.emitter.on("complete", () => resolve(events)) }) -export const loadOne = async (request: SubscribeRequest) => first(await load(request)) +export const loadOne = (request: SubscribeRequest) => + new Promise(resolve => { + const sub = subscribe({closeOnEose: true, timeout: 3000, ...request}) + + sub.emitter.on("event", (url: string, event: TrustedEvent) => { + resolve(event) + sub.close() + }) + + sub.emitter.on("complete", () => { + resolve(null) + }) + }) diff --git a/packages/app/src/follows.ts b/packages/app/src/follows.ts index c3b0f85..b5bd128 100644 --- a/packages/app/src/follows.ts +++ b/packages/app/src/follows.ts @@ -5,7 +5,7 @@ import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' import {ensurePlaintext} from './plaintext' -import {getWriteRelayUrls, loadRelaySelections} from './relaySelections' +import {getHintsForPubkey} from './relaySelections' export const follows = withGetter( deriveEventsMapped(repository, { @@ -28,13 +28,10 @@ export const { name: "follows", store: follows, getKey: follows => follows.event.pubkey, - load: async (pubkey: string, hints = [], request: Partial = {}) => { - const relays = getWriteRelayUrls(await loadRelaySelections(pubkey, hints)) - - return load({ + load: async (pubkey: string, request: Partial = {}) => + load({ ...request, - relays: [...relays, ...hints], filters: [{kinds: [FOLLOWS], authors: [pubkey]}], - }) - }, + relays: await getHintsForPubkey(pubkey, request.relays || []), + }), }) diff --git a/packages/app/src/handles.ts b/packages/app/src/handles.ts index a6ef7f2..c94ff74 100644 --- a/packages/app/src/handles.ts +++ b/packages/app/src/handles.ts @@ -1,9 +1,8 @@ -import {writable, derived} from 'svelte/store' +import {writable} from 'svelte/store' import {withGetter} from '@welshman/store' -import {uniq, indexBy, uniqBy, batcher, postJson, last} from '@welshman/lib' +import {uniq, uniqBy, batcher, postJson, last} from '@welshman/lib' import {env} from './core' import {collection} from './collection' -import {profilesByPubkey} from './profiles' export type Handle = { nip05: string @@ -14,13 +13,6 @@ export type Handle = { export const handles = withGetter(writable([])) -export const handlesByPubkey = derived([profilesByPubkey, handles], ([$profilesByPubkey, $handles]) => - indexBy( - $handle => $handle.pubkey, - $handles.filter($handle => $handle.pubkey && $profilesByPubkey.get($handle.pubkey)?.nip05 === $handle.nip05), - ), -) - export const fetchHandles = (handles: string[]) => { const base = env.DUFFLEPUD_URL! diff --git a/packages/app/src/mutes.ts b/packages/app/src/mutes.ts index 04d0b0d..663d64e 100644 --- a/packages/app/src/mutes.ts +++ b/packages/app/src/mutes.ts @@ -5,7 +5,7 @@ import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {collection} from './collection' import {ensurePlaintext} from './plaintext' -import {getWriteRelayUrls, loadRelaySelections} from './relaySelections' +import {getHintsForPubkey} from './relaySelections' export const mutes = withGetter( deriveEventsMapped(repository, { @@ -28,13 +28,10 @@ export const { name: "mutes", store: mutes, getKey: mute => mute.event.pubkey, - load: async (pubkey: string, hints = [], request: Partial = {}) => { - const relays = getWriteRelayUrls(await loadRelaySelections(pubkey, hints)) - - return load({ + load: async (pubkey: string, request: Partial = {}) => + load({ ...request, - relays: [...relays, ...hints], filters: [{kinds: [MUTES], authors: [pubkey]}], - }) - }, + relays: await getHintsForPubkey(pubkey, request.relays || []), + }), }) diff --git a/packages/app/src/profiles.ts b/packages/app/src/profiles.ts index 516cbe2..0a74ff2 100644 --- a/packages/app/src/profiles.ts +++ b/packages/app/src/profiles.ts @@ -2,17 +2,19 @@ import {derived} from 'svelte/store' import {readProfile, displayProfile, displayPubkey, PROFILE} from '@welshman/util' import {type SubscribeRequest} from "@welshman/net" import {type PublishedProfile} from "@welshman/util" -import {deriveEventsMapped} from '@welshman/store' +import {deriveEventsMapped, withGetter} from '@welshman/store' import {repository, load} from './core' import {createSearch} from './util' import {collection} from './collection' -import {getWriteRelayUrls, loadRelaySelections} from './relaySelections' +import {getHintsForPubkey} from './relaySelections' -export const profiles = deriveEventsMapped(repository, { - filters: [{kinds: [PROFILE]}], - eventToItem: readProfile, - itemToEvent: item => item.event, -}) +export const profiles = withGetter( + deriveEventsMapped(repository, { + filters: [{kinds: [PROFILE]}], + eventToItem: readProfile, + itemToEvent: item => item.event, + }) +) export const { indexStore: profilesByPubkey, @@ -22,15 +24,12 @@ export const { name: "profiles", store: profiles, getKey: profile => profile.event.pubkey, - load: async (pubkey: string, hints = [], request: Partial = {}) => { - const relays = getWriteRelayUrls(await loadRelaySelections(pubkey, hints)) - - return load({ + load: async (pubkey: string, request: Partial = {}) => + load({ ...request, - relays: [...relays, ...hints], filters: [{kinds: [PROFILE], authors: [pubkey]}], - }) - }, + relays: await getHintsForPubkey(pubkey, request.relays || []), + }), }) export const profileSearch = derived(profiles, $profiles => diff --git a/packages/app/src/relaySelections.ts b/packages/app/src/relaySelections.ts index cf1f5a6..1f01eb1 100644 --- a/packages/app/src/relaySelections.ts +++ b/packages/app/src/relaySelections.ts @@ -1,9 +1,14 @@ -import {RELAYS, getRelayTags, normalizeRelayUrl, type TrustedEvent} from '@welshman/util' +import {uniq} from '@welshman/lib' +import {INBOX_RELAYS, RELAYS, getRelayTags, normalizeRelayUrl, type TrustedEvent} from '@welshman/util' import {type SubscribeRequest} from "@welshman/net" -import {deriveEvents} from '@welshman/store' -import {load, repository} from './core' +import {deriveEvents, withGetter} from '@welshman/store' +import {env, load, repository} from './core' import {collection} from './collection' +export const getRelayUrls = (event?: TrustedEvent): string[] => + getRelayTags(event?.tags || []) + .map((t: string[]) => normalizeRelayUrl(t[1])) + export const getReadRelayUrls = (event?: TrustedEvent): string[] => getRelayTags(event?.tags || []) .filter((t: string[]) => !t[2] || t[2] === "read") @@ -14,7 +19,7 @@ export const getWriteRelayUrls = (event?: TrustedEvent): string[] => .filter((t: string[]) => !t[2] || t[2] === "write") .map((t: string[]) => normalizeRelayUrl(t[1])) -export const relaySelections = deriveEvents(repository, {filters: [{kinds: [RELAYS]}]}) +export const relaySelections = withGetter(deriveEvents(repository, {filters: [{kinds: [RELAYS]}]})) export const { indexStore: relaySelectionsByPubkey, @@ -24,10 +29,31 @@ export const { name: "relaySelections", store: relaySelections, getKey: relaySelections => relaySelections.pubkey, - load: (pubkey: string, relays: string[], request: Partial = {}) => + load: (pubkey: string, request: Partial = {}) => load({ ...request, - relays, filters: [{kinds: [RELAYS], authors: [pubkey]}], + relays: [...env.BOOTSTRAP_RELAYS, ...request.relays || []], + }), +}) + +export const getHintsForPubkey = async (pubkey: string, relays: string[] = []) => + uniq([...relays, ...env.BOOTSTRAP_RELAYS, ...getWriteRelayUrls(await loadRelaySelections(pubkey, {relays}))]) + +export const inboxRelaySelections = withGetter(deriveEvents(repository, {filters: [{kinds: [RELAYS]}]})) + +export const { + indexStore: inboxRelaySelectionsByPubkey, + deriveItem: deriveInboxRelaySelections, + loadItem: loadInboxRelaySelections, +} = collection({ + name: "inboxRelaySelections", + store: inboxRelaySelections, + getKey: inboxRelaySelections => inboxRelaySelections.pubkey, + load: async (pubkey: string, request: Partial = {}) => + load({ + ...request, + filters: [{kinds: [INBOX_RELAYS], authors: [pubkey]}], + relays: await getHintsForPubkey(pubkey, request.relays), }), }) diff --git a/packages/app/src/zappers.ts b/packages/app/src/zappers.ts index c83d1f3..85b7e98 100644 --- a/packages/app/src/zappers.ts +++ b/packages/app/src/zappers.ts @@ -1,20 +1,12 @@ -import {writable, derived} from 'svelte/store' +import {writable} from 'svelte/store' import {withGetter} from '@welshman/store' import type {Zapper} from '@welshman/util' -import {uniq, identity, bech32ToHex, indexBy, tryCatch, uniqBy, batcher, postJson} from '@welshman/lib' +import {uniq, identity, bech32ToHex, tryCatch, uniqBy, batcher, postJson} from '@welshman/lib' import {env} from './core' import {collection} from './collection' -import {profilesByPubkey} from './profiles' export const zappers = withGetter(writable([])) -export const zappersByPubkey = derived([profilesByPubkey, zappers], ([$profilesByPubkey, $zappers]) => - indexBy( - $zapper => $zapper.pubkey, - $zappers.filter($zapper => $zapper.pubkey && $profilesByPubkey.get($zapper.pubkey)?.lnurl === $zapper.lnurl), - ), -) - export const fetchZappers = (lnurls: string[]) => { const base = env.DUFFLEPUD_URL!