Browse Source

Extract caching logic into cacheable-request module

cacheable-request
Luke Childs 8 years ago
parent
commit
23167fe63a
  1. 98
      index.js
  2. 4
      package.json

98
index.js

@ -16,9 +16,7 @@ const unzipResponse = require('unzip-response');
const createErrorClass = require('create-error-class');
const isRetryAllowed = require('is-retry-allowed');
const Buffer = require('safe-buffer').Buffer;
const CachePolicy = require('http-cache-semantics');
const normalizeUrl = require('normalize-url');
const Response = require('responselike');
const cacheableRequest = require('cacheable-request');
const pkg = require('./package');
function requestAsEventEmitter(opts) {
@ -26,17 +24,18 @@ function requestAsEventEmitter(opts) {
const ee = new EventEmitter();
const requestUrl = opts.href || urlLib.resolve(urlLib.format(opts), opts.path);
let revalidateCache = false;
let redirectCount = 0;
let retryCount = 0;
let redirectUrl;
const get = opts => {
const fn = opts.protocol === 'https:' ? https : http;
let request = opts.protocol === 'https:' ? https.request : http.request;
if (opts.cache) {
request = cacheableRequest(request, opts.cache);
}
const req = fn.request(opts, res => {
const req = request(opts, res => {
const statusCode = res.statusCode;
if (isRedirect(statusCode) && opts.followRedirect && 'location' in res.headers && (opts.method === 'GET' || opts.method === 'HEAD')) {
res.resume();
@ -58,55 +57,13 @@ function requestAsEventEmitter(opts) {
}
setImmediate(() => {
let response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
if (revalidateCache) {
const cachedResponse = revalidateCache.response;
const {policy, modified} = CachePolicy.fromObject(revalidateCache.policy).revalidatedPolicy(opts, response);
if (!modified) {
const {statusCode, url} = response;
const headers = policy.responseHeaders();
const bodyBuffer = Buffer.from(cachedResponse.body.data, cachedResponse.body.encoding);
response = new Response(statusCode, headers, bodyBuffer, url);
response.cachePolicy = policy;
}
}
if (typeof response.cachePolicy === 'undefined') {
response.cachePolicy = new CachePolicy(opts, response);
}
if (opts.cache && response.cachePolicy.storable()) {
const encoding = opts.encoding === null ? 'buffer' : opts.encoding;
getStream(response, {encoding})
.then(body => {
response.body = body;
const key = cacheKey(opts);
const value = {
policy: response.cachePolicy.toObject(),
response: {
url: response.url,
statusCode: response.statusCode,
body: {
encoding: opts.encoding,
data: response.body
}
}
};
const ttl = response.cachePolicy.timeToLive();
opts.cache.set(key, value, ttl);
});
} else if (revalidateCache) {
const key = cacheKey(opts);
opts.cache.delete(key);
}
const response = typeof unzipResponse === 'function' && req.method !== 'HEAD' ? unzipResponse(res) : res;
response.url = redirectUrl || requestUrl;
response.requestUrl = requestUrl;
response.fromCache = false;
ee.emit('response', response);
});
});
}).on('request', reqs => ee.emit('request', reqs));
req.once('error', err => {
const backoff = opts.retries(++retryCount, err);
@ -124,39 +81,13 @@ function requestAsEventEmitter(opts) {
}
setImmediate(() => {
ee.emit('request', req);
if (!opts.cache) {
ee.emit('request', req);
}
});
};
const getFromCache = opts => {
if (!opts.cache) {
return Promise.reject(new Error('Cache isn\'t enabled'));
}
const key = cacheKey(opts);
return Promise.resolve(opts.cache.get(key))
.then(value => {
if (typeof value === 'undefined') {
throw new TypeError('Cached value is undefined');
}
const policy = CachePolicy.fromObject(value.policy);
if (policy.satisfiesWithoutRevalidation(opts)) {
const {statusCode, body, url} = value.response;
const headers = policy.responseHeaders();
const bodyBuffer = Buffer.from(body.data, body.encoding);
const response = new Response(statusCode, headers, bodyBuffer, url);
response.cachePolicy = policy;
response.fromCache = true;
ee.emit('response', response);
} else {
revalidateCache = value;
opts.headers = policy.revalidationHeaders(opts);
get(opts);
}
});
};
getFromCache(opts).catch(() => get(opts));
get(opts);
return ee;
}
@ -372,11 +303,6 @@ function normalizeArguments(url, opts) {
return opts;
}
function cacheKey(opts) {
const url = normalizeUrl(urlLib.format(opts));
return `${opts.method}:${url}`;
}
function got(url, opts) {
try {
return asPromise(normalizeArguments(url, opts));

4
package.json

@ -42,16 +42,14 @@
"fetch"
],
"dependencies": {
"cacheable-request": "^0.2.0",
"create-error-class": "^3.0.0",
"duplexer3": "^0.1.4",
"get-stream": "^3.0.0",
"http-cache-semantics": "^3.7.3",
"is-redirect": "^1.0.0",
"is-retry-allowed": "^1.0.0",
"is-stream": "^1.0.0",
"lowercase-keys": "^1.0.0",
"normalize-url": "^1.9.1",
"responselike": "^0.1.0",
"safe-buffer": "^5.0.1",
"timed-out": "^4.0.0",
"unzip-response": "^2.0.1",

Loading…
Cancel
Save