Files

172 lines
4.2 KiB
JavaScript
Raw Permalink Normal View History

2019-05-27 10:33:22 -07:00
var http = require('http'),
https = require('https');
var Client = function(opts) {
this.opts = opts || {};
this.http = this.opts.ssl ? https : http;
};
Client.prototype.call = function(method, params, callback, errback, path) {
var time = Date.now();
var requestJSON;
if (Array.isArray(method)) {
// multiple rpc batch call
requestJSON = [];
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
method.forEach(function(batchCall, i) {
requestJSON.push({
id: time + '-' + i,
method: batchCall.method,
params: batchCall.params
});
});
} else {
// single rpc call
requestJSON = {
id: time,
method: method,
params: params
};
}
2021-03-17 17:54:09 -06:00
// first we encode the request into JSON
2019-05-27 10:33:22 -07:00
var requestJSON = JSON.stringify(requestJSON);
// prepare request options
var requestOptions = {
host: this.opts.host,
port: this.opts.port,
method: 'POST',
path: path || '/',
headers: {
'Host': this.opts.host,
'Content-Length': requestJSON.length
},
agent: false,
rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false
};
if (this.opts.ssl && this.opts.sslCa) {
requestOptions.ca = this.opts.sslCa;
}
// use HTTP auth if user and password set
2021-03-17 17:54:09 -06:00
if (this.opts.username && this.opts.password)
2020-11-21 20:27:50 -07:00
requestOptions.auth = this.opts.username + ':' + this.opts.password;
2019-05-27 10:33:22 -07:00
2021-03-17 17:54:09 -06:00
// now make a request to the server
2019-05-27 10:33:22 -07:00
var cbCalled = false
var request = this.http.request(requestOptions);
// start request timeout timer
var reqTimeout = setTimeout(function() {
2021-03-17 17:54:09 -06:00
if (cbCalled)
return;
2019-05-27 10:33:22 -07:00
cbCalled = true;
request.abort();
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
var err = new Error('ETIMEDOUT');
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
err.code = 'ETIMEDOUT';
errback(err);
}, this.opts.timeout || 30000);
// set additional timeout on socket in case of remote freeze after sending headers
request.setTimeout(this.opts.timeout || 30000, function() {
2021-03-17 17:54:09 -06:00
if (cbCalled)
return;
2019-05-27 10:33:22 -07:00
cbCalled = true;
request.abort();
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
var err = new Error('ESOCKETTIMEDOUT');
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
err.code = 'ESOCKETTIMEDOUT';
errback(err);
});
request.on('error', function(err) {
2021-03-17 17:54:09 -06:00
if (cbCalled)
return;
2019-05-27 10:33:22 -07:00
cbCalled = true;
clearTimeout(reqTimeout);
errback(err);
});
request.on('response', function(response) {
clearTimeout(reqTimeout);
2021-03-17 17:54:09 -06:00
// we need to buffer the response chunks in a nonblocking way
2019-05-27 10:33:22 -07:00
var buffer = '';
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
response.on('data', function(chunk) {
buffer = buffer + chunk;
});
2021-03-17 17:54:09 -06:00
// when all the responses are finished, we decode the JSON and
2019-05-27 10:33:22 -07:00
// depending on whether it's got a result or an error, we call
// emitSuccess or emitError on the promise.
response.on('end', function() {
var err;
2021-03-17 17:54:09 -06:00
if (cbCalled)
return;
2019-05-27 10:33:22 -07:00
cbCalled = true;
try {
var decoded = JSON.parse(buffer);
} catch (e) {
if (response.statusCode !== 200) {
err = new Error('Invalid params, response status code: ' + response.statusCode);
err.code = -32602;
errback(err);
} else {
err = new Error('Problem parsing JSON response from server');
err.code = -32603;
errback(err);
}
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
return;
}
2021-03-17 17:54:09 -06:00
if (!Array.isArray(decoded))
2019-05-27 10:33:22 -07:00
decoded = [decoded];
// iterate over each response, normally there will be just one
// unless a batch rpc call response is being processed
decoded.forEach(function(decodedResponse, i) {
if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) {
if (errback) {
err = new Error(decodedResponse.error.message || '');
2021-03-17 17:54:09 -06:00
if (decodedResponse.error.code)
2019-05-27 10:33:22 -07:00
err.code = decodedResponse.error.code;
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
errback(err);
}
} else if (decodedResponse.hasOwnProperty('result')) {
2021-03-17 17:54:09 -06:00
if (callback)
2019-05-27 10:33:22 -07:00
callback(decodedResponse.result, response.headers);
} else {
if (errback) {
err = new Error(decodedResponse.error.message || '');
2021-03-17 17:54:09 -06:00
if (decodedResponse.error.code)
2019-05-27 10:33:22 -07:00
err.code = decodedResponse.error.code;
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
errback(err);
}
}
});
});
});
2021-03-17 17:54:09 -06:00
2019-05-27 10:33:22 -07:00
request.on('error', errback);
request.end(requestJSON);
};
module.exports.Client = Client;