Skip to content

Instantly share code, notes, and snippets.

@CedricSch
Created June 3, 2021 01:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CedricSch/6265bdce306f6367ec8d9ccbc2c0b7f5 to your computer and use it in GitHub Desktop.
Save CedricSch/6265bdce306f6367ec8d9ccbc2c0b7f5 to your computer and use it in GitHub Desktop.
Exercise 8.1 Http Cache
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