diff --git a/src/contexts/NDKContext.tsx b/src/contexts/NDKContext.tsx index 0ec3771..4c84f7f 100644 --- a/src/contexts/NDKContext.tsx +++ b/src/contexts/NDKContext.tsx @@ -33,12 +33,8 @@ type FetchModsOptions = { interface NDKContextType { ndk: NDK fetchMods: (opts: FetchModsOptions) => Promise - fetchEvents: (filter: NDKFilter, relayUrls?: string[]) => Promise - fetchEvent: ( - filter: NDKFilter, - relayUrls?: string[] - ) => Promise - + fetchEvents: (filter: NDKFilter) => Promise + fetchEvent: (filter: NDKFilter) => Promise fetchEventsFromUserRelays: ( filter: NDKFilter, hexKey: string, @@ -72,6 +68,31 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { } }, []) + const addAdminRelays = async (ndk: NDK) => { + const adminNpubs = import.meta.env.VITE_ADMIN_NPUBS.split(',') + adminNpubs.forEach((npub) => { + const hexKey = npubToHex(npub) + if (hexKey) { + getRelayListForUser(hexKey, ndk) + .then((ndkRelayList) => { + if (ndkRelayList) { + ndkRelayList.bothRelayUrls.forEach((url) => + ndk.addExplicitRelay(url) + ) + } + }) + .catch((err) => { + log( + true, + LogType.Error, + `❌ Error occurred in getting the instance of NDKRelayList for npub: ${npub}`, + err + ) + }) + } + }) + } + const ndk = useMemo(() => { localStorage.setItem('debug', '*') const dexieAdapter = new NDKCacheAdapterDexie({ dbName: 'degmod-db' }) @@ -88,6 +109,7 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { ], cacheAdapter: dexieAdapter }) + addAdminRelays(ndk) ndk.connect() @@ -110,33 +132,6 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { since, limit }: FetchModsOptions): Promise => { - const relays = new Set() - relays.add(import.meta.env.VITE_APP_RELAY) - - const adminNpubs = import.meta.env.VITE_ADMIN_NPUBS.split(',') - - const promises = adminNpubs.map((npub) => { - const hexKey = npubToHex(npub) - if (!hexKey) return null - - return getRelayListForUser(hexKey, ndk) - .then((ndkRelayList) => { - if (ndkRelayList) { - ndkRelayList.writeRelayUrls.forEach((url) => relays.add(url)) - } - }) - .catch((err) => { - log( - true, - LogType.Error, - `❌ Error occurred in getting the instance of NDKRelayList for npub: ${npub}`, - err - ) - }) - }) - - await Promise.allSettled(promises) - // Define the filter criteria for fetching mods const filter: NDKFilter = { kinds: [NDKKind.Classified], // Specify the kind of events to fetch @@ -152,11 +147,10 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { } return ndk - .fetchEvents( - filter, - { closeOnEose: true, cacheUsage: NDKSubscriptionCacheUsage.PARALLEL }, - NDKRelaySet.fromRelayUrls(Array.from(relays), ndk, true) - ) + .fetchEvents(filter, { + closeOnEose: true, + cacheUsage: NDKSubscriptionCacheUsage.PARALLEL + }) .then((ndkEventSet) => { const ndkEvents = Array.from(ndkEventSet) orderEventsChronologically(ndkEvents) @@ -179,56 +173,17 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { } /** - * Asynchronously retrieves multiple event from a set of relays based on a provided filter. - * If no relays are specified, it defaults to using connected relays. + * Asynchronously retrieves multiple event based on a provided filter. * * @param filter - The filter criteria to find the event. - * @param relays - An optional array of relay URLs to search for the event. * @returns Returns a promise that resolves to the found event or null if not found. */ - const fetchEvents = async ( - filter: NDKFilter, - relayUrls: string[] = [] - ): Promise => { - const relays = new Set() - - // add all the relays passed to relay set - relayUrls.forEach((relayUrl) => { - relays.add(relayUrl) - }) - - relays.add(import.meta.env.VITE_APP_RELAY) - - const adminNpubs = import.meta.env.VITE_ADMIN_NPUBS.split(',') - - const promises = adminNpubs.map((npub) => { - const hexKey = npubToHex(npub) - if (!hexKey) return null - - return getRelayListForUser(hexKey, ndk) - .then((ndkRelayList) => { - if (ndkRelayList) { - ndkRelayList.writeRelayUrls.forEach((url) => relays.add(url)) - } - }) - .catch((err) => { - log( - true, - LogType.Error, - `❌ Error occurred in getting the instance of NDKRelayList for npub: ${npub}`, - err - ) - }) - }) - - await Promise.allSettled(promises) - + const fetchEvents = async (filter: NDKFilter): Promise => { return ndk - .fetchEvents( - filter, - { closeOnEose: true, cacheUsage: NDKSubscriptionCacheUsage.PARALLEL }, - NDKRelaySet.fromRelayUrls(Array.from(relays), ndk, true) - ) + .fetchEvents(filter, { + closeOnEose: true, + cacheUsage: NDKSubscriptionCacheUsage.PARALLEL + }) .then((ndkEventSet) => { const ndkEvents = Array.from(ndkEventSet) return orderEventsChronologically(ndkEvents) @@ -242,15 +197,13 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { } /** - * Asynchronously retrieves an event from a set of relays based on a provided filter. - * If no relays are specified, it defaults to using connected relays. + * Asynchronously retrieves an event based on a provided filter. * * @param filter - The filter criteria to find the event. - * @param relaysUrls - An optional array of relay URLs to search for the event. * @returns Returns a promise that resolves to the found event or null if not found. */ - const fetchEvent = async (filter: NDKFilter, relayUrls: string[] = []) => { - const events = await fetchEvents(filter, relayUrls) + const fetchEvent = async (filter: NDKFilter) => { + const events = await fetchEvents(filter) if (events.length === 0) return null return events[0] } @@ -285,8 +238,22 @@ export const NDKContextProvider = ({ children }: { children: ReactNode }) => { return [] as string[] }) - // Fetch the event from the user's relays using the provided filter and relay URLs - return fetchEvents(filter, relayUrls) + return ndk + .fetchEvents( + filter, + { closeOnEose: true, cacheUsage: NDKSubscriptionCacheUsage.PARALLEL }, + NDKRelaySet.fromRelayUrls(relayUrls, ndk, true) + ) + .then((ndkEventSet) => { + const ndkEvents = Array.from(ndkEventSet) + return orderEventsChronologically(ndkEvents) + }) + .catch((err) => { + // Log the error and show a notification if fetching fails + log(true, LogType.Error, 'An error occurred in fetching events', err) + toast.error('An error occurred in fetching events') // Show error notification + return [] // Return an empty array in case of an error + }) } /** diff --git a/src/controllers/relay.ts b/src/controllers/relay.ts index 2fdd6ae..64c22c2 100644 --- a/src/controllers/relay.ts +++ b/src/controllers/relay.ts @@ -372,75 +372,6 @@ export class RelayController { return publishedOnRelays } - /** - * Subscribes to events from multiple relays. - * - * This method connects to the specified relay URLs and subscribes to events - * using the provided filter. It handles incoming events through the given - * `eventHandler` callback and manages the subscription lifecycle. - * - * @param filter - The filter criteria to apply when subscribing to events. - * @param relayUrls - An optional array of relay URLs to connect to. The default relay URL (`APP_RELAY`) is added automatically. - * @param eventHandler - A callback function to handle incoming events. It receives an `Event` object. - * - */ - subscribeForEvents = async ( - filter: Filter, - relayUrls: string[] = [], - eventHandler: (event: Event) => void - ) => { - const appRelay = import.meta.env.VITE_APP_RELAY - if (!relayUrls.includes(appRelay)) { - /** - * NOTE: To avoid side-effects on external relayUrls array passed as argument - * re-assigned relayUrls with added sigit relay instead of just appending to same array - */ - relayUrls = [...relayUrls, appRelay] // Add app relay to relays array if not exists already - } - - // connect to all specified relays - const relayPromises = relayUrls.map((relayUrl) => - this.connectRelay(relayUrl) - ) - - // Use Promise.allSettled to wait for all promises to settle - const results = await Promise.allSettled(relayPromises) - - // Extract non-null values from fulfilled promises in a single pass - const relays = results.reduce((acc, result) => { - if (result.status === 'fulfilled') { - const value = result.value - if (value) { - acc.push(value) - } - } - return acc - }, []) - - // Check if any relays are connected - if (relays.length === 0) { - throw new Error('No relay is connected to fetch events!') - } - - const processedEvents: string[] = [] // To keep track of processed events - - // Create a promise for each relay subscription - const subscriptions = relays.map((relay) => - relay.subscribe([filter], { - // Handle incoming events - onevent: (e) => { - // Process event only if it hasn't been processed before - if (!processedEvents.includes(e.id)) { - processedEvents.push(e.id) - eventHandler(e) // Call the event handler with the event - } - } - }) - ) - - return subscriptions - } - getTotalZapAmount = async ( user: string, eTag: string, diff --git a/src/pages/search.tsx b/src/pages/search.tsx index 41aebcb..f9f3cac 100644 --- a/src/pages/search.tsx +++ b/src/pages/search.tsx @@ -392,7 +392,7 @@ const UsersResult = ({ } setIsFetching(true) - fetchEvents(filter, ['wss://purplepag.es', 'wss://user.kindpag.es']) + fetchEvents(filter) .then((events) => { const results = events.map((event) => { const ndkEvent = new NDKEvent(undefined, event)