Browse Source

make relays more efficient

imwald
Silberengel 5 months ago
parent
commit
1df2e61f78
  1. 8
      src/components/QuoteList/index.tsx
  2. 10
      src/components/ReplyNoteList/index.tsx
  3. 16
      src/constants.ts
  4. 27
      src/services/client.service.ts

8
src/components/QuoteList/index.tsx

@ -1,4 +1,4 @@
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants' import { FAST_READ_RELAY_URLS, ExtendedKind } from '@/constants'
import { getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event' import { getReplaceableCoordinateFromEvent, isReplaceableEvent } from '@/lib/event'
import { useNostr } from '@/providers/NostrProvider' import { useNostr } from '@/providers/NostrProvider'
import { useUserTrust } from '@/providers/UserTrustProvider' import { useUserTrust } from '@/providers/UserTrustProvider'
@ -32,14 +32,16 @@ export default function QuoteList({ event, className }: { event: Event; classNam
const relayList = await client.fetchRelayList(event.pubkey) const relayList = await client.fetchRelayList(event.pubkey)
// Include user's mailbox relays for better quote discovery // Include user's mailbox relays for better quote discovery
const userRelays = userRelayList?.read || [] const userRelays = userRelayList?.read || []
const relayUrls = relayList.read.concat(userRelays).concat(BIG_RELAY_URLS) const relayUrls = Array.from(new Set(relayList.read.concat(userRelays).concat(FAST_READ_RELAY_URLS)))
const seenOn = client.getSeenEventRelayUrls(event.id) const seenOn = client.getSeenEventRelayUrls(event.id)
relayUrls.unshift(...seenOn) relayUrls.unshift(...seenOn)
// Deduplicate the final list including seenOn relays
const finalRelayUrls = Array.from(new Set(relayUrls))
const { closer, timelineKey } = await client.subscribeTimeline( const { closer, timelineKey } = await client.subscribeTimeline(
[ [
{ {
urls: relayUrls, urls: finalRelayUrls,
filter: { filter: {
'#q': [ '#q': [
isReplaceableEvent(event.kind) ? getReplaceableCoordinateFromEvent(event) : event.id isReplaceableEvent(event.kind) ? getReplaceableCoordinateFromEvent(event) : event.id

10
src/components/ReplyNoteList/index.tsx

@ -1,4 +1,4 @@
import { BIG_RELAY_URLS, ExtendedKind } from '@/constants' import { FAST_READ_RELAY_URLS, ExtendedKind } from '@/constants'
import { import {
getParentETag, getParentETag,
getReplaceableCoordinateFromEvent, getReplaceableCoordinateFromEvent,
@ -145,7 +145,7 @@ export default function ReplyNoteList({ index, event }: { index?: number; event:
) )
// Include user's mailbox relays for better reply discovery // Include user's mailbox relays for better reply discovery
const userRelays = userRelayList?.read || [] const userRelays = userRelayList?.read || []
const relayUrls = relayList.read.concat(userRelays).concat(BIG_RELAY_URLS) const relayUrls = Array.from(new Set(relayList.read.concat(userRelays).concat(FAST_READ_RELAY_URLS)))
const seenOn = const seenOn =
rootInfo.type === 'E' rootInfo.type === 'E'
? client.getSeenEventRelayUrls(rootInfo.id) ? client.getSeenEventRelayUrls(rootInfo.id)
@ -153,6 +153,8 @@ export default function ReplyNoteList({ index, event }: { index?: number; event:
? client.getSeenEventRelayUrls(rootInfo.eventId) ? client.getSeenEventRelayUrls(rootInfo.eventId)
: [] : []
relayUrls.unshift(...seenOn) relayUrls.unshift(...seenOn)
// Deduplicate the final list including seenOn relays
const finalRelayUrls = Array.from(new Set(relayUrls))
const filters: (Omit<Filter, 'since' | 'until'> & { const filters: (Omit<Filter, 'since' | 'until'> & {
limit: number limit: number
@ -184,7 +186,7 @@ export default function ReplyNoteList({ index, event }: { index?: number; event:
} }
) )
if (rootInfo.relay) { if (rootInfo.relay) {
relayUrls.push(rootInfo.relay) finalRelayUrls.push(rootInfo.relay)
} }
} else { } else {
filters.push({ filters.push({
@ -195,7 +197,7 @@ export default function ReplyNoteList({ index, event }: { index?: number; event:
} }
const { closer, timelineKey } = await client.subscribeTimeline( const { closer, timelineKey } = await client.subscribeTimeline(
filters.map((filter) => ({ filters.map((filter) => ({
urls: relayUrls.slice(0, 5), urls: finalRelayUrls.slice(0, 5),
filter filter
})), })),
{ {

16
src/constants.ts

@ -67,6 +67,22 @@ export const BIG_RELAY_URLS = [
'wss://nostr21.com' 'wss://nostr21.com'
] ]
// Optimized relay list for read operations (includes aggregator)
export const FAST_READ_RELAY_URLS = [
'wss://theforest.nostr1.com',
'wss://orly-relay.imwald.eu',
'wss://nostr.wine',
'wss://aggr.nostr.land'
]
// Optimized relay list for write operations (no aggregator since it's read-only)
export const FAST_WRITE_RELAY_URLS = [
'wss://nostr.wine',
'wss://nostr.land',
'wss://freelay.sovbit.host/',
'wss://thecitadel.nostr1.com/'
]
export const SEARCHABLE_RELAY_URLS = ['wss://relay.nostr.band/', 'wss://freelay.sovbit.host/', 'wss://relay.damus.io/', 'wss://search.nos.today/', 'wss://aggr.nostr.land', 'wss://purplepag.es', 'wss://profiles.nostr1.com'] export const SEARCHABLE_RELAY_URLS = ['wss://relay.nostr.band/', 'wss://freelay.sovbit.host/', 'wss://relay.damus.io/', 'wss://search.nos.today/', 'wss://aggr.nostr.land', 'wss://purplepag.es', 'wss://profiles.nostr1.com']
// Combined relay URLs for profile fetching - includes both BIG_RELAY_URLS and SEARCHABLE_RELAY_URLS // Combined relay URLs for profile fetching - includes both BIG_RELAY_URLS and SEARCHABLE_RELAY_URLS

27
src/services/client.service.ts

@ -1,4 +1,4 @@
import { BIG_RELAY_URLS, ExtendedKind, PROFILE_FETCH_RELAY_URLS } from '@/constants' import { BIG_RELAY_URLS, ExtendedKind, FAST_READ_RELAY_URLS, FAST_WRITE_RELAY_URLS, PROFILE_FETCH_RELAY_URLS } from '@/constants'
import { import {
compareEvents, compareEvents,
getReplaceableCoordinate, getReplaceableCoordinate,
@ -131,20 +131,20 @@ class ClientService extends EventTarget {
} }
const relayList = await this.fetchRelayList(event.pubkey) const relayList = await this.fetchRelayList(event.pubkey)
relays = (relayList?.write.slice(0, 10) ?? []).concat( relays = (relayList?.write.slice(0, 6) ?? []).concat(
Array.from(new Set(_additionalRelayUrls)) ?? [] Array.from(new Set(_additionalRelayUrls)) ?? []
) )
} }
if (!relays.length) { if (!relays.length) {
relays.push(...BIG_RELAY_URLS) relays.push(...FAST_WRITE_RELAY_URLS)
} }
return relays return relays
} }
async publishEvent(relayUrls: string[], event: NEvent) { async publishEvent(relayUrls: string[], event: NEvent) {
const uniqueRelayUrls = Array.from(new Set(relayUrls)) const uniqueRelayUrls = this.optimizeRelaySelection(Array.from(new Set(relayUrls)))
await new Promise<void>((resolve, reject) => { await new Promise<void>((resolve, reject) => {
let successCount = 0 let successCount = 0
let finishedCount = 0 let finishedCount = 0
@ -154,7 +154,7 @@ class ClientService extends EventTarget {
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this const that = this
const relay = await this.pool.ensureRelay(url) const relay = await this.pool.ensureRelay(url)
relay.publishTimeout = 10_000 // 10s relay.publishTimeout = 8_000 // 8s
return relay return relay
.publish(event) .publish(event)
.then(() => { .then(() => {
@ -367,7 +367,7 @@ class ClientService extends EventTarget {
onAllClose?: (reasons: string[]) => void onAllClose?: (reasons: string[]) => void
} }
) { ) {
const relays = Array.from(new Set(urls)) const relays = this.optimizeRelaySelection(Array.from(new Set(urls)))
const filters = Array.isArray(filter) ? filter : [filter] const filters = Array.isArray(filter) ? filter : [filter]
// eslint-disable-next-line @typescript-eslint/no-this-alias // eslint-disable-next-line @typescript-eslint/no-this-alias
@ -386,7 +386,7 @@ class ClientService extends EventTarget {
async function startSub() { async function startSub() {
startedCount++ startedCount++
const relay = await that.pool.ensureRelay(url, { connectionTimeout: 5000 }).catch(() => { const relay = await that.pool.ensureRelay(url, { connectionTimeout: 3000 }).catch(() => {
return undefined return undefined
}) })
// cannot connect to relay // cannot connect to relay
@ -465,7 +465,7 @@ class ClientService extends EventTarget {
} }
return return
}, },
eoseTimeout: 10_000 // 10s eoseTimeout: 8_000 // 8s
}) })
} }
}) })
@ -657,7 +657,7 @@ class ClientService extends EventTarget {
} }
getSeenEventRelayUrls(eventId: string) { getSeenEventRelayUrls(eventId: string) {
return this.getSeenEventRelays(eventId).map((relay) => relay.url) return Array.from(new Set(this.getSeenEventRelays(eventId).map((relay) => relay.url)))
} }
getEventHints(eventId: string) { getEventHints(eventId: string) {
@ -875,7 +875,7 @@ class ClientService extends EventTarget {
} }
private async fetchEventsFromBigRelays(ids: readonly string[]) { private async fetchEventsFromBigRelays(ids: readonly string[]) {
const events = await this.query(PROFILE_FETCH_RELAY_URLS, { const events = await this.query(FAST_READ_RELAY_URLS, {
ids: Array.from(new Set(ids)), ids: Array.from(new Set(ids)),
limit: ids.length limit: ids.length
}) })
@ -1340,6 +1340,13 @@ class ClientService extends EventTarget {
return await this.replaceableEventDataLoader.loadMany(params) return await this.replaceableEventDataLoader.loadMany(params)
} }
// ================= Performance Optimization =================
private optimizeRelaySelection(relays: string[]): string[] {
// Limit to 4 relays for better performance
return relays.slice(0, 4)
}
// ================= Utils ================= // ================= Utils =================
async generateSubRequestsForPubkeys(pubkeys: string[], myPubkey?: string | null) { async generateSubRequestsForPubkeys(pubkeys: string[], myPubkey?: string | null) {

Loading…
Cancel
Save