Browse Source

make relay service more efficient

imwald
Silberengel 2 months ago
parent
commit
744c1c68c8
  1. 6
      Dockerfile
  2. 143
      src/services/client.service.ts

6
Dockerfile

@ -34,8 +34,10 @@ RUN printf "server {\n\ @@ -34,8 +34,10 @@ RUN printf "server {\n\
}\n\
\n\
location / {\n\
# For scrapers, serve index.html (they'll see static meta tags)\n\
# Note: To get dynamic meta tags, you need SSR or a meta tag service\n\
# For scrapers, always serve index.html so they see static og/twitter meta tags\n\
if (\$is_scraper = 1) {\n\
rewrite ^ /index.html last;\n\
}\n\
try_files \$uri \$uri/ /index.html;\n\
}\n\
\n\

143
src/services/client.service.ts

@ -65,10 +65,6 @@ class ClientService extends EventTarget { @@ -65,10 +65,6 @@ class ClientService extends EventTarget {
tokenize: 'forward'
})
/** Min delay between starting subscriptions to the same relay to avoid hammering one relay with many REQs */
private static readonly PER_RELAY_SUB_STAGGER_MS = 80
private lastSubStartByRelay = new Map<string, number>()
constructor() {
super()
this.pool = new SimplePool()
@ -650,110 +646,35 @@ class ClientService extends EventTarget { @@ -650,110 +646,35 @@ class ClientService extends EventTarget {
// eslint-disable-next-line @typescript-eslint/no-this-alias
const that = this
const _knownIds = new Set<string>()
let startedCount = 0
let eosedCount = 0
let eosed = false
let closedCount = 0
const closeReasons: string[] = []
const subPromises: Promise<{ close: () => void }>[] = []
const staggerMs = ClientService.PER_RELAY_SUB_STAGGER_MS
relays.forEach((url) => {
let hasAuthed = false
subPromises.push(startSub())
async function startSub() {
const relayKey = normalizeUrl(url) || url
const now = Date.now()
const last = that.lastSubStartByRelay.get(relayKey) ?? 0
const wait = staggerMs - (now - last)
if (wait > 0) {
await new Promise<void>((r) => setTimeout(r, wait))
}
that.lastSubStartByRelay.set(relayKey, Date.now())
startedCount++
const relay = await that.pool.ensureRelay(url, { connectionTimeout: 5000 }).catch(() => {
return undefined
})
// cannot connect to relay
if (!relay) {
if (!eosed) {
eosedCount++
eosed = eosedCount >= startedCount
oneose?.(eosed)
}
return {
close: () => {}
}
}
return relay.subscribe(filters, {
receivedEvent: (relay, id) => {
that.trackEventSeenOn(id, relay)
},
alreadyHaveEvent: (id: string) => {
const have = _knownIds.has(id)
if (have) {
return true
}
_knownIds.add(id)
return false
},
onevent: (evt: NEvent) => {
onevent?.(evt)
},
oneose: () => {
// make sure eosed is not called multiple times
if (eosed) return
eosedCount++
eosed = eosedCount >= startedCount
oneose?.(eosed)
},
onclose: (reason: string) => {
// auth-required
if (reason.startsWith('auth-required') && !hasAuthed) {
// already logged in
if (that.signer) {
relay
.auth(async (authEvt: EventTemplate) => {
const evt = await that.signer!.signEvent(authEvt)
if (!evt) {
throw new Error('sign event failed')
}
return evt as VerifiedEvent
})
.then(() => {
hasAuthed = true
if (!eosed) {
subPromises.push(startSub())
}
})
.catch(() => {
// ignore
})
return
}
// open login dialog
if (startLogin) {
startLogin()
return
}
}
// One request per (relay, filter) so pool groups by relay and sends one REQ per relay with all filters
const requests = relays.flatMap((url) =>
filters.map((f) => ({ url: normalizeUrl(url) || url, filter: f }))
)
// close the subscription
closedCount++
closeReasons.push(reason)
onclose?.(url, reason)
if (closedCount >= startedCount) {
onAllClose?.(closeReasons)
}
return
},
eoseTimeout: 10_000 // 10s
})
}
const poolCloser = this.pool.subscribeMap(requests, {
onevent: (evt: NEvent) => onevent?.(evt),
oneose: () => oneose?.(true),
onclose: (reasons: string[]) => {
relays.forEach((url, i) => onclose?.(url, reasons[i] ?? ''))
onAllClose?.(reasons)
},
onauth: async (authEvt: EventTemplate) => {
if (that.signer) {
const evt = await that.signer.signEvent(authEvt)
if (!evt) throw new Error('sign event failed')
return evt as VerifiedEvent
}
startLogin?.()
throw new Error('Login required')
},
alreadyHaveEvent: (id: string) => {
const have = _knownIds.has(id)
if (have) return true
_knownIds.add(id)
return false
},
eoseTimeout: 10_000
})
const handleNewEventFromInternal = (data: Event) => {
@ -774,15 +695,7 @@ class ClientService extends EventTarget { @@ -774,15 +695,7 @@ class ClientService extends EventTarget {
return {
close: () => {
this.removeEventListener('newEvent', handleNewEventFromInternal)
subPromises.forEach((subPromise) => {
subPromise
.then((sub) => {
sub.close()
})
.catch(() => {
// Silent fail
})
})
poolCloser.close()
}
}
}

Loading…
Cancel
Save