tendermint
Version:
A light client which talks to your Tendermint node over RPC
236 lines (200 loc) • 7.59 kB
JavaScript
;
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var EventEmitter = require('events');
var axios = require('axios');
var url = require('url');
var old = require('old');
var camel = require('camelcase');
var websocket = require('websocket-stream');
var ndjson = require('ndjson');
var pumpify = require('pumpify').obj;
var debug = require('debug')('tendermint:rpc');
var tendermintMethods = require('./methods.js');
function convertHttpArgs(args) {
args = args || {};
for (var k in args) {
var v = args[k];
if (typeof v === 'number') {
args[k] = '"' + v + '"';
}
}
return args;
}
function convertWsArgs(args) {
args = args || {};
for (var k in args) {
var v = args[k];
if (typeof v === 'number') {
args[k] = String(v);
} else if (Buffer.isBuffer(v)) {
args[k] = '0x' + v.toString('hex');
} else if (v instanceof Uint8Array) {
args[k] = '0x' + Buffer.from(v).toString('hex');
}
}
return args;
}
var wsProtocols = ['ws:', 'wss:'];
var httpProtocols = ['http:', 'https:'];
var allProtocols = wsProtocols.concat(httpProtocols);
var Client = function (_EventEmitter) {
_inherits(Client, _EventEmitter);
function Client() {
var uriString = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'localhost:26657';
_classCallCheck(this, Client);
// parse full-node URI
var _this = _possibleConstructorReturn(this, (Client.__proto__ || Object.getPrototypeOf(Client)).call(this));
var _url$parse = url.parse(uriString),
protocol = _url$parse.protocol,
hostname = _url$parse.hostname,
port = _url$parse.port;
// default to http
if (!allProtocols.includes(protocol)) {
var uri = url.parse('http://' + uriString);
protocol = uri.protocol;
hostname = uri.hostname;
port = uri.port;
}
// default port
if (!port) {
port = 26657;
}
if (wsProtocols.includes(protocol)) {
_this.websocket = true;
_this.uri = protocol + '//' + hostname + ':' + port + '/websocket';
_this.call = _this.callWs;
_this.connectWs();
} else if (httpProtocols.includes(protocol)) {
_this.uri = protocol + '//' + hostname + ':' + port + '/';
_this.call = _this.callHttp;
}
return _this;
}
_createClass(Client, [{
key: 'connectWs',
value: function connectWs() {
var _this2 = this;
this.ws = pumpify(ndjson.stringify(), websocket(this.uri));
this.ws.on('error', function (err) {
return _this2.emit('error', err);
});
this.ws.on('close', function () {
if (_this2.closed) return;
_this2.emit('error', Error('websocket disconnected'));
});
this.ws.on('data', function (data) {
data = JSON.parse(data);
if (data.result && data.result.query) {
_this2.emit('query#' + data.result.query, data.error, data.result);
}
if (!data.id) return;
_this2.emit(data.id, data.error, data.result);
});
}
}, {
key: 'callHttp',
value: function callHttp(method, args) {
return axios({
url: this.uri + method,
params: convertHttpArgs(args)
}).then(function (_ref) {
var data = _ref.data;
if (data.error) {
var err = Error(data.error.message);
Object.assign(err, data.error);
throw err;
}
return data.result;
}, function (err) {
throw Error(err);
});
}
}, {
key: 'callWs',
value: function callWs(method, args, listener) {
var _this3 = this;
var self = this;
return new Promise(function (resolve, reject) {
var id = Math.random().toString(36);
var params = convertWsArgs(args);
if (method === 'subscribe') {
if (typeof listener !== 'function') {
throw Error('Must provide listener function');
}
// id-free query responses in tendermint-0.33 are returned as follows
if (params.query) {
_this3.on('query#' + params.query, function (err, res) {
if (err) return self.emit('error', err);
listener(res.data.value);
});
}
// promise resolves on successful subscription or error
_this3.once(id, function (err, res) {
if (err) return reject(err);
// now that we are subscribed, pass further events to listener
_this3.on(id, function (err, res) {
if (err) return _this3.emit('error', err);
listener(res.data.value);
});
resolve();
});
} else {
// response goes to promise
_this3.once(id, function (err, res) {
if (err) return reject(err);
resolve(res);
});
}
_this3.ws.write({ jsonrpc: '2.0', id: id, method: method, params: params });
});
}
}, {
key: 'close',
value: function close() {
this.closed = true;
if (!this.ws) return;
this.ws.destroy();
}
}]);
return Client;
}(EventEmitter);
// add methods to Client class based on methods defined in './methods.js'
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
var _loop = function _loop() {
var name = _step.value;
Client.prototype[camel(name)] = function (args, listener) {
if (args) {
debug('>>', name, args);
} else {
debug('>>', name);
}
return this.call(name, args, listener).then(function (res) {
debug('<<', name, res);
return res;
});
};
};
for (var _iterator = tendermintMethods[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
_loop();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
module.exports = old(Client);