diff --git a/index.js b/index.js index e69de29..9f96b88 100644 --- a/index.js +++ b/index.js @@ -0,0 +1,70 @@ +const fetch = require('node-fetch'); +const fs = require('fs'); +const crypto = require('crypto'); +const path = require('path'); + +function md5(str) { + return crypto.createHash('md5').update(str).digest('hex'); +} + +async function getResponse(cacheDirPath, requestArguments, bodyFunctionName) { + const cacheHash = md5(JSON.stringify(requestArguments) + bodyFunctionName); + const cachedFilePath = path.join(cacheDirPath, `${cacheHash}.json`); + + try { + const body = JSON.parse(await fs.promises.readFile(cachedFilePath)); + if (bodyFunctionName === 'buffer') { + return Buffer.from(body); + } + + return body; + } catch (err) { + const fetchResponse = await fetch(...requestArguments); + const bodyResponse = await fetchResponse[bodyFunctionName](); + await fs.promises.writeFile(cachedFilePath, JSON.stringify(bodyResponse)); + return bodyResponse; + } +} + +class ResponseWrapper { + constructor(cacheDirPath, requestArguments) { + this.cacheDirPath = cacheDirPath; + this.requestArguments = requestArguments; + } + + text() { + return getResponse(this.cacheDirPath, this.requestArguments, this.text.name); + } + + json() { + return getResponse(this.cacheDirPath, this.requestArguments, this.json.name); + } + + buffer() { + return getResponse(this.cacheDirPath, this.requestArguments, this.buffer.name); + } + + textConverted() { + return getResponse(this.cacheDirPath, this.requestArguments, this.textConverted.name); + } +} + +function createFetch(cacheDirPath) { + let madeDir = false; + + return async (...args) => { + if (!madeDir) { + try { + await fs.promises.mkdir(cacheDirPath); + } catch (err) { + // Ignore. + } + + madeDir = true; + } + + return new ResponseWrapper(cacheDirPath, args); + }; +} + +module.exports = createFetch; diff --git a/package-lock.json b/package-lock.json index a55dd92..bd90a6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1043,6 +1043,11 @@ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", "dev": true }, + "node-fetch": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", + "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", diff --git a/package.json b/package.json index 10de5c1..9272b3f 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "lint": "./node_modules/.bin/eslint ." + "lint": "./node_modules/.bin/eslint .", + "lintfix": "./node_modules/.bin/eslint . --fix" }, "repository": { "type": "git", @@ -28,5 +29,8 @@ "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.1.0", "eslint-plugin-import": "^2.20.2" + }, + "dependencies": { + "node-fetch": "*" } }