Browse Source

more efficiency fixes

imwald
Silberengel 1 month ago
parent
commit
08c5c71763
  1. 4
      src/components/Sidebar/SidebarCalendarWeekWidget.tsx
  2. 65
      src/providers/FeedProvider.tsx
  3. 10
      src/services/client.service.ts
  4. 52
      src/services/indexed-db.service.ts

4
src/components/Sidebar/SidebarCalendarWeekWidget.tsx

@ -20,7 +20,6 @@ import client from '@/services/client.service' @@ -20,7 +20,6 @@ import client from '@/services/client.service'
import { registerSessionInteractivePrewarmListener } from '@/services/session-interactive-prewarm-bridge'
import indexedDb from '@/services/indexed-db.service'
import { CALENDAR_EVENT_KINDS, ExtendedKind } from '@/constants'
import { appendCuratedReadOnlyRelays } from '@/pages/primary/SpellsPage/fauxSpellFeeds'
import { CalendarDays, ChevronLeft, ChevronRight } from 'lucide-react'
import { type Event } from 'nostr-tools'
import { useCallback, useEffect, useMemo, useReducer, useState } from 'react'
@ -69,7 +68,8 @@ export default function SidebarCalendarWeekWidget() { @@ -69,7 +68,8 @@ export default function SidebarCalendarWeekWidget() {
applySocialKindBlockedFilter: false
}
)
return appendCuratedReadOnlyRelays(base, blockedRelays).slice(0, SIDEBAR_CALENDAR_MAX_RELAYS)
/** Sidebar only: avoid prepending {@link READ_ONLY_RELAY_URLS} so idle shell does not open aggregator sockets. */
return base.slice(0, SIDEBAR_CALENDAR_MAX_RELAYS)
}, [favoriteRelays, blockedRelays, relayList])
const relayKey = useMemo(() => [...relayUrls].sort().join('|'), [relayUrls])

65
src/providers/FeedProvider.tsx

@ -67,7 +67,10 @@ export function FeedProvider({ children }: { children: ReactNode }) { @@ -67,7 +67,10 @@ export function FeedProvider({ children }: { children: ReactNode }) {
[favoriteRelays, relaySets]
)
/** Home Notes/Gallery stay focused: favorites/defaults plus the mixed trending relay. */
/**
* Mixed trending slice (nostrarchives / Wisp-style feed) so the home timeline isnt only the users
* graph keeps a finger on what the wider network is surfacing, alongside favorites / NIP-65.
*/
const primaryExtraRelayUrls = useMemo(() => [buildWispTrendingNotesRelayUrl()], [])
/** Home Replies widen to relays that can surface inbox/reply context. */
@ -182,6 +185,8 @@ export function FeedProvider({ children }: { children: ReactNode }) { @@ -182,6 +185,8 @@ export function FeedProvider({ children }: { children: ReactNode }) {
)
const lastRelayInitDebugKey = useRef('')
const lastHadFavoriteRelaysRef = useRef<boolean | null>(null)
const relayUrlDebounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
useEffect(() => {
const initKey = [
isInitialized ? '1' : '0',
@ -194,29 +199,47 @@ export function FeedProvider({ children }: { children: ReactNode }) { @@ -194,29 +199,47 @@ export function FeedProvider({ children }: { children: ReactNode }) {
replyExtraRelayLayers.httpRelayUrls.length,
blockedRelays.length
].join('\x1e')
if (initKey !== lastRelayInitDebugKey.current) {
lastRelayInitDebugKey.current = initKey
logger.debug('FeedProvider relay init:', {
isInitialized,
favoriteRelays: favoriteRelays.length,
relaySets: relaySets.length,
relaySetRelays: favoriteFeedRelayUrls.length - favoriteRelays.length,
inboxRelays: replyExtraRelayLayers.inboxRelayUrls.length,
outboxRelays: replyExtraRelayLayers.outboxRelayUrls.length,
cacheRelays: replyExtraRelayLayers.cacheRelayUrls.length,
httpRelays: replyExtraRelayLayers.httpRelayUrls.length,
blockedRelays: blockedRelays.length
})
}
const hasFavoriteRelays = favoriteFeedRelayUrls.length > 0
const prevHad = lastHadFavoriteRelaysRef.current
lastHadFavoriteRelaysRef.current = hasFavoriteRelays
if (!hasFavoriteRelays && prevHad !== false) {
logger.debug('FeedProvider: no favorite or relay-set relays, using defaults')
const flush = () => {
if (initKey !== lastRelayInitDebugKey.current) {
lastRelayInitDebugKey.current = initKey
logger.debug('FeedProvider relay init:', {
isInitialized,
favoriteRelays: favoriteRelays.length,
relaySets: relaySets.length,
relaySetRelays: favoriteFeedRelayUrls.length - favoriteRelays.length,
inboxRelays: replyExtraRelayLayers.inboxRelayUrls.length,
outboxRelays: replyExtraRelayLayers.outboxRelayUrls.length,
cacheRelays: replyExtraRelayLayers.cacheRelayUrls.length,
httpRelays: replyExtraRelayLayers.httpRelayUrls.length,
blockedRelays: blockedRelays.length
})
}
const hasFavoriteRelays = favoriteFeedRelayUrls.length > 0
const prevHad = lastHadFavoriteRelaysRef.current
lastHadFavoriteRelaysRef.current = hasFavoriteRelays
if (!hasFavoriteRelays && prevHad !== false) {
logger.debug('FeedProvider: no favorite or relay-set relays, using defaults')
}
updateFeedRelayUrls()
}
updateFeedRelayUrls()
if (relayUrlDebounceTimerRef.current) {
clearTimeout(relayUrlDebounceTimerRef.current)
}
relayUrlDebounceTimerRef.current = setTimeout(() => {
relayUrlDebounceTimerRef.current = null
flush()
}, 80)
return () => {
if (relayUrlDebounceTimerRef.current) {
clearTimeout(relayUrlDebounceTimerRef.current)
relayUrlDebounceTimerRef.current = null
}
}
}, [isInitialized, favoriteRelaysIdentity, blockedRelaysIdentity, replyExtraRelaysIdentity, updateFeedRelayUrls])
return (

10
src/services/client.service.ts

@ -483,7 +483,15 @@ class ClientService extends EventTarget { @@ -483,7 +483,15 @@ class ClientService extends EventTarget {
if (!this.sessionPrewarmBaseCompleted) {
this.sessionPrewarmBaseCompleted = true
fastTasks.push(this.prewarmProfileSearchIndexFromIdb(), this.fetchNip66RelayDiscovery())
fastTasks.push(this.prewarmProfileSearchIndexFromIdb())
/** NIP-66 discovery hits extra relays; defer so first feed/session work is not competing for sockets. */
if (typeof window !== 'undefined') {
window.setTimeout(() => {
void this.fetchNip66RelayDiscovery()
}, 12_000)
} else {
void this.fetchNip66RelayDiscovery()
}
}
if (fastTasks.length === 0 && !options.pubkey) {

52
src/services/indexed-db.service.ts

@ -811,35 +811,53 @@ class IndexedDbService { @@ -811,35 +811,53 @@ class IndexedDbService {
})
}
async iterateProfileEvents(callback: (event: Event) => Promise<void>): Promise<void> {
/**
* Loads all cached kind-0 rows in one synchronous cursor pass (no `await` inside `onsuccess`, which
* would risk inactive transactions), then invokes `callback` in chunks with `requestAnimationFrame`
* yields so FlexSearch indexing does not monopolize the main thread.
*/
async iterateProfileEvents(callback: (event: Event) => void | Promise<void>): Promise<void> {
await this.initPromise
if (!this.db) {
return
}
return new Promise<void>((resolve, reject) => {
const transaction = this.db!.transaction(StoreNames.PROFILE_EVENTS, 'readwrite')
const events = await new Promise<Event[]>((resolve, reject) => {
const out: Event[] = []
const transaction = this.db!.transaction(StoreNames.PROFILE_EVENTS, 'readonly')
const store = transaction.objectStore(StoreNames.PROFILE_EVENTS)
const request = store.openCursor()
request.onsuccess = (event) => {
const cursor = (event.target as IDBRequest).result
if (cursor) {
const value = (cursor.value as TValue<Event>).value
if (value) {
callback(value)
}
cursor.continue()
} else {
transaction.commit()
resolve()
const cursor = (event.target as IDBRequest).result as IDBCursorWithValue | null
if (!cursor) {
resolve(out)
return
}
const value = (cursor.value as TValue<Event>).value
if (value) out.push(value)
cursor.continue()
}
request.onerror = (event) => {
transaction.commit()
reject(event)
request.onerror = () => {
reject(request.error ?? new Error('iterateProfileEvents: cursor failed'))
}
})
const yieldToMain = () =>
new Promise<void>((resolve) => {
if (typeof requestAnimationFrame === 'function') {
requestAnimationFrame(() => resolve())
} else {
setTimeout(resolve, 0)
}
})
const chunkYieldEvery = 150
for (let i = 0; i < events.length; i++) {
await Promise.resolve(callback(events[i]!))
if (i > 0 && (i + 1) % chunkYieldEvery === 0) {
await yieldToMain()
}
}
}
async putFollowingFavoriteRelays(pubkey: string, relays: [string, string[]][]): Promise<void> {

Loading…
Cancel
Save