Last active
July 17, 2018 09:36
-
-
Save progress44/bba5d6c10b5022fad7bb339c2bca7c6e to your computer and use it in GitHub Desktop.
Utility wrapping requests and enabling caching with redis for http requests
This file contains hidden or 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
const https = require('https') | |
const qs = require('querystring') | |
const redis = require("redis") | |
const sha1 = require("sha1") | |
const url = require('url') | |
const util = require('util') | |
const client = redis.createClient({ | |
host: config.redis.host, | |
port: config.redis.port, | |
retry_strategy: (opts) => { | |
if (opts.error && opts.error.code === 'ECONNREFUSED') return undefined | |
if (opts.total_retry_time > 1000 * 60 * 60) return undefined | |
if (opts.attempt > 10) return undefined | |
} | |
}) | |
client.on("error", function (err) { | |
console.log(err) | |
}) | |
const DEFAULT_TIMEOUT_MS = 5000 | |
const ACK_METHODS = ["POST", "GET"] | |
const _checkCache = function(hash) { | |
return new Promise((resolve, reject) => { | |
if (!client) return reject({}) | |
client.get(hash, (err, resp) => { | |
if (!err && resp != null) { | |
console.log("Cache HIT for <" + hash + ">") | |
try { | |
resolve(JSON.parse(resp)) | |
} catch (e) { | |
resolve(resp) | |
} | |
} else { | |
console.log("Cache MISS for <" + hash + ">") | |
reject(err) | |
} | |
}) | |
}) | |
} | |
const _clearCache = function(hash) { | |
return new Promise((resolve, reject) => { | |
try { | |
client.DEL(hash, (err, resp) => { | |
if (!err && resp) { | |
console.log("Cache deleted") | |
resolve() | |
} else { | |
console.log("Error deleting cache") | |
reject(err) | |
} | |
}) | |
} catch (e) { | |
reject(e) | |
} | |
}) | |
} | |
const _responseHandler = (res, body, hash, ttl) => { | |
return new Promise( (resolve, reject) => { | |
var payload | |
var responseText = body.join('').replace("])}while(1);</x>", "") | |
try { | |
payload = JSON.parse(responseText) | |
} catch (err) { | |
return reject(`Failed to parse response: ${body}`) | |
} | |
var statusCode = res.statusCode | |
var statusType = Math.floor(res.statusCode / 100) | |
if (statusType == 4 || statusType == 5) { | |
var err = payload && payload.errors && payload.errors[0] ? payload.errors[0] : payload | |
reject(err.message ? err.message : err) | |
} else if (statusType == 2) { | |
// Adding redis cache | |
if(client) client.set(hash, JSON.stringify(payload.data || payload)) | |
resolve(payload.data || payload) | |
} else { | |
reject('Unexpected response') | |
} | |
}) | |
} | |
const _requestStream = (res, hash, ttl) => { | |
return new Promise((resolve, reject) => { | |
var body = [] | |
res.setEncoding('utf-8') | |
res.on('data', data => { | |
body.push(data) | |
} ) | |
res.on('end', () => _responseHandler(res, body, hash, ttl).then(resolve).catch(reject) ) | |
}) | |
} | |
const _makeRequest = function (requestParams, hash) { | |
return new Promise((resolve, reject) => { | |
if (requestParams.method == "GET" && requestParams.data) { | |
requestParams.path += "?" | |
_.each(requestParams.data, (v, i) => { | |
requestParams.path += `${i}=${v}&` | |
}) | |
requestParams.path += `t=` + Date.now() | |
} | |
var req = https.request(_.omit(requestParams, ["ttl", "data", "headers", "contentType"]), (data) => { | |
return _requestStream(data, hash, requestParams.ttl) | |
.then(resolve) | |
.catch(reject) | |
}) | |
req.on('error', (e) => { | |
console.log(`<HTTP> Error: ${e.message}`) | |
return reject(e.message) | |
}) | |
req.setHeader('Content-Type', requestParams.contentType || 'application/json') | |
req.setHeader('Accept', 'application/json') | |
req.setHeader('Accept-Charset', 'utf-8') | |
if (requestParams.headers && _.isObject(requestParams.headers)) { | |
for (var k in requestParams.headers) { | |
if (requestParams.headers[k]) { | |
req.setHeader(k, requestParams.headers[k]) | |
} else if (null == requestParams.headers[k]) { | |
req.removeHeader(k) | |
} | |
} | |
} | |
req.setTimeout(DEFAULT_TIMEOUT_MS, () => { | |
// Aborting a request triggers the 'error' event. | |
req.abort() | |
reject("Http request aborted") | |
}) | |
if (requestParams.data && requestParams.method != "GET") { | |
var data = requestParams.data | |
if (typeof data == 'object' && (!requestParams.contentType || requestParams.contentType == "application/json")) { | |
data = JSON.stringify(data) | |
} | |
req.write(data) | |
} | |
req.end() | |
}) | |
} | |
const http = (options) => { | |
return new Promise((resolve, reject) => { | |
var requestParams = { | |
host: options.url, | |
hostname: options.url, | |
port: options.port || 443, | |
method: options.method, | |
path: options.path, | |
contentType: options.contentType || null, | |
headers: options.headers || [], | |
data: options.data || null, | |
ttl: options.ttl, | |
protocol: options.protocol || 'https:' | |
} | |
var urlHash = sha1(requestParams.method + "|" + requestParams.host + ":" + requestParams.port + "/" + requestParams.path + "/" + JSON.stringify(requestParams.data)) | |
if (options.ttl === 0) _clearCache(urlHash).then(1).catch(e => console.log(`Error deleting cache ${e}`)) | |
_checkCache(urlHash) | |
.then(resolve) | |
.catch((e) => { | |
return _makeRequest(requestParams, urlHash) | |
.then(resolve) | |
.catch(reject) | |
}) | |
}) | |
} | |
module.exports.download = function(options) { | |
var requestParams = { | |
host: options.url, | |
hostname: options.url, | |
port: options.port || 443, | |
method: options.method || 'GET', | |
path: options.path, | |
contentType: options.contentType || null, | |
headers: options.headers || [], | |
data: options.data || null, | |
ttl: options.ttl, | |
protocol: options.protocol || 'https:' | |
} | |
var urlHash = sha1(requestParams.method + "|" + requestParams.host + ":" + requestParams.port + "/" + requestParams.path + "/" + JSON.stringify(requestParams.data)) | |
if (options.ttl === 0) _clearCache(urlHash).then(1).catch(e => console.log(`Error deleting cache ${e}`)) | |
_checkCache(urlHash) | |
.then(resolve) | |
.catch((e) => { | |
return _makeRequest(requestParams, urlHash) | |
.then(resolve) | |
.catch(reject) | |
}) | |
} | |
module.exports.request = http |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment