From ffdc6fd0c8fe794bdc3318789b16d115f3f4e6e2 Mon Sep 17 00:00:00 2001 From: codytseng Date: Sat, 24 May 2025 20:42:46 +0800 Subject: [PATCH] feat: cache not found relay lists to avoid redundant queries --- src/services/client.service.ts | 11 +++++-- src/services/indexed-db.service.ts | 50 ++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/services/client.service.ts b/src/services/client.service.ts index 5429c75f..29e9fbf9 100644 --- a/src/services/client.service.ts +++ b/src/services/client.service.ts @@ -723,7 +723,7 @@ class ClientService extends EventTarget { const relayEvents = await indexedDb.getManyReplaceableEvents(pubkeys, kinds.RelayList) const nonExistingPubkeyIndexMap = new Map() pubkeys.forEach((pubkey, i) => { - if (!relayEvents[i]) { + if (relayEvents[i] === undefined) { nonExistingPubkeyIndexMap.set(pubkey, i) } }) @@ -1024,7 +1024,14 @@ class ClientService extends EventTarget { eventsMap.set(pubkey, event) } } - Array.from(eventsMap.values()).forEach((evt) => indexedDb.putReplaceableEvent(evt)) + pubkeys.forEach((pubkey) => { + const event = eventsMap.get(pubkey) + if (event) { + indexedDb.putReplaceableEvent(event) + } else { + indexedDb.putNullReplaceableEvent(pubkey, kinds.RelayList) + } + }) return pubkeys.map((pubkey) => eventsMap.get(pubkey)) } diff --git a/src/services/indexed-db.service.ts b/src/services/indexed-db.service.ts index 6cc3a0f2..caded0b0 100644 --- a/src/services/indexed-db.service.ts +++ b/src/services/indexed-db.service.ts @@ -84,6 +84,45 @@ class IndexedDbService { return this.initPromise } + async putNullReplaceableEvent(pubkey: string, kind: number) { + const storeName = this.getStoreNameByKind(kind) + if (!storeName) { + return Promise.reject('store name not found') + } + await this.initPromise + return new Promise((resolve, reject) => { + if (!this.db) { + return reject('database not initialized') + } + const transaction = this.db.transaction(storeName, 'readwrite') + const store = transaction.objectStore(storeName) + + const getRequest = store.get(pubkey) + getRequest.onsuccess = () => { + const oldValue = getRequest.result as TValue | undefined + if (oldValue) { + transaction.commit() + return resolve(oldValue.value) + } + const putRequest = store.put(this.formatValue(pubkey, null)) + putRequest.onsuccess = () => { + transaction.commit() + resolve(null) + } + + putRequest.onerror = (event) => { + transaction.commit() + reject(event) + } + } + + getRequest.onerror = (event) => { + transaction.commit() + reject(event) + } + }) + } + async putReplaceableEvent(event: Event): Promise { const storeName = this.getStoreNameByKind(event.kind) if (!storeName) { @@ -154,7 +193,7 @@ class IndexedDbService { async getManyReplaceableEvents( pubkeys: readonly string[], kind: number - ): Promise<(Event | undefined)[]> { + ): Promise<(Event | undefined | null)[]> { const storeName = this.getStoreNameByKind(kind) if (!storeName) { return Promise.reject('store name not found') @@ -166,14 +205,14 @@ class IndexedDbService { } const transaction = this.db.transaction(storeName, 'readonly') const store = transaction.objectStore(storeName) - const events: Event[] = new Array(pubkeys.length).fill(undefined) + const events: (Event | null)[] = new Array(pubkeys.length).fill(undefined) let count = 0 pubkeys.forEach((pubkey, i) => { const request = store.get(pubkey) request.onsuccess = () => { - const event = (request.result as TValue)?.value - if (event) { + const event = (request.result as TValue)?.value + if (event || event === null) { events[i] = event } @@ -384,8 +423,7 @@ class IndexedDbService { const cursor = (event.target as IDBRequest).result if (cursor) { const value: TValue = cursor.value - // 10% chance to delete - if (value.addedAt < expirationTimestamp && Math.random() < 0.1) { + if (value.addedAt < expirationTimestamp) { cursor.delete() } cursor.continue()