Browse Source

filter out other people's local relays. deduplicate relay list

imwald
Silberengel 5 months ago
parent
commit
6c282bd008
  1. 20
      src/components/PostEditor/PostContent.tsx
  2. 15
      src/components/PostEditor/PostRelaySelector.tsx
  3. 99
      src/services/relay-selection.service.ts

20
src/components/PostEditor/PostContent.tsx

@ -140,17 +140,11 @@ export default function PostContent({
// Extract mentions from content for public messages // Extract mentions from content for public messages
const extractMentionsFromContent = useCallback(async (content: string) => { const extractMentionsFromContent = useCallback(async (content: string) => {
try { try {
// First try to extract nostr: protocol mentions // Extract nostr: protocol mentions
const { pubkeys: nostrPubkeys } = await extractMentions(content, undefined) const { pubkeys: nostrPubkeys } = await extractMentions(content, undefined)
// Also extract regular @ mentions (simple pattern for now) // For now, we'll use the nostr mentions
const atMentions = content.match(/@[a-zA-Z0-9_]+/g) || [] // In a real implementation, you'd also resolve @ mentions to pubkeys
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
setExtractedMentions(nostrPubkeys) setExtractedMentions(nostrPubkeys)
} catch (error) { } catch (error) {
console.error('Error extracting mentions:', error) console.error('Error extracting mentions:', error)
@ -495,13 +489,6 @@ export default function PostContent({
</div> </div>
))} ))}
{!isPoll && ( {!isPoll && (
<>
{console.log('PostContent: Rendering PostRelaySelector with:', {
extractedMentions,
isPublicMessage,
isPoll,
textLength: text.length
})}
<PostRelaySelector <PostRelaySelector
setIsProtectedEvent={setIsProtectedEvent} setIsProtectedEvent={setIsProtectedEvent}
setAdditionalRelayUrls={setAdditionalRelayUrls} setAdditionalRelayUrls={setAdditionalRelayUrls}
@ -511,7 +498,6 @@ export default function PostContent({
isPublicMessage={isPublicMessage} isPublicMessage={isPublicMessage}
mentions={extractedMentions} mentions={extractedMentions}
/> />
</>
)} )}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div className="flex gap-2 items-center"> <div className="flex gap-2 items-center">

15
src/components/PostEditor/PostRelaySelector.tsx

@ -122,24 +122,11 @@ export default function PostRelaySelector({
// Separate effect for mention changes in non-discussion replies // Separate effect for mention changes in non-discussion replies
useEffect(() => { useEffect(() => {
console.log('PostRelaySelector: Mentions effect triggered', { if (isDiscussionReply) return // Skip for discussion replies
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
}
const mentionsChanged = JSON.stringify(mentions) !== JSON.stringify(previousMentions) const mentionsChanged = JSON.stringify(mentions) !== JSON.stringify(previousMentions)
console.log('PostRelaySelector: Mentions changed?', mentionsChanged)
if (mentionsChanged) { if (mentionsChanged) {
console.log('PostRelaySelector: Updating relay selection due to mention changes')
setPreviousMentions(mentions) setPreviousMentions(mentions)
// Update relay selection when mentions change // Update relay selection when mentions change

99
src/services/relay-selection.service.ts

@ -2,7 +2,7 @@ import { Event, kinds } from 'nostr-tools'
import { ExtendedKind } from '@/constants' import { ExtendedKind } from '@/constants'
import { FAST_WRITE_RELAY_URLS } from '@/constants' import { FAST_WRITE_RELAY_URLS } from '@/constants'
import client from '@/services/client.service' import client from '@/services/client.service'
import { normalizeUrl } from '@/lib/url' import { normalizeUrl, isLocalNetworkUrl } from '@/lib/url'
import { TRelaySet } from '@/types' import { TRelaySet } from '@/types'
export interface RelaySelectionContext { export interface RelaySelectionContext {
@ -28,6 +28,20 @@ export interface RelaySelectionResult {
} }
class RelaySelectionService { 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 * Main entry point for relay selection logic
*/ */
@ -65,31 +79,45 @@ class RelaySelectionService {
const selectableRelays = new Set<string>() const selectableRelays = new Set<string>()
// 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) // Always include user's write relays (or fallback to fast write relays)
const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS 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 // Always include favorite relays
favoriteRelays.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) favoriteRelays.forEach(addRelay)
// Always include relays from relay sets // Always include relays from relay sets
relaySets.forEach(set => { relaySets.forEach(set => {
set.relayUrls.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) set.relayUrls.forEach(addRelay)
}) })
// Add contextual relays for replies and public messages // Add contextual relays for replies and public messages
if (parentEvent || isPublicMessage) { if (parentEvent || isPublicMessage) {
const contextualRelays = await this.getContextualRelays(context) 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 called with specific relay URLs (e.g., from openFrom), include those
if (openFrom && openFrom.length > 0) { if (openFrom && openFrom.length > 0) {
openFrom.forEach(url => selectableRelays.add(normalizeUrl(url) || url)) openFrom.forEach(addRelay)
} }
// Filter out blocked relays // Filter out blocked relays and return deduplicated list
return this.filterBlockedRelays(Array.from(selectableRelays).filter(Boolean), context.blockedRelays) const deduplicatedRelays = Array.from(selectableRelays).filter(Boolean)
return this.filterBlockedRelays(deduplicatedRelays, context.blockedRelays)
} }
/** /**
@ -103,11 +131,12 @@ class RelaySelectionService {
try { try {
// For replies (any kind) and public messages // For replies (any kind) and public messages
if (parentEvent || isPublicMessage) { 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) { if (parentEvent) {
const authorRelayList = await client.fetchRelayList(parentEvent.pubkey) const authorRelayList = await client.fetchRelayList(parentEvent.pubkey)
if (authorRelayList?.read) { 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) const relayList = await client.fetchRelayList(pubkey)
// Use write relays for replies, read relays for public messages // Use write relays for replies, read relays for public messages
const relayType = isPublicMessage ? 'read' : 'write' 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) { } catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error) console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return [] return []
@ -181,6 +212,8 @@ class RelaySelectionService {
// If called with specific relay URLs, use those // If called with specific relay URLs, use those
if (openFrom && openFrom.length > 0) { if (openFrom && openFrom.length > 0) {
selectedRelays = openFrom.map(url => normalizeUrl(url) || url).filter(Boolean) 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 // 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)) { else if (parentEvent && (parentEvent.kind === ExtendedKind.DISCUSSION || parentEvent.kind === ExtendedKind.COMMENT)) {
@ -198,6 +231,8 @@ class RelaySelectionService {
// Get user's write relays // Get user's write relays
const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS
selectedRelays = userRelays.map(url => normalizeUrl(url) || url).filter(Boolean) selectedRelays = userRelays.map(url => normalizeUrl(url) || url).filter(Boolean)
// Deduplicate the selected relays
selectedRelays = Array.from(new Set(selectedRelays))
// Add mention relays // Add mention relays
if (userPubkey) { if (userPubkey) {
@ -221,7 +256,9 @@ class RelaySelectionService {
mentionedPubkeys.map(async (pubkey) => { mentionedPubkeys.map(async (pubkey) => {
try { try {
const relayList = await client.fetchRelayList(pubkey) 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) { } catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error) console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return [] return []
@ -230,6 +267,8 @@ class RelaySelectionService {
) )
const mentionRelays = mentionRelayLists.flat().map(url => normalizeUrl(url) || url).filter(Boolean) const mentionRelays = mentionRelayLists.flat().map(url => normalizeUrl(url) || url).filter(Boolean)
selectedRelays = [...selectedRelays, ...mentionRelays] selectedRelays = [...selectedRelays, ...mentionRelays]
// Deduplicate after adding mention relays
selectedRelays = Array.from(new Set(selectedRelays))
} }
} }
} }
@ -237,6 +276,8 @@ class RelaySelectionService {
else { else {
const defaultRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS const defaultRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS
selectedRelays = defaultRelays.map(url => normalizeUrl(url) || url).filter(Boolean) selectedRelays = defaultRelays.map(url => normalizeUrl(url) || url).filter(Boolean)
// Deduplicate the selected relays
selectedRelays = Array.from(new Set(selectedRelays))
} }
// Filter out blocked relays // Filter out blocked relays
@ -253,7 +294,14 @@ class RelaySelectionService {
try { try {
// Add sender's write relays (outboxes) - fallback to fast write relays if no user relays // 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 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) // Add receiver's read relays (inboxes)
if (isPublicMessage && content && userPubkey) { if (isPublicMessage && content && userPubkey) {
@ -266,21 +314,38 @@ class RelaySelectionService {
mentionedPubkeys.map(async (pubkey) => { mentionedPubkeys.map(async (pubkey) => {
try { try {
const relayList = await client.fetchRelayList(pubkey) 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) { } catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error) console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return [] 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) { } 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 { try {
const senderRelayList = await client.fetchRelayList(parentEvent.pubkey) const senderRelayList = await client.fetchRelayList(parentEvent.pubkey)
if (senderRelayList?.read) { 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) { } catch (error) {
console.warn(`Failed to fetch relay list for ${parentEvent.pubkey}:`, error) console.warn(`Failed to fetch relay list for ${parentEvent.pubkey}:`, error)

Loading…
Cancel
Save