diff --git a/packages/app/src/Cache/UserCache.ts b/packages/app/src/Cache/UserCache.ts index ae083339..ab6feade 100644 --- a/packages/app/src/Cache/UserCache.ts +++ b/packages/app/src/Cache/UserCache.ts @@ -107,50 +107,68 @@ class UserProfileCache extends FeedCache { } async #processZapperQueue() { - while (this.#zapperQueue.length > 0) { - const i = this.#zapperQueue.shift(); - if (i) { - try { - const svc = new LNURL(i.lnurl); - await svc.load(); - const p = this.getFromCache(i.pubkey); - if (p) { - this.#setItem({ - ...p, - zapService: svc.zapperPubkey, - }); - } - } catch { - console.warn("Failed to load LNURL for zapper pubkey", i.lnurl); + await this.#batchQueue( + this.#zapperQueue, + async i => { + const svc = new LNURL(i.lnurl); + await svc.load(); + const p = this.getFromCache(i.pubkey); + if (p) { + this.#setItem({ + ...p, + zapService: svc.zapperPubkey, + }); } - } - } + }, + 5 + ); setTimeout(() => this.#processZapperQueue(), 1_000); } async #processNip5Queue() { - while (this.#nip5Queue.length > 0) { - const i = this.#nip5Queue.shift(); - if (i) { - try { - const [name, domain] = i.nip05.split("@"); - const nip5pk = await fetchNip05Pubkey(name, domain); - const p = this.getFromCache(i.pubkey); - if (p) { - this.#setItem({ - ...p, - isNostrAddressValid: i.pubkey === nip5pk, - }); - } - } catch { - console.warn("Failed to load nip-05", i.nip05); + await this.#batchQueue( + this.#nip5Queue, + async i => { + const [name, domain] = i.nip05.split("@"); + const nip5pk = await fetchNip05Pubkey(name, domain); + const p = this.getFromCache(i.pubkey); + if (p) { + this.#setItem({ + ...p, + isNostrAddressValid: i.pubkey === nip5pk, + }); } - } - } + }, + 5 + ); setTimeout(() => this.#processNip5Queue(), 1_000); } + + async #batchQueue(queue: Array, proc: (v: T) => Promise, batchSize = 3) { + const batch = []; + while (queue.length > 0) { + const i = queue.shift(); + if (i) { + batch.push( + (async () => { + try { + await proc(i); + } catch { + console.warn("Failed to process item", i); + } + batch.pop(); // pop any + })() + ); + if (batch.length === batchSize) { + await Promise.all(batch); + } + } else { + await Promise.all(batch); + } + } + } } export const UserCache = new UserProfileCache(); diff --git a/packages/app/src/Nip05/Verifier.ts b/packages/app/src/Nip05/Verifier.ts index 43f96d67..5d02204f 100644 --- a/packages/app/src/Nip05/Verifier.ts +++ b/packages/app/src/Nip05/Verifier.ts @@ -6,12 +6,14 @@ interface NostrJson { names: Record; } -export async function fetchNip05Pubkey(name: string, domain: string) { +export async function fetchNip05Pubkey(name: string, domain: string, timeout = 2_000) { if (!name || !domain) { return undefined; } try { - const res = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(name)}`); + const res = await fetch(`https://${domain}/.well-known/nostr.json?name=${encodeURIComponent(name)}`, { + signal: AbortSignal.timeout(timeout), + }); const data: NostrJson = await res.json(); const match = Object.keys(data.names).find(n => { return n.toLowerCase() === name.toLowerCase();