feat: Implement caching and rate limiting for API requests

This commit is contained in:
2026-10-18 17:20:29 +03:00
parent 3dc6cc4e9e
commit 6b68cec34a
12 changed files with 282 additions and 27 deletions

View File

@@ -1,13 +1,18 @@
import { readFile, writeFile, mkdir } from "node:fs/promises";
import { fileURLToPath } from "node:url";
import { parseWord, PARSER_VERSION } from "./parser.js";
import { request } from "./source.js";
import { request, MIN_REFRESH } from "./source.js";
const data = fileURLToPath(new URL("../.data/parsed/", import.meta.url));
// When each document was last downloaded, and the downloads under way: a forced refresh
// downloads a document at most once per MIN_REFRESH, and simultaneous ones share a download.
const fetchedAt = new Map(),
loading = new Map();
/** A parsed catalog document, from the disk cache while the file and parser are unchanged. */
export async function scheduleFor(file, { refresh = false } = {}) {
const cache = data + file.id + ".json";
if (refresh && Date.now() - (fetchedAt.get(file.id) || 0) < MIN_REFRESH) refresh = false;
if (!refresh)
try {
const cached = JSON.parse(await readFile(cache, "utf8"));
@@ -17,7 +22,17 @@ export async function scheduleFor(file, { refresh = false } = {}) {
)
return cached;
} catch {}
if (!loading.has(file.id))
loading.set(
file.id,
download(file, cache).finally(() => loading.delete(file.id)),
);
return loading.get(file.id);
}
async function download(file, cache) {
const buffer = await request(file.path);
fetchedAt.set(file.id, Date.now());
const parsed = await parseWord(buffer, {
name: file.name,
url: file.url,