UNPKG

@trivechain/trivechaind-rpc

Version:

Trivechain Client Library to connect to Trivechain Core (trivechaind) via RPC

369 lines (333 loc) 9.32 kB
'use strict' var http = require('http') var https = require('https') var async = require('async') function RpcClient(opts) { opts = opts || {} this.host = opts.host || '127.0.0.1' this.port = opts.port || 9998 this.user = opts.user || 'user' this.pass = opts.pass || 'pass' this.protocol = opts.protocol === 'http' ? http : https this.batchedCalls = null this.disableAgent = opts.disableAgent || false var queueSize = opts.queue || 16 var isRejectUnauthorized = typeof opts.rejectUnauthorized !== 'undefined' this.rejectUnauthorized = isRejectUnauthorized ? opts.rejectUnauthorized : true if (RpcClient.config.log) { this.log = RpcClient.config.log } else { this.log = RpcClient.loggers[RpcClient.config.logger || 'normal'] } this.queue = async.queue(function (task, callback) { task(callback) }, queueSize) } var cl = console.log.bind(console) var noop = function () {} RpcClient.loggers = { none: { info: noop, warn: noop, err: noop, debug: noop }, normal: { info: cl, warn: cl, err: cl, debug: noop }, debug: { info: cl, warn: cl, err: cl, debug: cl }, } RpcClient.config = { logger: 'normal', // none, normal, debug, } function rpc(request, callback) { var self = this var task = function (taskCallback) { var newCallback = function () { callback.apply(undefined, arguments) taskCallback() } innerRpc.call(self, request, newCallback) } this.queue.push(task) } function innerRpc(request, callback) { var self = this request = JSON.stringify(request) var auth = Buffer.from(self.user + ':' + self.pass).toString('base64') var options = { host: self.host, path: '/', method: 'POST', port: self.port, rejectUnauthorized: self.rejectUnauthorized, agent: self.disableAgent ? false : undefined, } if (self.httpOptions) { for (var k in self.httpOptions) { options[k] = self.httpOptions[k] } } var called = false var errorMessage = 'Trivechain JSON-RPC: ' var req = this.protocol.request(options, function (res) { var buf = '' res.on('data', function (data) { buf += data }) res.on('end', function () { if (called) { return } called = true if (res.statusCode === 401) { callback( new Error(errorMessage + 'Connection Rejected: 401 Unnauthorized') ) return } if (res.statusCode === 403) { callback(new Error(errorMessage + 'Connection Rejected: 403 Forbidden')) return } if ( res.statusCode === 500 && buf.toString('utf8') === 'Work queue depth exceeded' ) { var exceededError = new Error( 'Trivechain JSON-RPC: ' + buf.toString('utf8') ) exceededError.code = 429 // Too many requests callback(exceededError) return } var parsedBuf try { parsedBuf = JSON.parse(buf) } catch (e) { self.log.err(e.stack) self.log.err(buf) self.log.err('HTTP Status code:' + res.statusCode) var err = new Error(errorMessage + 'Error Parsing JSON: ' + e.message) callback(err) return } callback(parsedBuf.error, parsedBuf) }) }) req.on('error', function (e) { var err = new Error(errorMessage + 'Request Error: ' + e.message) if (!called) { called = true callback(err) } }) req.setHeader('Content-Length', request.length) req.setHeader('Content-Type', 'application/json') req.setHeader('Authorization', 'Basic ' + auth) req.write(request) req.end() } RpcClient.prototype.batch = function (batchCallback, resultCallback) { this.batchedCalls = [] batchCallback() rpc.call(this, this.batchedCalls, resultCallback) this.batchedCalls = null } // For definitions of RPC calls, see various files in: https://github.com/trivechain/trivechain-core/tree/master/src RpcClient.callspec = { abandonTransaction: 'str', addMultiSigAddress: 'int str str', addNode: 'str str', backupWallet: 'str', clearBanned: '', createMultiSig: 'int str', createRawTransaction: 'str str int', debug: 'str', decodeRawTransaction: 'str', decodeScript: 'str', disconnectNode: 'str', dumpPrivKey: 'str', dumpWallet: 'str', encryptWallet: 'str', estimateFee: 'int', estimatePriority: 'int', estimateSmartFee: 'int', estimateSmartPriority: 'int', fundRawTransaction: 'str bool', generate: 'int', generateToAddress: 'int str', getAccount: 'str', getAccountAddress: 'str', getAddressMempool: 'obj', getAddressUtxos: 'obj', getAddressBalance: 'obj', getAddressDeltas: 'obj', getAddressTxids: 'obj', getAddressesByAccount: '', getAddedNodeInfo: 'bool str', getBalance: 'str int bool', getBestBlockHash: '', getBlock: 'str bool', getBlockchainInfo: '', getBlockCount: '', getBlockHashes: 'int int', getBlockHash: 'int', getBlockHeader: 'str bool', getBlockHeaders: 'str int bool', getBlockTemplate: '', getConnectionCount: '', getChainTips: 'int int', getDifficulty: '', getGenerate: '', getGovernanceInfo: '', getInfo: '', getMemPoolInfo: '', getMerkleBlocks: 'str str int', getMiningInfo: '', getNewAddress: '', getNetTotals: '', getNetworkInfo: '', getNetworkHashps: 'int int', getPeerInfo: '', getPoolInfo: '', getRawMemPool: 'bool', getRawChangeAddress: '', getRawTransaction: 'str int', getReceivedByAccount: 'str int', getReceivedByAddress: 'str int', getSpentInfo: 'obj', getSuperBlockBudget: 'int', getTransaction: '', getTxOut: 'str int bool', getTxOutProof: 'str str', getTxOutSetInfo: '', getWalletInfo: '', help: 'str', importAddress: 'str str bool', instantSendToAddress: 'str int str str bool', gobject: 'str str', invalidateBlock: 'str', importPrivKey: 'str str bool', importPubKey: 'str str bool', importElectrumWallet: 'str int', importWallet: 'str', keyPoolRefill: 'int', listAccounts: 'int bool', listAddressGroupings: '', listBanned: '', listReceivedByAccount: 'int bool', listReceivedByAddress: 'int bool', listSinceBlock: 'str int', listTransactions: 'str int int bool', listUnspent: 'int int str', listLockUnspent: 'bool', lockUnspent: 'bool obj', masternode: 'str', masternodeBroadcast: 'str', masternodelist: 'str str', mnsync: '', move: 'str str float int str', ping: '', prioritiseTransaction: 'str float int', privateSend: 'str', protx: 'str str str', reconsiderBlock: 'str', resendWalletTransactions: '', sendFrom: 'str str float int str str', sendMany: 'str obj int str str bool bool', sendRawTransaction: 'str bool bool', sendToAddress: 'str float str str', sentinelPing: 'str', setAccount: '', setBan: 'str str int bool', setGenerate: 'bool int', setTxFee: 'float', setMockTime: 'int', spork: 'str str', signMessage: 'str str', signRawTransaction: 'str str str str', stop: '', submitBlock: 'str str', validateAddress: 'str', verifyMessage: 'str str str', verifyChain: 'int int', verifyTxOutProof: 'str', voteRaw: 'str int', waitForNewBlock: 'int', walletLock: '', walletPassPhrase: 'str int bool', walletPassphraseChange: 'str str', getUser: 'str', } var slice = function (arr, start, end) { return Array.prototype.slice.call(arr, start, end) } function generateRPCMethods(constructor, apiCalls, rpc) { function createRPCMethod(methodName, argMap) { return function () { var limit = arguments.length - 1 if (this.batchedCalls) { limit = arguments.length } for (var i = 0; i < limit; i++) { if (argMap[i]) { arguments[i] = argMap[i](arguments[i]) } } if (this.batchedCalls) { this.batchedCalls.push({ jsonrpc: '2.0', method: methodName, params: slice(arguments), id: getRandomId(), }) } else { rpc.call( this, { method: methodName, params: slice(arguments, 0, arguments.length - 1), id: getRandomId(), }, arguments[arguments.length - 1] ) } } } var types = { str: function (arg) { return arg.toString() }, int: function (arg) { return parseFloat(arg) }, float: function (arg) { return parseFloat(arg) }, bool: function (arg) { // eslint-disable-next-line return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true') }, obj: function (arg) { if (typeof arg === 'string') { return JSON.parse(arg) } return arg }, } for (var k in apiCalls) { var spec = apiCalls[k].split(' ') for (var i = 0; i < spec.length; i++) { if (types[spec[i]]) { spec[i] = types[spec[i]] } else { spec[i] = types.str } } var methodName = k.toLowerCase() constructor.prototype[k] = createRPCMethod(methodName, spec) constructor.prototype[methodName] = constructor.prototype[k] } constructor.prototype.apiCalls = apiCalls } function getRandomId() { return parseInt(Math.random() * 100000) } generateRPCMethods(RpcClient, RpcClient.callspec, rpc) module.exports = RpcClient