|
|
|
@ -2,8 +2,10 @@ import NormalFeed from '@/components/NormalFeed' |
|
|
|
import { checkAlgoRelay } from '@/lib/relay' |
|
|
|
import { checkAlgoRelay } from '@/lib/relay' |
|
|
|
import logger from '@/lib/logger' |
|
|
|
import logger from '@/lib/logger' |
|
|
|
import { useFeed } from '@/providers/FeedProvider' |
|
|
|
import { useFeed } from '@/providers/FeedProvider' |
|
|
|
|
|
|
|
import { useKindFilter } from '@/providers/KindFilterProvider' |
|
|
|
import relayInfoService from '@/services/relay-info.service' |
|
|
|
import relayInfoService from '@/services/relay-info.service' |
|
|
|
import React, { useEffect, useMemo, useState } from 'react' |
|
|
|
import { kinds } from 'nostr-tools' |
|
|
|
|
|
|
|
import React, { useEffect, useMemo, useState, useRef } from 'react' |
|
|
|
|
|
|
|
|
|
|
|
export default function RelaysFeed({ |
|
|
|
export default function RelaysFeed({ |
|
|
|
setSubHeader |
|
|
|
setSubHeader |
|
|
|
@ -12,30 +14,32 @@ export default function RelaysFeed({ |
|
|
|
}) { |
|
|
|
}) { |
|
|
|
logger.debug('RelaysFeed component rendering') |
|
|
|
logger.debug('RelaysFeed component rendering') |
|
|
|
const { feedInfo, relayUrls } = useFeed() |
|
|
|
const { feedInfo, relayUrls } = useFeed() |
|
|
|
const [isReady, setIsReady] = useState(false) |
|
|
|
const { showKinds } = useKindFilter() |
|
|
|
const [areAlgoRelays, setAreAlgoRelays] = useState(false) |
|
|
|
const [areAlgoRelays, setAreAlgoRelays] = useState(false) |
|
|
|
|
|
|
|
const relayInfoFetchedRef = useRef(false) |
|
|
|
|
|
|
|
|
|
|
|
// Debug logging
|
|
|
|
// Debug logging
|
|
|
|
logger.debug('RelaysFeed debug:', { |
|
|
|
logger.debug('RelaysFeed debug:', { |
|
|
|
feedInfo, |
|
|
|
feedInfo, |
|
|
|
relayUrls, |
|
|
|
relayUrls: relayUrls.length, |
|
|
|
isReady |
|
|
|
showKinds: showKinds.length |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fetch relay info in background (non-blocking) - don't wait for it to render
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
// Only fetch once per relayUrls change
|
|
|
|
|
|
|
|
if (relayInfoFetchedRef.current || relayUrls.length === 0) { |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const init = async () => { |
|
|
|
const init = async () => { |
|
|
|
// If relayUrls is empty, we can't initialize the feed
|
|
|
|
relayInfoFetchedRef.current = true |
|
|
|
if (relayUrls.length === 0) { |
|
|
|
|
|
|
|
logger.debug('RelaysFeed: relayUrls is empty, not initializing') |
|
|
|
|
|
|
|
setIsReady(false) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Add timeout to prevent hanging if getRelayInfos is slow
|
|
|
|
// Add aggressive timeout to prevent hanging (reduced from 5s to 2s)
|
|
|
|
const timeoutPromise = new Promise<never>((_, reject) => { |
|
|
|
const timeoutPromise = new Promise<never>((_, reject) => { |
|
|
|
setTimeout(() => { |
|
|
|
setTimeout(() => { |
|
|
|
reject(new Error('getRelayInfos timeout after 5 seconds')) |
|
|
|
reject(new Error('getRelayInfos timeout after 2 seconds')) |
|
|
|
}, 5000) |
|
|
|
}, 2000) |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
@ -43,39 +47,64 @@ export default function RelaysFeed({ |
|
|
|
relayInfoService.getRelayInfos(relayUrls), |
|
|
|
relayInfoService.getRelayInfos(relayUrls), |
|
|
|
timeoutPromise |
|
|
|
timeoutPromise |
|
|
|
]) |
|
|
|
]) |
|
|
|
setAreAlgoRelays(relayInfos.every((relayInfo) => checkAlgoRelay(relayInfo))) |
|
|
|
const areAlgo = relayInfos.every((relayInfo) => checkAlgoRelay(relayInfo)) |
|
|
|
setIsReady(true) |
|
|
|
setAreAlgoRelays(areAlgo) |
|
|
|
logger.debug('RelaysFeed: Initialized successfully', { |
|
|
|
logger.debug('RelaysFeed: Relay info fetched successfully', { |
|
|
|
relayCount: relayUrls.length, |
|
|
|
relayCount: relayUrls.length, |
|
|
|
areAlgoRelays: relayInfos.every((relayInfo) => checkAlgoRelay(relayInfo)) |
|
|
|
areAlgoRelays: areAlgo |
|
|
|
}) |
|
|
|
}) |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
logger.warn('RelaysFeed: Failed to get relay infos, proceeding anyway', { |
|
|
|
logger.debug('RelaysFeed: Failed to get relay infos (non-blocking)', { |
|
|
|
error: error instanceof Error ? error.message : String(error), |
|
|
|
error: error instanceof Error ? error.message : String(error), |
|
|
|
relayUrls |
|
|
|
relayUrls: relayUrls.length |
|
|
|
}) |
|
|
|
}) |
|
|
|
// Proceed anyway - we can still show the feed even without relay info
|
|
|
|
// Default to false - feed will work without this info
|
|
|
|
setAreAlgoRelays(false) |
|
|
|
setAreAlgoRelays(false) |
|
|
|
setIsReady(true) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
init() |
|
|
|
|
|
|
|
|
|
|
|
// Don't await - let it run in background
|
|
|
|
|
|
|
|
init().catch((err) => { |
|
|
|
|
|
|
|
logger.debug('RelaysFeed: Unhandled error in init', { error: err }) |
|
|
|
|
|
|
|
setAreAlgoRelays(false) |
|
|
|
|
|
|
|
}) |
|
|
|
}, [relayUrls]) |
|
|
|
}, [relayUrls]) |
|
|
|
|
|
|
|
|
|
|
|
// Memoize subRequests before any early returns to avoid Rules of Hooks violation
|
|
|
|
// Reset fetch flag when relayUrls change
|
|
|
|
const subRequests = useMemo(() => [{ urls: relayUrls, filter: {} }], [relayUrls]) |
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
relayInfoFetchedRef.current = false |
|
|
|
|
|
|
|
}, [relayUrls]) |
|
|
|
|
|
|
|
|
|
|
|
if (!isReady) { |
|
|
|
// Early returns for invalid feed types
|
|
|
|
|
|
|
|
if (feedInfo.feedType !== 'relay' && feedInfo.feedType !== 'relays' && feedInfo.feedType !== 'all-favorites') { |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (feedInfo.feedType !== 'relay' && feedInfo.feedType !== 'relays' && feedInfo.feedType !== 'all-favorites') { |
|
|
|
// CRITICAL: Don't render feed if relayUrls is empty - this would cause subscription to fail
|
|
|
|
|
|
|
|
if (relayUrls.length === 0) { |
|
|
|
|
|
|
|
logger.debug('RelaysFeed: relayUrls is empty, not rendering feed') |
|
|
|
return null |
|
|
|
return null |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CRITICAL: Provide proper filter with default kinds - NoteList requires kinds in filter
|
|
|
|
|
|
|
|
// Use showKinds from KindFilterProvider if available, otherwise default to kind 1
|
|
|
|
|
|
|
|
const defaultKinds = showKinds.length > 0 ? showKinds : [kinds.ShortTextNote] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Memoize subRequests with proper filter - this ensures NoteList gets valid filter
|
|
|
|
|
|
|
|
const subRequests = useMemo(() => { |
|
|
|
|
|
|
|
return [{ |
|
|
|
|
|
|
|
urls: relayUrls, |
|
|
|
|
|
|
|
filter: { |
|
|
|
|
|
|
|
kinds: defaultKinds |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}] |
|
|
|
|
|
|
|
}, [relayUrls, defaultKinds]) |
|
|
|
|
|
|
|
|
|
|
|
logger.component('RelaysFeed', 'Rendering NormalFeed', {
|
|
|
|
logger.component('RelaysFeed', 'Rendering NormalFeed', {
|
|
|
|
subRequests: subRequests.length,
|
|
|
|
subRequests: subRequests.length,
|
|
|
|
relayUrls: relayUrls.length,
|
|
|
|
relayUrls: relayUrls.length,
|
|
|
|
areAlgoRelays
|
|
|
|
areAlgoRelays, |
|
|
|
|
|
|
|
filterKinds: subRequests[0]?.filter?.kinds?.length || 0 |
|
|
|
}) |
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
|