diff --git a/src/services/bookmarkService.ts b/src/services/bookmarkService.ts index 3f461055..c9e42963 100644 --- a/src/services/bookmarkService.ts +++ b/src/services/bookmarkService.ts @@ -1,5 +1,4 @@ -import { RelayPool, completeOnEose } from 'applesauce-relay' -import { lastValueFrom, merge, Observable, takeUntil, timer, toArray } from 'rxjs' +import { RelayPool } from 'applesauce-relay' import { AccountWithExtension, NostrEvent, @@ -16,7 +15,7 @@ import { Bookmark } from '../types/bookmarks' import { collectBookmarksFromEvents } from './bookmarkProcessing.ts' import { UserSettings } from './settingsService' import { rebroadcastEvents } from './rebroadcastService' -import { prioritizeLocalRelays, partitionRelays } from '../utils/helpers' +import { queryEvents } from './dataFetch' @@ -31,23 +30,14 @@ export const fetchBookmarks = async ( if (!isAccountWithExtension(activeAccount)) { throw new Error('Invalid account object provided') } - // Get relay URLs from the pool - const relayUrls = prioritizeLocalRelays(Array.from(relayPool.relays.values()).map(relay => relay.url)) - const { local: localRelays, remote: remoteRelays } = partitionRelays(relayUrls) // Fetch bookmark events - NIP-51 standards, legacy formats, and web bookmarks (NIP-B0) - console.log('🔍 Fetching bookmark events from relays:', relayUrls) - // Try local-first quickly, then full set fallback - const local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [10003, 30003, 30001, 39701], authors: [activeAccount.pubkey] }) - .pipe(completeOnEose(), takeUntil(timer(1200))) - : new Observable((sub) => sub.complete()) - const remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [10003, 30003, 30001, 39701], authors: [activeAccount.pubkey] }) - .pipe(completeOnEose(), takeUntil(timer(6000))) - : new Observable((sub) => sub.complete()) - const rawEvents = await lastValueFrom(merge(local$, remote$).pipe(toArray())) + console.log('🔍 Fetching bookmark events') + + const rawEvents = await queryEvents( + relayPool, + { kinds: [10003, 30003, 30001, 39701], authors: [activeAccount.pubkey] }, + {} + ) console.log('📊 Raw events fetched:', rawEvents.length, 'events') // Rebroadcast bookmark events to local/all relays based on settings @@ -111,14 +101,11 @@ export const fetchBookmarks = async ( let idToEvent: Map = new Map() if (noteIds.length > 0) { try { - const { local: localHydrate, remote: remoteHydrate } = partitionRelays(relayUrls) - const localHydrate$ = localHydrate.length > 0 - ? relayPool.req(localHydrate, { ids: noteIds }).pipe(completeOnEose(), takeUntil(timer(800))) - : new Observable((sub) => sub.complete()) - const remoteHydrate$ = remoteHydrate.length > 0 - ? relayPool.req(remoteHydrate, { ids: noteIds }).pipe(completeOnEose(), takeUntil(timer(2500))) - : new Observable((sub) => sub.complete()) - const events: NostrEvent[] = await lastValueFrom(merge(localHydrate$, remoteHydrate$).pipe(toArray())) + const events = await queryEvents( + relayPool, + { ids: noteIds }, + { localTimeoutMs: 800, remoteTimeoutMs: 2500 } + ) idToEvent = new Map(events.map((e: NostrEvent) => [e.id, e])) } catch (error) { console.warn('Failed to fetch events for hydration:', error) diff --git a/src/services/libraryService.ts b/src/services/libraryService.ts index 0c8b3729..8818b818 100644 --- a/src/services/libraryService.ts +++ b/src/services/libraryService.ts @@ -1,11 +1,10 @@ -import { RelayPool, completeOnEose, onlyEvents } from 'applesauce-relay' -import { lastValueFrom, merge, Observable, takeUntil, timer, toArray } from 'rxjs' +import { RelayPool } from 'applesauce-relay' import { NostrEvent } from 'nostr-tools' import { Helpers } from 'applesauce-core' import { RELAYS } from '../config/relays' -import { prioritizeLocalRelays, partitionRelays } from '../utils/helpers' import { MARK_AS_READ_EMOJI } from './reactionService' import { BlogPostPreview } from './exploreService' +import { queryEvents } from './dataFetch' const { getArticleTitle, getArticleImage, getArticlePublished, getArticleSummary } = Helpers @@ -28,58 +27,11 @@ export async function fetchReadArticles( userPubkey: string ): Promise { try { - const orderedRelays = prioritizeLocalRelays(RELAYS) - const { local: localRelays, remote: remoteRelays } = partitionRelays(orderedRelays) - - // Fetch kind:7 reactions (nostr-native articles) - const kind7Local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [7], authors: [userPubkey] }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(1200)) - ) - : new Observable((sub) => sub.complete()) - - const kind7Remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [7], authors: [userPubkey] }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(6000)) - ) - : new Observable((sub) => sub.complete()) - - const kind7Events: NostrEvent[] = await lastValueFrom( - merge(kind7Local$, kind7Remote$).pipe(toArray()) - ) - - // Fetch kind:17 reactions (external URLs) - const kind17Local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [17], authors: [userPubkey] }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(1200)) - ) - : new Observable((sub) => sub.complete()) - - const kind17Remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [17], authors: [userPubkey] }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(6000)) - ) - : new Observable((sub) => sub.complete()) - - const kind17Events: NostrEvent[] = await lastValueFrom( - merge(kind17Local$, kind17Remote$).pipe(toArray()) - ) + // Fetch kind:7 and kind:17 reactions in parallel + const [kind7Events, kind17Events] = await Promise.all([ + queryEvents(relayPool, { kinds: [7], authors: [userPubkey] }, { relayUrls: RELAYS }), + queryEvents(relayPool, { kinds: [17], authors: [userPubkey] }, { relayUrls: RELAYS }) + ]) const readArticles: ReadArticle[] = [] @@ -157,34 +109,13 @@ export async function fetchReadArticlesWithData( return [] } - const orderedRelays = prioritizeLocalRelays(RELAYS) - const { local: localRelays, remote: remoteRelays } = partitionRelays(orderedRelays) - // Fetch the actual article events const eventIds = nostrArticles.map(a => a.eventId!).filter(Boolean) - const local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [30023], ids: eventIds }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(1200)) - ) - : new Observable((sub) => sub.complete()) - - const remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [30023], ids: eventIds }) - .pipe( - onlyEvents(), - completeOnEose(), - takeUntil(timer(6000)) - ) - : new Observable((sub) => sub.complete()) - - const articleEvents: NostrEvent[] = await lastValueFrom( - merge(local$, remote$).pipe(toArray()) + const articleEvents = await queryEvents( + relayPool, + { kinds: [30023], ids: eventIds }, + { relayUrls: RELAYS } ) // Deduplicate article events by ID diff --git a/src/services/nostrverseService.ts b/src/services/nostrverseService.ts index aa5a6839..04a98431 100644 --- a/src/services/nostrverseService.ts +++ b/src/services/nostrverseService.ts @@ -1,11 +1,10 @@ -import { RelayPool, completeOnEose, onlyEvents } from 'applesauce-relay' -import { lastValueFrom, merge, Observable, takeUntil, timer, toArray } from 'rxjs' +import { RelayPool } from 'applesauce-relay' import { NostrEvent } from 'nostr-tools' -import { prioritizeLocalRelays, partitionRelays } from '../utils/helpers' import { Helpers } from 'applesauce-core' import { BlogPostPreview } from './exploreService' import { Highlight } from '../types/highlights' import { eventToHighlight, dedupeHighlights, sortHighlights } from './highlightEventProcessor' +import { queryEvents } from './dataFetch' const { getArticleTitle, getArticleImage, getArticlePublished, getArticleSummary } = Helpers @@ -23,36 +22,25 @@ export const fetchNostrverseBlogPosts = async ( ): Promise => { try { console.log('📚 Fetching nostrverse blog posts (kind 30023), limit:', limit) - - const prioritized = prioritizeLocalRelays(relayUrls) - const { local: localRelays, remote: remoteRelays } = partitionRelays(prioritized) // Deduplicate replaceable events by keeping the most recent version const uniqueEvents = new Map() - const processEvents = (incoming: NostrEvent[]) => { - for (const event of incoming) { - const dTag = event.tags.find(t => t[0] === 'd')?.[1] || '' - const key = `${event.pubkey}:${dTag}` - const existing = uniqueEvents.get(key) - if (!existing || event.created_at > existing.created_at) { - uniqueEvents.set(key, event) + const events = await queryEvents( + relayPool, + { kinds: [30023], limit }, + { + relayUrls, + onEvent: (event: NostrEvent) => { + const dTag = event.tags.find(t => t[0] === 'd')?.[1] || '' + const key = `${event.pubkey}:${dTag}` + const existing = uniqueEvents.get(key) + if (!existing || event.created_at > existing.created_at) { + uniqueEvents.set(key, event) + } } } - } - - const local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [30023], limit }) - .pipe(completeOnEose(), takeUntil(timer(1200)), onlyEvents()) - : new Observable((sub) => sub.complete()) - const remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [30023], limit }) - .pipe(completeOnEose(), takeUntil(timer(6000)), onlyEvents()) - : new Observable((sub) => sub.complete()) - const events = await lastValueFrom(merge(local$, remote$).pipe(toArray())) - processEvents(events) + ) console.log('📊 Nostrverse blog post events fetched (unique):', uniqueEvents.size) @@ -93,24 +81,12 @@ export const fetchNostrverseHighlights = async ( ): Promise => { try { console.log('💡 Fetching nostrverse highlights (kind 9802), limit:', limit) - - const relayUrls = Array.from(relayPool.relays.values()).map(relay => relay.url) - const prioritized = prioritizeLocalRelays(relayUrls) - const { local: localRelays, remote: remoteRelays } = partitionRelays(prioritized) - const local$ = localRelays.length > 0 - ? relayPool - .req(localRelays, { kinds: [9802], limit }) - .pipe(completeOnEose(), takeUntil(timer(1200)), onlyEvents()) - : new Observable((sub) => sub.complete()) - - const remote$ = remoteRelays.length > 0 - ? relayPool - .req(remoteRelays, { kinds: [9802], limit }) - .pipe(completeOnEose(), takeUntil(timer(6000)), onlyEvents()) - : new Observable((sub) => sub.complete()) - - const rawEvents: NostrEvent[] = await lastValueFrom(merge(local$, remote$).pipe(toArray())) + const rawEvents = await queryEvents( + relayPool, + { kinds: [9802], limit }, + {} + ) const uniqueEvents = dedupeHighlights(rawEvents) const highlights = uniqueEvents.map(eventToHighlight)