Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@suissa
Last active March 27, 2018 01:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save suissa/8126ad8c68e9cd1db7c15860e3b423d0 to your computer and use it in GitHub Desktop.
Save suissa/8126ad8c68e9cd1db7c15860e3b423d0 to your computer and use it in GitHub Desktop.
Refatorando uma LIB para retirar o this + prototype + new | Ainda falta a parte do jsonrpc.js
module.exports = {
addMultiSigAddress: 'addmultisigaddress',
addNode: 'addnode', // litecoind v0.8+
backupWallet: 'backupwallet',
banNode: 'bannode', // OMG2 only
createMultisig: 'createmultisig',
createRawTransaction: 'createrawtransaction',
decodeRawTransaction: 'decoderawtransaction',
dumpPrivKey: 'dumpprivkey',
encryptWallet: 'encryptwallet',
getAccount: 'getaccount',
getAccountAddress: 'getaccountaddress',
getAddedNodeInfo: 'getaddednodeinfo', // litecoind v0.8+
getAddressesByAccount: 'getaddressesbyaccount',
getBalance: 'getbalance',
getbestblockhash: 'getbestblockhash', // litecoind v0.8.6.1+
getBlock: 'getblock',
getBlockCount: 'getblockcount',
getBlockHash: 'getblockhash',
getBlockTemplate: 'getblocktemplate',
getConnectionCount: 'getconnectioncount',
getDifficulty: 'getdifficulty',
getInfo: 'getinfo',
getMiningInfo: 'getmininginfo',
getNetworkHashPs: 'getnetworkhashps', // litecoind v0.8.4+
getNewAddress: 'getnewaddress',
getPeerInfo: 'getpeerinfo',
getRawMempool: 'getrawmempool',
getRawTransaction: 'getrawtransaction',
getReceivedByAccount: 'getreceivedbyaccount', // litecoind v0.3.24+
getReceivedByAddress: 'getreceivedbyaddress',
getTransaction: 'gettransaction',
getTxOut: 'gettxout',
getTxOutSetInfo: 'gettxoutsetinfo',
getWork: 'getwork',
help: 'help',
importPrivKey: 'importprivkey', // litecoind v0.8+
keyPoolRefill: 'keypoolrefill',
listAccounts: 'listaccounts',
listAddressGroupings: 'listaddressgroupings',
listBannedNodes: 'listbannednodes', // OMG2 only
listLockUnspent: 'listlockunspent',
listReceivedByAccount: 'listreceivedbyaccount',
listReceivedByAddress: 'listreceivedbyaddress',
listSinceBlock: 'listsinceblock',
listTransactions: 'listtransactions',
listUnspent: 'listunspent',
lockUnspent: 'lockunspent', // litecoind v0.8+
move: 'move',
sendFrom: 'sendfrom',
sendMany: 'sendmany',
sendRawTransaction: 'sendrawtransaction',
sendToAddress: 'sendtoaddress',
setAccount: 'setaccount',
setMininput: 'setmininput',
setTxFee: 'settxfee',
signMessage: 'signmessage',
signRawTransaction: 'signrawtransaction',
stop: 'stop',
submitBlock: 'submitblock',
validateAddress: 'validateaddress',
verifyChain: 'verifychain', // litecoind v0.8.6.1+
verifyMessage: 'verifymessage',
walletLock: 'walletlock',
walletPassphrase: 'walletpassphrase',
walletPassphraseChange: 'walletpassphrasechange'
};
const commands = require('./commands')
const rpc = require('./jsonrpc')
const handleError = (err) => console.error(err)
const error = (fn) => (err) => fn(err)
const getFn = (cb, args) => (cb === undefined) ? args : cb
const toArg = (prev, cur, i) => [...prev, cur]
const getArgs = (_args) => [
null,
..._args.reduce(toArg, [])
]
const success = ({cb, args, self}) => (..._args) =>
getFn(cb, args).apply(
self,
getArgs(_args)
)
const callRpc = ({ cmd, args, cb, rpc }) =>
rpc.call(
cmd,
args,
success({ cb, args, self: this}),
error(handleError)
)
const getAction = ({actions, i, cmd, rpc}) => ({
[actions[i]]: (args, cb) => callRpc({ cmd, args, cb, rpc }) })
const toClientActions = ({actions, rpc}) => (result, cmd, i) =>
Object.assign(
result,
getAction({ actions, i, cmd, rpc})
)
const toActions = (opts, commands) => toClientActions({
actions: Object.keys(commands),
rpc: new rpc.Client(opts)
})
const Client = (opts) =>
Object.values(commands)
.reduce(toActions(opts, commands), {})
module.exports.Client = Client
var commands = require('./commands');
var rpc = require('./jsonrpc');
// ===----------------------------------------------------------------------===//
// Client
// ===----------------------------------------------------------------------===//
function Client (opts) {
this.rpc = new rpc.Client(opts);
}
// ===----------------------------------------------------------------------===//
// cmd
// ===----------------------------------------------------------------------===//
Client.prototype.cmd = function () {
var args = [].slice.call(arguments);
var cmd = args.shift();
callRpc(cmd, args, this.rpc);
};
// ===----------------------------------------------------------------------===//
// callRpc
// ===----------------------------------------------------------------------===//
function callRpc (cmd, args, rpc) {
var fn = args[args.length - 1];
// If the last argument is a callback, pop it from the args list
if (typeof fn === 'function') {
args.pop();
} else {
fn = function () {};
}
rpc.call(cmd, args, function () {
var args = [].slice.call(arguments);
args.unshift(null);
fn.apply(this, args);
}, function (err) {
fn(err);
});
}
// ===----------------------------------------------------------------------===//
// Initialize wrappers
// ===----------------------------------------------------------------------===//
(function () {
for (var protoFn in commands) {
(function (protoFn) {
Client.prototype[protoFn] = function () {
var args = [].slice.call(arguments);
callRpc(commands[protoFn], args, this.rpc);
};
})(protoFn);
}
})();
// Export!
module.exports.Client = Client;
const http = require('http')
const https = require('https')
const Client = (opts) => ({
opts: opts || {},
http: opts.ssl ? https : http
})
let cbCalled = false
const ERRORS = {
'-32602': (statusCode) => Object.assign(
new Error('Invalid params, response status code: ' + statusCode),
{ code: -32603 }
),
'-32603': (...args) => Object.assign(
new Error('Problem parsing JSON response from server'),
{ code: -32603 }
)
}
const isTrue = (...conditions) =>
conditions.reduce((result, cond) => result && cond, true)
const reqOnError = ({cbCalled, reqTimeout, errback}) => (err) => {
if (cbCalled) return true
clearTimeout(reqTimeout)
return errback(err)
}
const getReject = (self) => self.opts.ssl && self.opts.sslStrict !== false
const getRequestJSONArray = (method, time) =>
method.map((batchCall, i) => ({
id: time + '-' + i,
method: batchCall.method,
params: batchCall.params
})
)
const getRequestJSONObject = (method, time, params) => ({
method,
params
})
const getRequestJSON = (method, time, params) =>
JSON.stringify((Array.isArray(method))
? getRequestJSONArray(method, time)
: getRequestJSONObject(method, time, params))
const getRequestOptions = (
self,
path = '/',
requestJSON,
method = 'POST',
agent = false) => ({
host: self.opts.host || 'localhost',
port: self.opts.port || 9332,
method,
path,
headers: {
'Host': self.opts.host || 'localhost',
'Content-Length': requestJSON.length
},
agent,
rejectUnauthorized: getReject(self)
})
const getTimetout = (self, cbCalled, request, errback, errMsg = 'ETIMEDOUT') =>
setTimeout( () => {
if (cbCalled) return true
cbCalled = true
request.abort()
var err = new Error(errMsg)
err.code = errMsg
return errback(err)
}, self.opts.timeout || 30000)
const cbErrorBack = (decodedResponse, errback) => {
const err = new Error(decodedResponse.error.message || '')
if (decodedResponse.error.code) {
err.code = decodedResponse.error.code
}
return errback(err)
}
const getErrorBack = ({ code, statusCode = false }) =>
ERRORS[code](statusCode)
const responseCbResult = (callback, decodedResponse, response) =>
(callback)
? callback(decodedResponse.result, response.headers)
: false
const responseCbError = (errback, decodedResponse) =>
(errback)
? cbErrorBack(decodedResponse, errback)
: false
const toDecodedResponse = (response, callback, errback) => (decodedResponse, i) => {
if (isTrue(
decodedResponse.hasOwnProperty('error'),
decodedResponse.error != null)) {
return responseCbError(errback, decodedResponse)
} else if (decodedResponse.hasOwnProperty('result')) {
return responseCbResult(callback, decodedResponse, response)
} else
return responseCbError(errback, decodedResponse)
}
const returnError = (res, err, errback) =>
(res.statusCode !== 200)
? errback(getErrorBack({ code: '-32602', statusCode: res.statusCode }))
: errback(getErrorBack({ code: '-32603'}))
const decodedResponseFinal = (buffer, response, callback, errback) => {
let decoded = JSON.parse(buffer)
if (!Array.isArray(decoded)) decoded = [decoded]
return decoded.map(toDecodedResponse(response, callback, errback))
}
const reqOnResponse = ({cbCalled = false, reqTimeout, callback, errback}) =>
(response) => {
clearTimeout(reqTimeout)
let buffer = ''
response.on('data', (chunk) => {
buffer = buffer + chunk
})
response.on('end', () => {
if (cbCalled) return true
try {
return decodedResponseFinal(buffer, response, callback, errback)
} catch (e) {
return returnError(response, e, errback)
}
})
}
const call = (self) => async function ({method, params, callback, errback, path}) {
const time = Date.now()
const requestJSON = getRequestJSON(method, time, params)
const requestOptions = getRequestOptions(self, path, requestJSON)
path = '/'
if (isTrue(self.opts.ssl, self.opts.sslCa)) {
requestOptions.ca = self.opts.sslCa
}
if (isTrue(self.opts.user, self.opts.pass)) {
requestOptions.auth = self.opts.user + ':' + self.opts.pass
}
const request = self.http.request(requestOptions)
const reqTimeout = getTimetout(self, cbCalled, request, errback)
request.on('error', reqOnError({cbCalled, reqTimeout, errback}))
request.on('response', reqOnResponse({cbCalled, reqTimeout, callback, errback}))
request.end(requestJSON)
}
module.exports.Client = (opts) => {
const client = Client(opts)
return Object.assign(
client,
{ call: call(client) }
)
}
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 || 9332,
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();
var err = new Error('ETIMEDOUT');
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 () {
if (cbCalled) return;
cbCalled = true;
request.abort();
var err = new Error('ESOCKETTIMEDOUT');
err.code = 'ESOCKETTIMEDOUT';
errback(err);
});
request.on('error', function (err) {
if (cbCalled) return;
cbCalled = true;
clearTimeout(reqTimeout);
errback(err);
});
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) {
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);
}
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) {
err = new Error(decodedResponse.error.message || '');
if (decodedResponse.error.code) {
err.code = decodedResponse.error.code;
}
errback(err);
}
} else if (decodedResponse.hasOwnProperty('result')) {
if (callback) {
callback(decodedResponse.result, response.headers);
}
} else {
if (errback) {
err = new Error(decodedResponse.error.message || '')
if (decodedResponse.error.code) {
err.code = decodedResponse.error.code;
}
errback(err);
}
}
});
});
});
request.end(requestJSON);
};
module.exports.Client = Client;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment