Skip to content

Commit

Permalink
Refactor to use Node HTTP (#116)
Browse files Browse the repository at this point in the history
  • Loading branch information
cjus authored May 6, 2017
1 parent 3af3e1c commit a39d1a1
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 158 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"-": 0,
"define": true,
"expect": true,
"it": true
"it": true,
"require": true
}
}
71 changes: 10 additions & 61 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ Promise.series = (iterable, action) => {
const EventEmitter = require('events');
const util = require('util');
const Route = require('route-parser');
const fetch = require('node-fetch');

const Utils = require('./lib/utils');
const UMFMessage = require('./lib/umfmessage');
const RedisConnection = require('./lib/redis-connection');
const ServerResponse = require('./lib/server-response');
let serverResponse = new ServerResponse();
const ServerRequest = require('./lib/server-request');
let serverRequest = new ServerRequest();

let HYDRA_REDIS_DB = 0;
const redisPreKey = 'hydra:service';
Expand Down Expand Up @@ -1059,60 +1060,23 @@ class Hydra extends EventEmitter {
reject(err);
} else {
instance = Utils.safeJSONParse(result);
let url = `http://${instance.ip}:${instance.port}${parsedRoute.apiRoute}`;
let options = {
method: parsedRoute.httpMethod.toUpperCase(),
timeout: 0
host: instance.ip,
port: instance.port,
path: parsedRoute.apiRoute,
method: parsedRoute.httpMethod.toUpperCase()
};
options.headers = Object.assign({}, umfmsg.headers);
if (umfmsg.authorization) {
options.headers.Authorization = umfmsg.authorization;
}
if (umfmsg.body) {
let httpMethod = parsedRoute.httpMethod.toUpperCase();
if (httpMethod === 'POST' || httpMethod === 'PUT') {
options.body = Utils.safeJSONStringify(umfmsg.body);
}
}

let status = 0;
let ct;
let isJSON = false;
let headers = {};
fetch(url, options)
options.body = Utils.safeJSONStringify(umfmsg.body);
serverRequest.send(options)
.then((res) => {
status = res.status;
res.headers.forEach((value, name) => {
headers[name] = value;
});
ct = res.headers.get('content-type');
if (ct && ct.indexOf('json') > -1) {
isJSON = true;
return res.json();
} else {
isJSON = false;
return res.buffer();
}
})
.then((body) => {
if (body.statusCode) {
resolve(body);
} else {
let resObject;
if (isJSON) {
resObject = serverResponse.createResponseObject(status, {
result: body
});
} else {
resObject = {
headers,
body
};
}
resolve(resObject);
}
resolve(serverResponse.createResponseObject(res.statusCode, res));
})
.catch((_err) => {
this.emit('metric', `service:unavailable|${instance.serviceName}|${instance.instanceID}`);
instanceList.shift();
if (instanceList.length === 0) {
resolve(this._createServerResponseWithReason(ServerResponse.HTTP_SERVICE_UNAVAILABLE, `An instance of ${instance.serviceName} is unavailable`));
Expand Down Expand Up @@ -1508,21 +1472,6 @@ class Hydra extends EventEmitter {
* Hydra private utility functions.
* ***************************************************************/

/**
* @name _createServerResponseWithReason
* @summary Create a server response using an HTTP code and reason
* @param {number} httpCode - code using ServerResponse.HTTP_XXX
* @param {string} reason - reason description
* @return {object} response - response object for use with promise resolve and reject calls
*/
_createServerResponse(httpCode, reason) {
return serverResponse.createResponseObject(httpCode, {
result: {
reason: reason
}
});
}

/**
* @name _createServerResponseWithReason
* @summary Create a server response using an HTTP code and reason
Expand Down
42 changes: 1 addition & 41 deletions lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const fs = require('fs');
const Promise = require('bluebird');
const fetch = require('node-fetch');
const Utils = require('./utils');

/**
Expand Down Expand Up @@ -43,13 +42,7 @@ class Config {
} else {
try {
if (typeof cfg === 'string') {
if (cfg.substring(0, 4) === 'http') {
// network based
this._doInitViaNetwork(cfg, resolve, reject);
} else {
// file based
this._doInitViaFile(cfg, resolve, reject);
}
this._doInitViaFile(cfg, resolve, reject);
} else {
this.config = Object.assign({}, cfg);
resolve();
Expand Down Expand Up @@ -88,39 +81,6 @@ class Config {
});
}

/**
* @name _doInitViaNetwork
* @summary Perform initialization using remote request.
* @param {string} configFilePath - URL to configuration JSON data
* @param {function} resolve - resolve function
* @param {function} reject - reject function
* @return {undefined}
*/
_doInitViaNetwork(configFilePath, resolve, reject) {
let options = {
headers: {
'content-type': 'application/json',
'Accept': 'application/json; charset=UTF-8'
},
method: 'GET'
};
fetch(configFilePath, options)
.then((response) => {
return response.json();
})
.then((config) => {
if (config.location) {
this._doInit(config.location, resolve, reject);
} else {
this.config = config;
resolve();
}
})
.catch((_err) => {
reject(new Error('config file contents is not valid JSON'));
});
}

/**
* @name init
* @summary Initializes config object with JSON file data.
Expand Down
70 changes: 70 additions & 0 deletions lib/server-request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const http = require('http');
const REQUEST_TIMEOUT = 5 * 1000; // 5-seconds

/**
* @name ServerRequest
* @summary Class for handling server requests
*/
class ServerRequest {
/**
* @name constructor
* @summary Class constructor
* @return {undefined}
*/
constructor() {
}

/**
* @name send
* @summary sends an HTTP Request
* @param {object} options - request options
* @return {object} promise
*/
send(options) {
return new Promise((resolve, reject) => {
if (options.method === 'POST' || options.method === 'PUT') {
options.headers['content-length'] = options.body.length;
} else {
delete options.body;
}

let req = http.request(options, (res) => {
let response = [];
res.on('data', (data) => {
response.push(data);
});
res.on('end', () => {
let buffer = Buffer.concat(response);
let data = {
statusCode: res.statusCode,
headers: res.headers
};
data.headers['content-length'] = Buffer.byteLength(buffer);
data.payLoad = buffer;
resolve(data);
});
res.on('error', (err) => {
reject(err);
});
});

req.on('socket', (socket) => {
socket.setNoDelay(true);
socket.setTimeout(options.timeout * 1000 || REQUEST_TIMEOUT, () => {
req.abort();
});
});

req.on('error', (err) => {
reject(err);
});

if (options.body) {
req.write(options.body);
}
req.end();
});
}
}

module.exports = ServerRequest;
Loading

0 comments on commit a39d1a1

Please sign in to comment.