Created
June 3, 2021 01:00
-
-
Save CedricSch/6265bdce306f6367ec8d9ccbc2c0b7f5 to your computer and use it in GitHub Desktop.
Exercise 8.1 Http Cache
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import https from "https"; | |
import { createHash, randomInt } from "crypto"; | |
import { PassThrough, Readable } from "stream"; | |
import { promises as fs } from "fs"; | |
/** | |
* | |
* Please feel free to inform me about a better solution. | |
* | |
*/ | |
function createObjectHash(obj) { | |
// Good enough for this | |
const hash = createHash("MD5"); | |
const value = JSON.stringify(obj); | |
return hash.update(value).digest("hex"); | |
} | |
function createCacheProxy(target, cache) { | |
return new Proxy(target, { | |
get: function (target, propertyName) { | |
if (propertyName === "get" && typeof target[propertyName] === "function") { | |
return function (...args) { | |
const properties = { url: args[0] }; | |
const originalCallback = args.slice(-1)[0]; | |
if(args.length > 2 && typeof args[1] === "object" && args[1]["headers"] !== undefined) { | |
properties["headers"] = args[1]["headers"]; | |
} | |
const hash = createObjectHash(properties); | |
if (cache.has(hash)) { | |
console.log(`Cache hit for url: ${properties.url}`); | |
const cachedObject = cache.get(hash); | |
const cachedContent = Readable.from([cachedObject.body]) | |
originalCallback(cachedContent); | |
return cachedObject.clientRequest; | |
} | |
// Split stream and and save body in cache | |
const dataMonitor = new PassThrough(); | |
let body = ""; | |
dataMonitor.on("data", (chunk) => { | |
body += chunk; | |
}) | |
dataMonitor.on("end", () => { | |
cache.set(hash, { body, clientRequest }) | |
}) | |
const clientRequest = target.get(...args.slice(0, -1), (res) => { | |
res.pipe(dataMonitor); | |
return originalCallback(res); | |
}); | |
return clientRequest; | |
} | |
} | |
return target[propertyName]; | |
} | |
}) | |
} | |
// Test stuff | |
const cache = new Map(); | |
const cachedHttps = createCacheProxy(https, cache); | |
const host = "www.reddit.com"; | |
for (let i = 0; i < 10; i++) { | |
setTimeout(() => { | |
const client = cachedHttps.get(`https://${host}`, (res) => { | |
let body = ""; | |
res.on("data", (chunk) => { | |
body += chunk; | |
}) | |
res.on("end", () => { | |
fs.writeFile(`data/get_${host}_${i}.html`, body) | |
.then( (content) => { | |
console.log("Body saved.") | |
console.log(cache.size) | |
}) | |
.catch( (err) => { | |
console.error(err); | |
}) | |
}) | |
}); | |
}, i * 3000) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment