From 086deb490490823b9be7656bca17418c02934509 Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Tue, 12 Aug 2025 18:51:33 -0400 Subject: [PATCH 1/3] feat(nostr): Handle multiple nostr relays --- .../content-creators/content-creators-list.js | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/src/components/app-body/nostr/content-creators/content-creators-list.js b/src/components/app-body/nostr/content-creators/content-creators-list.js index fa85ec2..0ddb350 100644 --- a/src/components/app-body/nostr/content-creators/content-creators-list.js +++ b/src/components/app-body/nostr/content-creators/content-creators-list.js @@ -31,9 +31,11 @@ function ContentCreators (props) { const [followList, setFollowList] = useState([]) + // Get the list of profiles followed by the user const getFollowList = useCallback(async () => { const list = await new Promise((resolve, reject) => { let list = [] + let closedRelays = 0 const { nostrKeyPair } = appData.bchWalletState const pool = RelayPool(config.nostrRelays) @@ -43,49 +45,60 @@ function ContentCreators (props) { }) pool.on('eose', relay => { - console.log('Closing Relay') relay.close() - /** This ensures to return an empty array if no records are found! - * Applies for new users that don't have a follow list - */ - resolve(list) + closedRelays++ + // Resolve list if all relays are closed + if (closedRelays === config.nostrRelays.length) { + resolve(list) + } }) pool.on('event', (relay, subId, ev) => { - console.log('Received event:', ev) - list = ev.tags - resolve(list) + // console.log('Received event:', ev) + // Merge list received from all relays + list = [...list, ...ev.tags] }) }) - console.log('Follow List', list) + // console.log('Follow List', list) setFollowList(list) }, [appData]) + // Load profile from nostr relays const loadProfile = useCallback(async (pubKey) => { - return new Promise((resolve) => { - // const pool = RelayPool(config.nostrRelays) - const pool = RelayPool([config.nostrRelay]) - pool.on('open', relay => { - relay.subscribe('subid', { limit: 5, kinds: [0], authors: [pubKey] }) - }) + // Looking for the profile in each relay sequentially + for (let i = 0; i < config.nostrRelays.length; i++) { + const profile = await new Promise((resolve) => { + const relay = config.nostrRelays[i] + // const pool = RelayPool(config.nostrRelays) + const pool = RelayPool([relay]) + pool.on('open', relay => { + relay.subscribe('subid', { limit: 5, kinds: [0], authors: [pubKey] }) + }) - pool.on('eose', relay => { - console.log('Closing Relay') - relay.close() - resolve(false) - }) - - pool.on('event', (relay, subId, ev) => { - try { - const profile = JSON.parse(ev.content) - // console.log('profile', profile) - resolve(profile) - } catch (error) { + pool.on('eose', relay => { + console.log('Closing Relay') + relay.close() resolve(false) - } + }) + + pool.on('event', (relay, subId, ev) => { + try { + const profile = JSON.parse(ev.content) + // console.log('profile', profile) + console.log(`Profile found for ${pubKey} at ${relay.url}`) + resolve(profile) + } catch (error) { + resolve(false) + } + relay.close() + }) }) - }) + // Stop looking for profile if found + if (profile) { + return profile + } + } }, []) useEffect(() => { From e46068165fb6da618f1289eff80db35ffb28e24f Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 13 Aug 2025 08:00:52 -0700 Subject: [PATCH 2/3] Removing completed todos --- .../nostr/content-creators/content-creators-list.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/app-body/nostr/content-creators/content-creators-list.js b/src/components/app-body/nostr/content-creators/content-creators-list.js index 0ddb350..1d3f0c4 100644 --- a/src/components/app-body/nostr/content-creators/content-creators-list.js +++ b/src/components/app-body/nostr/content-creators/content-creators-list.js @@ -2,12 +2,6 @@ This component is used to display the list of content creators. TODO: - - getFollowList() should aggregate all the followers from all the relays. - Currently each relay overwrites the last one. - - - loadProfile() should use multiple relays. It should exit after the first - successful retrieval of data from a relay. If the relay fails to give data, - it should move on to the next relay. */ import React, { useState, useEffect, useCallback } from 'react' From 173cda717e938b5304b1381a5ca1d3fb3606f743 Mon Sep 17 00:00:00 2001 From: Chris Troutner Date: Wed, 13 Aug 2025 08:02:50 -0700 Subject: [PATCH 3/3] Adding comments --- .../nostr/content-creators/content-creators-list.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/components/app-body/nostr/content-creators/content-creators-list.js b/src/components/app-body/nostr/content-creators/content-creators-list.js index 1d3f0c4..2a1c8f0 100644 --- a/src/components/app-body/nostr/content-creators/content-creators-list.js +++ b/src/components/app-body/nostr/content-creators/content-creators-list.js @@ -2,6 +2,12 @@ This component is used to display the list of content creators. TODO: + - getFollowList() should aggregate all the followers from all the relays. + Currently each relay overwrites the last one. + + - loadProfile() should use multiple relays. It should exit after the first + successful retrieval of data from a relay. If the relay fails to give data, + it should move on to the next relay. */ import React, { useState, useEffect, useCallback } from 'react' @@ -25,7 +31,8 @@ function ContentCreators (props) { const [followList, setFollowList] = useState([]) - // Get the list of profiles followed by the user + // Get the list of profiles followed by the user. + // It aggregates all the followers from all the relays. const getFollowList = useCallback(async () => { const list = await new Promise((resolve, reject) => { let list = [] @@ -59,6 +66,8 @@ function ContentCreators (props) { }, [appData]) // Load profile from nostr relays + // It uses multiple relays. It will exit after the first successful retrieval + // from any relay. If one relay fails, it will move on to the next one. const loadProfile = useCallback(async (pubKey) => { // Looking for the profile in each relay sequentially for (let i = 0; i < config.nostrRelays.length; i++) {