fix: use subscription for user search
All checks were successful
Release to Staging / build_and_release (push) Successful in 38s

This commit is contained in:
enes 2024-10-30 14:59:44 +01:00
parent 43c8ae4066
commit 4eb8c7d653

View File

@ -4,11 +4,11 @@ import {
NDKKind,
NDKSubscriptionCacheUsage,
NDKUserProfile,
NostrEvent,
profileFromEvent
} from '@nostr-dev-kit/ndk'
import { ErrorBoundary } from 'components/ErrorBoundary'
import { GameCard } from 'components/GameCard'
import { LoadingSpinner } from 'components/LoadingSpinner'
import { ModCard } from 'components/ModCard'
import { ModFilter } from 'components/ModsFilter'
import { Pagination } from 'components/Pagination'
@ -35,10 +35,7 @@ import {
DEFAULT_FILTER_OPTIONS,
extractModData,
isModDataComplete,
log,
LogType,
scrollIntoView,
timeout
scrollIntoView
} from 'utils'
enum SearchKindEnum {
@ -364,48 +361,70 @@ const UsersResult = ({
moderationFilter,
muteLists
}: UsersResultProps) => {
const { fetchEvents } = useNDKContext()
const [isFetching, setIsFetching] = useState(false)
const { ndk } = useNDKContext()
const [profiles, setProfiles] = useState<NDKUserProfile[]>([])
const userState = useAppSelector((state) => state.user)
useEffect(() => {
if (searchTerm === '') {
setProfiles([])
} else {
const fetchProfiles = async () => {
setIsFetching(true)
const filter: NDKFilter = {
const sub = ndk.subscribe(
{
kinds: [NDKKind.Metadata],
search: searchTerm
},
{
closeOnEose: true,
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
},
undefined,
false
)
// Stop the sub after 10 seconds if we are still searching the same term as before
window.setTimeout(() => {
if (sub.filter.search === searchTerm) {
sub.stop()
}
}, 10000)
const profiles = await Promise.race([
fetchEvents(filter),
timeout(10 * 1000)
])
.then((events) => {
const results = events.map((event) => {
const ndkEvent = new NDKEvent(undefined, event)
const profile = profileFromEvent(ndkEvent)
return profile
})
return results
})
.catch((err) => {
log(true, LogType.Error, 'An error occurred in fetching users', err)
return []
})
const onEvent = (event: NostrEvent | NDKEvent) => {
if (!(event instanceof NDKEvent)) event = new NDKEvent(undefined, event)
const dedupKey = event.deduplicationKey()
const existingEvent = events.get(dedupKey)
if (existingEvent) {
event = dedup(existingEvent, event)
}
event.ndk = this
events.set(dedupKey, event)
// We can't rely on the 'eose' to arrive
// Instead we repeat and sort results on each event
const ndkEvents = Array.from(events.values())
const profiles: NDKUserProfile[] = []
ndkEvents.forEach((event) => {
try {
const profile = profileFromEvent(event)
profiles.push(profile)
} catch (error) {
// If we are unable to parse silently skip over the errors
}
})
setProfiles(profiles)
setIsFetching(false)
}
fetchProfiles()
// Clear previous results
const events = new Map<string, NDKEvent>()
// Bind handler and start the sub
sub.on('event', onEvent)
sub.start()
return () => {
sub.stop()
}
}
}, [fetchEvents, searchTerm])
}, [ndk, searchTerm])
const filteredProfiles = useMemo(() => {
let filtered = [...profiles]
@ -430,7 +449,6 @@ const UsersResult = ({
}, [userState.user?.npub, moderationFilter, profiles, muteLists])
return (
<>
{isFetching && <LoadingSpinner desc='Fetching Profiles' />}
<div className='IBMSecMain IBMSMListWrapper'>
<div className='IBMSMList'>
{filteredProfiles.map((profile) => {
@ -505,3 +523,11 @@ const GamesResult = ({ searchTerm }: GamesResultProps) => {
</>
)
}
function dedup(event1: NDKEvent, event2: NDKEvent) {
// return the newest of the two
if (event1.created_at! > event2.created_at!) {
return event1
}
return event2
}