This repository has been archived on 2023-10-27. You can view files and clone it, but cannot push or open issues or pull requests.
node-fetch-cache/index.js

87 lines
2.4 KiB
JavaScript
Raw Normal View History

2020-04-17 20:31:22 +00:00
const fetch = require('node-fetch');
const fs = require('fs');
const { URLSearchParams } = require('url');
2020-04-17 20:31:22 +00:00
const crypto = require('crypto');
const path = require('path');
2020-11-28 04:28:00 +00:00
const Response = require('./classes/response.js');
2020-04-17 20:31:22 +00:00
function md5(str) {
return crypto.createHash('md5').update(str).digest('hex');
}
function getBodyCacheKeyJson(body) {
2020-11-28 16:25:23 +00:00
if (!body) {
return body;
} if (typeof body === 'string') {
return body;
} if (body instanceof URLSearchParams) {
return body.toString();
2020-11-28 16:25:23 +00:00
} if (body instanceof fs.ReadStream) {
return body.path;
}
2020-11-28 16:25:23 +00:00
throw new Error('Unsupported body type');
}
function getCacheKey(requestArguments) {
const resource = requestArguments[0];
const init = requestArguments[1] || {};
const resourceCacheKeyJson = typeof resource === 'string' ? { url: resource } : { ...resource };
const initCacheKeyJson = { ...init };
resourceCacheKeyJson.body = getBodyCacheKeyJson(resourceCacheKeyJson.body);
initCacheKeyJson.body = getBodyCacheKeyJson(initCacheKeyJson.body);
return md5(JSON.stringify([resourceCacheKeyJson, initCacheKeyJson]));
}
async function createRawResponse(fetchRes) {
const buffer = await fetchRes.buffer();
2020-11-28 03:26:31 +00:00
const rawHeaders = Array.from(fetchRes.headers.entries())
.reduce((aggregate, entry) => ({ ...aggregate, [entry[0]]: entry[1] }), {});
return {
status: fetchRes.status,
statusText: fetchRes.statusText,
type: fetchRes.type,
url: fetchRes.url,
ok: fetchRes.ok,
2020-11-28 03:26:31 +00:00
headers: rawHeaders,
redirected: fetchRes.redirected,
bodyBuffer: buffer,
};
}
async function getResponse(cacheDirPath, requestArguments) {
const cacheKey = getCacheKey(requestArguments);
const cachedFilePath = path.join(cacheDirPath, `${cacheKey}.json`);
try {
const rawResponse = JSON.parse(await fs.promises.readFile(cachedFilePath));
2020-11-28 03:26:31 +00:00
return new Response(rawResponse, cachedFilePath, true);
} catch (err) {
const fetchResponse = await fetch(...requestArguments);
2020-11-28 03:26:31 +00:00
const rawResponse = await createRawResponse(fetchResponse);
await fs.promises.writeFile(cachedFilePath, JSON.stringify(rawResponse));
2020-11-28 03:26:31 +00:00
return new Response(rawResponse, cachedFilePath, false);
2020-04-17 20:31:22 +00:00
}
}
function createFetch(cacheDirPath) {
let madeDir = false;
return async (...args) => {
if (!madeDir) {
await fs.promises.mkdir(cacheDirPath, { recursive: true });
2020-04-17 20:31:22 +00:00
madeDir = true;
}
return getResponse(cacheDirPath, args);
2020-04-17 20:31:22 +00:00
};
}
module.exports = createFetch;