From 6c282bd008674dbe97ad5e8148e557a4b1674b16 Mon Sep 17 00:00:00 2001 From: Silberengel Date: Mon, 13 Oct 2025 09:55:21 +0200 Subject: [PATCH] filter out other people's local relays. deduplicate relay list --- src/components/PostEditor/PostContent.tsx | 38 +++---- .../PostEditor/PostRelaySelector.tsx | 15 +-- src/services/relay-selection.service.ts | 99 +++++++++++++++---- 3 files changed, 95 insertions(+), 57 deletions(-) diff --git a/src/components/PostEditor/PostContent.tsx b/src/components/PostEditor/PostContent.tsx index 8226f4e..dce6861 100644 --- a/src/components/PostEditor/PostContent.tsx +++ b/src/components/PostEditor/PostContent.tsx @@ -140,17 +140,11 @@ export default function PostContent({ // Extract mentions from content for public messages const extractMentionsFromContent = useCallback(async (content: string) => { try { - // First try to extract nostr: protocol mentions + // Extract nostr: protocol mentions const { pubkeys: nostrPubkeys } = await extractMentions(content, undefined) - // Also extract regular @ mentions (simple pattern for now) - const atMentions = content.match(/@[a-zA-Z0-9_]+/g) || [] - - console.log('Nostr mentions:', nostrPubkeys) - console.log('@ mentions:', atMentions) - - // For now, we'll use the nostr mentions and show that we detected @ mentions - // In a real implementation, you'd resolve @ mentions to pubkeys + // For now, we'll use the nostr mentions + // In a real implementation, you'd also resolve @ mentions to pubkeys setExtractedMentions(nostrPubkeys) } catch (error) { console.error('Error extracting mentions:', error) @@ -495,23 +489,15 @@ export default function PostContent({ ))} {!isPoll && ( - <> - {console.log('PostContent: Rendering PostRelaySelector with:', { - extractedMentions, - isPublicMessage, - isPoll, - textLength: text.length - })} - - + )}
diff --git a/src/components/PostEditor/PostRelaySelector.tsx b/src/components/PostEditor/PostRelaySelector.tsx index c38e2b6..dded0fc 100644 --- a/src/components/PostEditor/PostRelaySelector.tsx +++ b/src/components/PostEditor/PostRelaySelector.tsx @@ -122,24 +122,11 @@ export default function PostRelaySelector({ // Separate effect for mention changes in non-discussion replies useEffect(() => { - console.log('PostRelaySelector: Mentions effect triggered', { - mentions, - previousMentions, - isDiscussionReply, - mentionsLength: mentions.length, - previousMentionsLength: previousMentions.length - }) - - if (isDiscussionReply) { - console.log('PostRelaySelector: Skipping mention update - is discussion reply') - return // Skip for discussion replies - } + if (isDiscussionReply) return // Skip for discussion replies const mentionsChanged = JSON.stringify(mentions) !== JSON.stringify(previousMentions) - console.log('PostRelaySelector: Mentions changed?', mentionsChanged) if (mentionsChanged) { - console.log('PostRelaySelector: Updating relay selection due to mention changes') setPreviousMentions(mentions) // Update relay selection when mentions change diff --git a/src/services/relay-selection.service.ts b/src/services/relay-selection.service.ts index bb4c72b..89cb0a5 100644 --- a/src/services/relay-selection.service.ts +++ b/src/services/relay-selection.service.ts @@ -2,7 +2,7 @@ import { Event, kinds } from 'nostr-tools' import { ExtendedKind } from '@/constants' import { FAST_WRITE_RELAY_URLS } from '@/constants' import client from '@/services/client.service' -import { normalizeUrl } from '@/lib/url' +import { normalizeUrl, isLocalNetworkUrl } from '@/lib/url' import { TRelaySet } from '@/types' export interface RelaySelectionContext { @@ -28,6 +28,20 @@ export interface RelaySelectionResult { } class RelaySelectionService { + /** + * Filter out local network relays from other users' relay lists + * We should only use our own local relays, not other users' local relays + */ + private filterLocalRelaysFromOthers(relays: string[], isOwnRelays: boolean = false): string[] { + if (isOwnRelays) { + // For our own relays, keep all of them including local ones + return relays + } + + // For other users' relays, filter out local network relays + return relays.filter(relay => !isLocalNetworkUrl(relay)) + } + /** * Main entry point for relay selection logic */ @@ -65,31 +79,45 @@ class RelaySelectionService { const selectableRelays = new Set() + // Helper function to safely add normalized URLs + const addRelay = (url: string) => { + if (!url) return + const normalized = normalizeUrl(url) + if (normalized) { + selectableRelays.add(normalized) + } else { + // If normalization fails, add the original URL but log a warning + console.warn('Failed to normalize relay URL:', url) + selectableRelays.add(url) + } + } + // Always include user's write relays (or fallback to fast write relays) const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS - userRelays.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) + userRelays.forEach(addRelay) // Always include favorite relays - favoriteRelays.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) + favoriteRelays.forEach(addRelay) // Always include relays from relay sets relaySets.forEach(set => { - set.relayUrls.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) + set.relayUrls.forEach(addRelay) }) // Add contextual relays for replies and public messages if (parentEvent || isPublicMessage) { const contextualRelays = await this.getContextualRelays(context) - contextualRelays.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) + contextualRelays.forEach(addRelay) } // If called with specific relay URLs (e.g., from openFrom), include those if (openFrom && openFrom.length > 0) { - openFrom.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) + openFrom.forEach(addRelay) } - // Filter out blocked relays - return this.filterBlockedRelays(Array.from(selectableRelays).filter(Boolean), context.blockedRelays) + // Filter out blocked relays and return deduplicated list + const deduplicatedRelays = Array.from(selectableRelays).filter(Boolean) + return this.filterBlockedRelays(deduplicatedRelays, context.blockedRelays) } /** @@ -103,11 +131,12 @@ class RelaySelectionService { try { // For replies (any kind) and public messages if (parentEvent || isPublicMessage) { - // Get the replied-to author's read relays + // Get the replied-to author's read relays (filter out their local relays) if (parentEvent) { const authorRelayList = await client.fetchRelayList(parentEvent.pubkey) if (authorRelayList?.read) { - authorRelayList.read.slice(0, 4).forEach(url => contextualRelays.add(url)) + const filteredRelays = this.filterLocalRelaysFromOthers(authorRelayList.read) + filteredRelays.slice(0, 4).forEach(url => contextualRelays.add(url)) } } @@ -142,7 +171,9 @@ class RelaySelectionService { const relayList = await client.fetchRelayList(pubkey) // Use write relays for replies, read relays for public messages const relayType = isPublicMessage ? 'read' : 'write' - return relayList?.[relayType] || [] + const userRelays = relayList?.[relayType] || [] + // Filter out local relays from other users + return this.filterLocalRelaysFromOthers(userRelays) } catch (error) { console.warn(`Failed to fetch relay list for ${pubkey}:`, error) return [] @@ -181,6 +212,8 @@ class RelaySelectionService { // If called with specific relay URLs, use those if (openFrom && openFrom.length > 0) { selectedRelays = openFrom.map(url => normalizeUrl(url) || url).filter(Boolean) + // Deduplicate the selected relays + selectedRelays = Array.from(new Set(selectedRelays)) } // For discussion replies, use relay hint from the kind 11 at the top of the thread else if (parentEvent && (parentEvent.kind === ExtendedKind.DISCUSSION || parentEvent.kind === ExtendedKind.COMMENT)) { @@ -198,6 +231,8 @@ class RelaySelectionService { // Get user's write relays const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS selectedRelays = userRelays.map(url => normalizeUrl(url) || url).filter(Boolean) + // Deduplicate the selected relays + selectedRelays = Array.from(new Set(selectedRelays)) // Add mention relays if (userPubkey) { @@ -221,7 +256,9 @@ class RelaySelectionService { mentionedPubkeys.map(async (pubkey) => { try { const relayList = await client.fetchRelayList(pubkey) - return relayList?.write || [] + const userRelays = relayList?.write || [] + // Filter out local relays from other users + return this.filterLocalRelaysFromOthers(userRelays) } catch (error) { console.warn(`Failed to fetch relay list for ${pubkey}:`, error) return [] @@ -230,6 +267,8 @@ class RelaySelectionService { ) const mentionRelays = mentionRelayLists.flat().map(url => normalizeUrl(url) || url).filter(Boolean) selectedRelays = [...selectedRelays, ...mentionRelays] + // Deduplicate after adding mention relays + selectedRelays = Array.from(new Set(selectedRelays)) } } } @@ -237,6 +276,8 @@ class RelaySelectionService { else { const defaultRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS selectedRelays = defaultRelays.map(url => normalizeUrl(url) || url).filter(Boolean) + // Deduplicate the selected relays + selectedRelays = Array.from(new Set(selectedRelays)) } // Filter out blocked relays @@ -253,7 +294,14 @@ class RelaySelectionService { try { // Add sender's write relays (outboxes) - fallback to fast write relays if no user relays const senderRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS - senderRelays.forEach(url => relays.add(normalizeUrl(url) || url)) + senderRelays.forEach(url => { + const normalized = normalizeUrl(url) + if (normalized) { + relays.add(normalized) + } else { + relays.add(url) + } + }) // Add receiver's read relays (inboxes) if (isPublicMessage && content && userPubkey) { @@ -266,21 +314,38 @@ class RelaySelectionService { mentionedPubkeys.map(async (pubkey) => { try { const relayList = await client.fetchRelayList(pubkey) - return relayList?.read || [] + const userRelays = relayList?.read || [] + // Filter out local relays from other users + return this.filterLocalRelaysFromOthers(userRelays) } catch (error) { console.warn(`Failed to fetch relay list for ${pubkey}:`, error) return [] } }) ) - receiverRelayLists.flat().forEach(url => relays.add(normalizeUrl(url) || url)) + receiverRelayLists.flat().forEach(url => { + const normalized = normalizeUrl(url) + if (normalized) { + relays.add(normalized) + } else { + relays.add(url) + } + }) } } else if (parentEvent && parentEvent.kind === ExtendedKind.PUBLIC_MESSAGE) { - // For public message replies, get original sender's read relays + // For public message replies, get original sender's read relays (filter out their local relays) try { const senderRelayList = await client.fetchRelayList(parentEvent.pubkey) if (senderRelayList?.read) { - senderRelayList.read.forEach(url => relays.add(normalizeUrl(url) || url)) + const filteredRelays = this.filterLocalRelaysFromOthers(senderRelayList.read) + filteredRelays.forEach(url => { + const normalized = normalizeUrl(url) + if (normalized) { + relays.add(normalized) + } else { + relays.add(url) + } + }) } } catch (error) { console.warn(`Failed to fetch relay list for ${parentEvent.pubkey}:`, error)