summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-core/src/wallet.ts
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2024-04-08 21:27:33 +0200
committerFlorian Dold <florian@dold.me>2024-04-08 21:27:33 +0200
commit30dea85f1e2410f974f8c16e4e53d4ba1290442d (patch)
tree735a68e1ccdd559adc220b800caea565c0cc7fbe /packages/taler-wallet-core/src/wallet.ts
parent85b6213333b211bbfae9209630d8446108c4ce56 (diff)
downloadwallet-core-30dea85f1e2410f974f8c16e4e53d4ba1290442d.tar.gz
wallet-core-30dea85f1e2410f974f8c16e4e53d4ba1290442d.tar.bz2
wallet-core-30dea85f1e2410f974f8c16e4e53d4ba1290442d.zip
wallet-core: perf, caching
Diffstat (limited to 'packages/taler-wallet-core/src/wallet.ts')
-rw-r--r--packages/taler-wallet-core/src/wallet.ts81
1 files changed, 66 insertions, 15 deletions
diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts
index 2bafba3af..223272745 100644
--- a/packages/taler-wallet-core/src/wallet.ts
+++ b/packages/taler-wallet-core/src/wallet.ts
@@ -24,7 +24,9 @@
*/
import { IDBFactory } from "@gnu-taler/idb-bridge";
import {
+ AbsoluteTime,
ActiveTask,
+ AmountJson,
AmountString,
Amounts,
AsyncCondition,
@@ -35,6 +37,7 @@ import {
CreateStoredBackupResponse,
DeleteStoredBackupRequest,
DenominationInfo,
+ Duration,
ExchangesShortListResponse,
GetCurrencySpecificationResponse,
InitResponse,
@@ -193,6 +196,7 @@ import {
} from "./deposits.js";
import { DevExperimentHttpLib, applyDevExperiment } from "./dev-experiments.js";
import {
+ ReadyExchangeSummary,
acceptExchangeTermsOfService,
addPresetExchangeEntry,
deleteExchange,
@@ -356,15 +360,15 @@ export async function getDenomInfo(
exchangeBaseUrl: string,
denomPubHash: string,
): Promise<DenominationInfo | undefined> {
- const key = `${exchangeBaseUrl}:${denomPubHash}`;
- const cached = wex.ws.lookupDenomCache(key);
+ const cacheKey = `${exchangeBaseUrl}:${denomPubHash}`;
+ const cached = wex.ws.denomInfoCache.get(cacheKey);
if (cached) {
return cached;
}
const d = await tx.denominations.get([exchangeBaseUrl, denomPubHash]);
if (d) {
const denomInfo = DenominationRecord.toDenomInfo(d);
- wex.ws.putDenomCache(key, denomInfo);
+ wex.ws.denomInfoCache.put(cacheKey, denomInfo);
return denomInfo;
}
return undefined;
@@ -794,6 +798,9 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
});
return {};
}
+ case WalletApiOperation.TestingPing: {
+ return {};
+ }
case WalletApiOperation.UpdateExchangeEntry: {
const req = codecForUpdateExchangeEntryRequest().decode(payload);
await fetchFreshExchange(wex, req.exchangeBaseUrl, {
@@ -1275,6 +1282,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
if (existingRec) {
return;
}
+ wex.ws.exchangeCache.clear();
await tx.globalCurrencyExchanges.add({
currency: req.currency,
exchangeBaseUrl: req.exchangeBaseUrl,
@@ -1294,6 +1302,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
if (!existingRec) {
return;
}
+ wex.ws.exchangeCache.clear();
checkDbInvariant(!!existingRec.id);
await tx.globalCurrencyExchanges.delete(existingRec.id);
});
@@ -1315,6 +1324,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
auditorBaseUrl: req.auditorBaseUrl,
auditorPub: req.auditorPub,
});
+ wex.ws.exchangeCache.clear();
});
return {};
}
@@ -1331,6 +1341,7 @@ async function dispatchRequestInternal<Op extends WalletApiOperation>(
}
checkDbInvariant(!!existingRec.id);
await tx.globalCurrencyAuditors.delete(existingRec.id);
+ wex.ws.exchangeCache.clear();
});
return {};
}
@@ -1664,6 +1675,44 @@ export interface DevExperimentState {
blockRefreshes?: boolean;
}
+export class Cache<T> {
+ private map: Map<string, [AbsoluteTime, T]> = new Map();
+
+ constructor(
+ private maxCapacity: number,
+ private cacheDuration: Duration,
+ ) {}
+
+ get(key: string): T | undefined {
+ const r = this.map.get(key);
+ if (!r) {
+ return undefined;
+ }
+
+ if (AbsoluteTime.isExpired(r[0])) {
+ this.map.delete(key);
+ return undefined;
+ }
+
+ return r[1];
+ }
+
+ clear(): void {
+ this.map.clear();
+ }
+
+ put(key: string, value: T): void {
+ if (this.map.size > this.maxCapacity) {
+ this.map.clear();
+ }
+ const expiry = AbsoluteTime.addDuration(
+ AbsoluteTime.now(),
+ this.cacheDuration,
+ );
+ this.map.set(key, [expiry, value]);
+ }
+}
+
/**
* Internal state of the wallet.
*
@@ -1681,7 +1730,20 @@ export class InternalWalletState {
initCalled = false;
- private denomCache: Map<string, DenominationInfo> = new Map();
+ refreshCostCache: Cache<AmountJson> = new Cache(
+ 1000,
+ Duration.fromSpec({ minutes: 1 }),
+ );
+
+ denomInfoCache: Cache<DenominationInfo> = new Cache(
+ 1000,
+ Duration.fromSpec({ minutes: 1 }),
+ );
+
+ exchangeCache: Cache<ReadyExchangeSummary> = new Cache(
+ 1000,
+ Duration.fromSpec({ minutes: 1 }),
+ );
/**
* Promises that are waiting for a particular resource.
@@ -1710,17 +1772,6 @@ export class InternalWalletState {
devExperimentState: DevExperimentState = {};
- lookupDenomCache(denomCacheKey: string): DenominationInfo | undefined {
- return this.denomCache.get(denomCacheKey);
- }
-
- putDenomCache(denomCacheKey: string, denomInfo: DenominationInfo): void {
- if (this.denomCache.size > 1000) {
- this.denomCache.clear();
- }
- this.denomCache.set(denomCacheKey, denomInfo);
- }
-
initWithConfig(newConfig: WalletRunConfig): void {
this._config = newConfig;