UNPKG

npm-bitcoin

Version:

Communicate with bitcoind via JSON-RPC

140 lines (121 loc) 4.11 kB
var http = require('http') var 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 = [] 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 } } // First we encode the request into JSON requestJSON = JSON.stringify(requestJSON) // prepare request options var requestOptions = { host: this.opts.host || 'localhost', port: this.opts.port || 8332, method: 'POST', path: path || '/', headers: { 'Host': this.opts.host || 'localhost', '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 if (this.opts.user && this.opts.pass) { requestOptions.auth = this.opts.user + ':' + this.opts.pass } // Now we'll make a request to the server var cbCalled = false; var request = this.http.request(requestOptions); // start request timeout timer var reqTimeout = setTimeout(function () { if (cbCalled) return; cbCalled = true; request.abort(); errback({ "error": "Timed out", "error_code": "TIMED_OUT"}); }, this.opts.timeout || 30000); // set additional timeout on socket in case of remote freeze after sending headers request.setTimeout(this.opts.timeout || 30000, function () { if (cbCalled) return; cbCalled = true; request.abort(); errback({ "error": "Socket Timed Out", "error_code": "SOCKET_TIMED_OUT"}); }) request.on('error', function (err) { if (cbCalled) return; cbCalled = true; clearTimeout(reqTimeout); errback({ "error": err, "error_code": "SOMETHING_WENT_WRONG" }); }) request.on('response', function (response) { clearTimeout(reqTimeout) // We need to buffer the response chunks in a nonblocking way. var buffer = '' response.on('data', function (chunk) { buffer = buffer + chunk }) // When all the responses are finished, we decode the JSON and // 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; if (cbCalled) return cbCalled = true try { var decoded = JSON.parse(buffer) } catch (e) { if (response.statusCode !== 200) { errback({ "error": "Invalid params, response status code: " + response.statusCode, "error_code": "INVALID_PARAMS" }); } else { errback({ "error": "Problem parsing JSON response from server", "error_code": "PROBLEM_PARSING_JSON_RESPONSE" }); } return; } if (!Array.isArray(decoded)) { 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) { errback({ "error": decodedResponse.error.message || "", "error_code": decodedResponse.error.code || "" }); } } else if (decodedResponse.hasOwnProperty('result')) { if (callback) { callback(decodedResponse.result, response.headers) } } else { if (errback) { errback({ "error": decodedResponse.error.message || "", "error_code": decodedResponse.error.code || "" }); } } }) }) }) request.end(requestJSON) } module.exports.Client = Client;