respect cache header

This commit is contained in:
Florian Dold 2020-09-02 12:23:11 +05:30
parent 0ffea74ad5
commit 659e9cdbe6
No known key found for this signature in database
GPG Key ID: D2E4F00F29D02A4B
4 changed files with 42 additions and 4 deletions

View File

@ -43,16 +43,19 @@ import {
WALLET_CACHE_BREAKER_CLIENT_VERSION,
WALLET_EXCHANGE_PROTOCOL_VERSION,
} from "./versions";
import { getTimestampNow, Duration } from "../util/time";
import { getTimestampNow, Duration, isTimestampExpired } from "../util/time";
import { compare } from "../util/libtoolVersion";
import { createRecoupGroup, processRecoupGroup } from "./recoup";
import { TalerErrorCode } from "../TalerErrorCode";
import {
readSuccessResponseJsonOrThrow,
readSuccessResponseTextOrThrow,
getExpiryTimestamp,
} from "../util/http";
import { Logger } from "../util/logging";
import { URL } from "../util/url";
import { reconcileReserveHistory } from "../util/reserveHistoryUtil";
import { checkDbInvariant } from "../util/invariants";
const logger = new Logger("exchanges.ts");
@ -195,6 +198,7 @@ async function updateExchangeWithKeys(
masterPublicKey: exchangeKeysJson.master_public_key,
protocolVersion: protocolVersion,
signingKeys: exchangeKeysJson.signkeys,
nextUpdateTime: getExpiryTimestamp(resp),
};
r.updateStatus = ExchangeUpdateStatus.FetchWire;
r.lastError = undefined;
@ -459,7 +463,7 @@ async function updateExchangeFromUrlImpl(
const now = getTimestampNow();
baseUrl = canonicalizeBaseUrl(baseUrl);
const r = await ws.db.get(Stores.exchanges, baseUrl);
let r = await ws.db.get(Stores.exchanges, baseUrl);
if (!r) {
const newExchangeRecord: ExchangeRecord = {
builtIn: false,
@ -476,7 +480,6 @@ async function updateExchangeFromUrlImpl(
termsOfServiceAcceptedTimestamp: undefined,
termsOfServiceLastEtag: undefined,
termsOfServiceText: undefined,
updateDiff: undefined,
};
await ws.db.put(Stores.exchanges, newExchangeRecord);
} else {
@ -498,6 +501,16 @@ async function updateExchangeFromUrlImpl(
});
}
r = await ws.db.get(Stores.exchanges, baseUrl);
checkDbInvariant(!!r);
const t = r.details?.nextUpdateTime;
if (!forceNow && t && !isTimestampExpired(t)) {
logger.trace("using cached exchange info");
return r;
}
await updateExchangeWithKeys(ws, baseUrl);
await updateExchangeWithWireInfo(ws, baseUrl);
await updateExchangeWithTermsOfService(ws, baseUrl);

View File

@ -539,6 +539,11 @@ export interface ExchangeDetails {
* Timestamp for last update.
*/
lastUpdateTime: Timestamp;
/**
* When should we next update the information about the exchange?
*/
nextUpdateTime: Timestamp;
}
export enum ExchangeUpdateStatus {

View File

@ -26,7 +26,7 @@ import { Codec } from "./codec";
import { OperationFailedError, makeErrorDetails } from "../operations/errors";
import { TalerErrorCode } from "../TalerErrorCode";
import { Logger } from "./logging";
import { Duration } from "./time";
import { Duration, Timestamp, getTimestampNow } from "./time";
const logger = new Logger("http.ts");
@ -253,3 +253,19 @@ export async function readSuccessResponseTextOrThrow<T>(
}
throwUnexpectedRequestError(httpResponse, r.talerErrorResponse);
}
/**
* Get the timestamp at which the response's content is considered expired.
*/
export function getExpiryTimestamp(httpResponse: HttpResponse): Timestamp {
const expiryDateMs = new Date(
httpResponse.headers.get("expiry") ?? "",
).getTime();
if (Number.isNaN(expiryDateMs)) {
return getTimestampNow();
} else {
return {
t_ms: expiryDateMs,
}
}
}

View File

@ -46,6 +46,10 @@ export function getTimestampNow(): Timestamp {
};
}
export function isTimestampExpired(t: Timestamp) {
return timestampCmp(t, getTimestampNow()) <= 0;
}
export function getDurationRemaining(
deadline: Timestamp,
now = getTimestampNow(),