Browse Source

update relay list only when mentions added or removed

imwald
Silberengel 5 months ago
parent
commit
d30ee3e830
  1. 3
      src/components/PostEditor/Mentions.tsx
  2. 41
      src/components/PostEditor/PostRelaySelector.tsx
  3. 4
      src/constants.ts
  4. 105
      src/services/relay-selection.service.ts

3
src/components/PostEditor/Mentions.tsx

@ -36,7 +36,8 @@ export default function Mentions({ @@ -36,7 +36,8 @@ export default function Mentions({
if (_parentEventPubkey) {
potentialMentions.push(_parentEventPubkey)
}
setPotentialMentions(potentialMentions)
// Deduplicate the potential mentions array
setPotentialMentions(Array.from(new Set(potentialMentions)))
setRemovedPubkeys((pubkeys) => {
return Array.from(
new Set(

41
src/components/PostEditor/PostRelaySelector.tsx

@ -27,13 +27,15 @@ export default function PostRelaySelector({ @@ -27,13 +27,15 @@ export default function PostRelaySelector({
}) {
const { t } = useTranslation()
const { isSmallScreen } = useScreenSize()
const { relayUrls } = useCurrentRelays()
useCurrentRelays() // Keep this hook call for any side effects
const { relaySets, favoriteRelays, blockedRelays } = useFavoriteRelays()
const { pubkey, relayList } = useNostr()
const [selectedRelayUrls, setSelectedRelayUrls] = useState<string[]>([])
const [selectableRelays, setSelectableRelays] = useState<string[]>([])
const [description, setDescription] = useState('')
const [isLoading, setIsLoading] = useState(true)
const [hasManualSelection, setHasManualSelection] = useState(false)
const [previousSelectableCount, setPreviousSelectableCount] = useState(0)
// Use centralized relay selection service
useEffect(() => {
@ -41,7 +43,7 @@ export default function PostRelaySelector({ @@ -41,7 +43,7 @@ export default function PostRelaySelector({
setIsLoading(true)
try {
const result = await relaySelectionService.selectRelays({
userWriteRelays: relayList?.write || relayUrls,
userWriteRelays: relayList?.write || [],
userReadRelays: relayList?.read || [],
favoriteRelays,
blockedRelays,
@ -53,32 +55,59 @@ export default function PostRelaySelector({ @@ -53,32 +55,59 @@ export default function PostRelaySelector({
openFrom
})
const newSelectableCount = result.selectableRelays.length
const selectableRelaysChanged = newSelectableCount !== previousSelectableCount
setSelectableRelays(result.selectableRelays)
setPreviousSelectableCount(newSelectableCount)
// Only update selected relays if:
// 1. User hasn't manually modified them, OR
// 2. New mention relays were added (selectable count changed)
if (!hasManualSelection || selectableRelaysChanged) {
setSelectedRelayUrls(result.selectedRelays)
setDescription(result.description)
// Reset manual selection flag if mentions changed
if (selectableRelaysChanged && hasManualSelection) {
setHasManualSelection(false)
}
}
console.log('PostRelaySelector: Updated relay selection:', result)
} catch (error) {
console.error('Failed to update relay selection:', error)
setSelectableRelays([])
if (!hasManualSelection) {
setSelectedRelayUrls([])
setDescription('No relays selected')
}
} finally {
setIsLoading(false)
}
}
updateRelaySelection()
}, [openFrom, _parentEvent, relayUrls, favoriteRelays, blockedRelays, relaySets, isPublicMessage, postContent, pubkey, relayList])
}, [openFrom, _parentEvent, favoriteRelays, blockedRelays, relaySets, isPublicMessage, postContent, pubkey, relayList, hasManualSelection, previousSelectableCount])
// Update description when selected relays change due to manual selection
useEffect(() => {
if (hasManualSelection && !isLoading) {
const count = selectedRelayUrls.length
setDescription(count === 0 ? 'No relays selected' : count === 1 ? simplifyUrl(selectedRelayUrls[0]) : `${count} relays`)
}
}, [selectedRelayUrls, hasManualSelection, isLoading])
// Update parent component with selected relays
useEffect(() => {
const isProtectedEvent = selectedRelayUrls.length > 0 && !selectedRelayUrls.some(url => relayUrls.includes(url))
// An event is "protected" if we have selected relays that aren't the default user write relays
const userWriteRelays = relayList?.write || []
const isProtectedEvent = selectedRelayUrls.length > 0 && !selectedRelayUrls.every(url => userWriteRelays.includes(url))
setIsProtectedEvent(isProtectedEvent)
setAdditionalRelayUrls(selectedRelayUrls)
}, [selectedRelayUrls, relayUrls, setIsProtectedEvent, setAdditionalRelayUrls])
}, [selectedRelayUrls, relayList, setIsProtectedEvent, setAdditionalRelayUrls])
const handleRelayCheckedChange = useCallback((checked: boolean, url: string) => {
setHasManualSelection(true)
if (checked) {
setSelectedRelayUrls(prev => [...prev, url])
} else {
@ -87,10 +116,12 @@ export default function PostRelaySelector({ @@ -87,10 +116,12 @@ export default function PostRelaySelector({
}, [])
const handleSelectAll = useCallback(() => {
setHasManualSelection(true)
setSelectedRelayUrls([...selectableRelays])
}, [selectableRelays])
const handleClearAll = useCallback(() => {
setHasManualSelection(true)
setSelectedRelayUrls([])
}, [])

4
src/constants.ts

@ -66,7 +66,8 @@ export const BIG_RELAY_URLS = [ @@ -66,7 +66,8 @@ export const BIG_RELAY_URLS = [
'wss://nostr.land',
'wss://nostr.wine',
'wss://nostr.sovbit.host',
'wss://nostr21.com'
'wss://nostr21.com',
'wss://thecitadel.nostr1.com'
]
// Optimized relay list for read operations (includes aggregator)
@ -74,6 +75,7 @@ export const FAST_READ_RELAY_URLS = [ @@ -74,6 +75,7 @@ export const FAST_READ_RELAY_URLS = [
'wss://theforest.nostr1.com',
'wss://orly-relay.imwald.eu',
'wss://nostr.wine',
'wss://thecitadel.nostr1.com',
'wss://aggr.nostr.land'
]

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

@ -99,6 +99,7 @@ class RelaySelectionService { @@ -99,6 +99,7 @@ class RelaySelectionService {
const { parentEvent, isPublicMessage, content, userPubkey } = context
const contextualRelays = new Set<string>()
try {
// For replies (any kind) and public messages
if (parentEvent || isPublicMessage) {
@ -116,17 +117,32 @@ class RelaySelectionService { @@ -116,17 +117,32 @@ class RelaySelectionService {
eventHints.forEach(url => contextualRelays.add(url))
}
// For public messages, also get mentioned users' read relays
if (isPublicMessage && content && userPubkey) {
const mentions = await this.extractMentions(content, parentEvent)
// For replies and public messages, get mentioned users' relays
if (userPubkey) {
let mentions: string[] = []
// Always include parent event author for replies
if (parentEvent) {
mentions.push(parentEvent.pubkey)
}
// Extract additional mentions from content if available
if (content) {
const contentMentions = await this.extractMentions(content, parentEvent)
mentions = [...new Set([...mentions, ...contentMentions])] // deduplicate
}
const mentionedPubkeys = mentions.filter(p => p !== userPubkey)
if (mentionedPubkeys.length > 0) {
const mentionRelayLists = await Promise.all(
mentionedPubkeys.map(async (pubkey) => {
try {
const relayList = await client.fetchRelayList(pubkey)
return relayList?.read || []
// Use write relays for replies, read relays for public messages
const relayType = isPublicMessage ? 'read' : 'write'
return relayList?.[relayType] || []
} catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return []
@ -155,7 +171,9 @@ class RelaySelectionService { @@ -155,7 +171,9 @@ class RelaySelectionService {
userWriteRelays,
parentEvent,
isPublicMessage,
openFrom
openFrom,
content,
userPubkey
} = context
let selectedRelays: string[] = []
@ -177,7 +195,43 @@ class RelaySelectionService { @@ -177,7 +195,43 @@ class RelaySelectionService {
}
// For regular replies, use user's write relays + mention relays
else if (parentEvent && this.isRegularReply(parentEvent)) {
selectedRelays = await this.getRegularReplyRelays(context)
// Get user's write relays
const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS
selectedRelays = userRelays.map(url => normalizeUrl(url) || url).filter(Boolean)
// Add mention relays
if (userPubkey) {
let mentions: string[] = []
// Always include parent event author for replies
if (parentEvent) {
mentions.push(parentEvent.pubkey)
}
// Extract additional mentions from content if available
if (content) {
const contentMentions = await this.extractMentions(content, parentEvent)
mentions = [...new Set([...mentions, ...contentMentions])] // deduplicate
}
const mentionedPubkeys = mentions.filter(p => p !== userPubkey)
if (mentionedPubkeys.length > 0) {
const mentionRelayLists = await Promise.all(
mentionedPubkeys.map(async (pubkey) => {
try {
const relayList = await client.fetchRelayList(pubkey)
return relayList?.write || []
} catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return []
}
})
)
const mentionRelays = mentionRelayLists.flat().map(url => normalizeUrl(url) || url).filter(Boolean)
selectedRelays = [...selectedRelays, ...mentionRelays]
}
}
}
// Default: user's write relays (or fallback to fast write relays if no user relays)
else {
@ -239,44 +293,6 @@ class RelaySelectionService { @@ -239,44 +293,6 @@ class RelaySelectionService {
return Array.from(relays)
}
/**
* Get relays for regular replies: user's write relays + mention relays
*/
private async getRegularReplyRelays(context: RelaySelectionContext): Promise<string[]> {
const { userWriteRelays, parentEvent, content, userPubkey } = context
const relays = new Set<string>()
try {
// Add user's write relays - fallback to fast write relays if no user relays
const userRelays = userWriteRelays.length > 0 ? userWriteRelays : FAST_WRITE_RELAY_URLS
userRelays.forEach(url => relays.add(normalizeUrl(url) || url))
// Add mentioned users' write relays
if (content && userPubkey) {
const mentions = await this.extractMentions(content, parentEvent)
const mentionedPubkeys = mentions.filter(p => p !== userPubkey)
if (mentionedPubkeys.length > 0) {
const mentionRelayLists = await Promise.all(
mentionedPubkeys.map(async (pubkey) => {
try {
const relayList = await client.fetchRelayList(pubkey)
return relayList?.write || []
} catch (error) {
console.warn(`Failed to fetch relay list for ${pubkey}:`, error)
return []
}
})
)
mentionRelayLists.flat().forEach(url => relays.add(normalizeUrl(url) || url))
}
}
} catch (error) {
console.error('Failed to get regular reply relays:', error)
}
return Array.from(relays)
}
/**
* Check if this is a regular reply (Kind 1 or Kind 1111, not to Kind 11)
@ -329,6 +345,7 @@ class RelaySelectionService { @@ -329,6 +345,7 @@ class RelaySelectionService {
/nostr:(npub1[a-z0-9]{58}|nprofile1[a-z0-9]+|note1[a-z0-9]{58}|nevent1[a-z0-9]+)/g
)
if (matches) {
for (const match of matches) {
try {

Loading…
Cancel
Save