Skip to content

Commit

Permalink
[UPDATE] Clean up structure
Browse files Browse the repository at this point in the history
  • Loading branch information
nrpatten committed Oct 20, 2014
1 parent c7ada41 commit 4c37aeb
Show file tree
Hide file tree
Showing 5 changed files with 300 additions and 15 deletions.
14 changes: 4 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ You'll need a running instance of a [litecoind](https://github.com/litecoin-proj

Then, install the node-altcoin NPM package.

`npm install node-altcoin`

or

`npm install git://github.com/nrpatten/node-altcoin/`

## Examples
Expand Down Expand Up @@ -88,8 +92,6 @@ Generates authorization header, returns `this` for chainability

## Commands

TODO: Write tests for these.

All [Litecoin API](https://litecoin.info/Litecoin_API) commands are supported, in lowercase or camelcase form.

<table>
Expand Down Expand Up @@ -526,11 +528,3 @@ var altcoin = require('node-altcoin')({
ca: ca
})
```

## Testing

```
npm install -g nodeunit
nodeunit test/test-node-altcoin.js
```
195 changes: 195 additions & 0 deletions altcoin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
var http = require('http')
, https = require('https')

var api = require('./commands')
, errors = require('./errors')

function Client(options) {
this.opts = {
host: 'localhost'
, port: 7142
, method: 'POST'
, user: ''
, pass: ''
, headers: {
'Host': 'localhost'
, 'Authorization': ''
}
, passphrasecallback: null
, https: false
, ca: null
}

if (options) {
this.set(options)
}
}

Client.prototype = {

invalid:function(command) {
var args = Array.prototype.slice.call(arguments, 1)
, fn = args.pop()

if (typeof fn !== 'function') {
fn = console.log
}

return fn(new Error('No such command "' + command + '"'))
},

send:function(command) {
var args = Array.prototype.slice.call(arguments, 1)
, self = this
, fn

if (typeof args[args.length-1] === 'function') {
fn = args.pop().bind(this)
}else {
fn = console.log
}

var rpcData = JSON.stringify({
id: new Date().getTime()
, method: command.toLowerCase()
, params: args
})

var options = this.opts
options.headers['Content-Length'] = rpcData.length

var request;
if (options.https === true){
request = https.request;
} else{
request = http.request;
}

var req = request(options, function(res) {
var data = ''
res.setEncoding('utf8')
res.on('data', function(chunk) {
data += chunk
})
res.on('end', function() {
try {
data = JSON.parse(data)
}catch(exception) {
var errMsg = res.statusCode !== 200
? 'Invalid params ' + res.statusCode
: 'Failed to parse JSON'
errMsg += ' : '+JSON.stringify(data)
return fn(new Error(errMsg))
}
if (data.error) {
if (data.error.code === errors.RPC_WALLET_UNLOCK_NEEDED &&
options.passphrasecallback) {
return self.unlock(command, args, fn)
} else {
var err = new Error(JSON.stringify(data))
err.code = data.error.code
return fn(err)
}
}
fn(null, data.result !== null ? data.result : data)
})
})

req.on('error', fn)
req.end(rpcData)
return this
},

exec:function(command) {
var func = api.isCommand(command) ? 'send' : 'invalid'
return this[func].apply(this, arguments)
},

auth:function(user, pass) {
if (user && pass) {
var authString = ('Basic ') + new Buffer(user+':'+pass).toString('base64')
this.opts.headers['Authorization'] = authString
}
return this
},

unlock:function(command, args, fn) {
var self = this

var retry = function(err) {
if (err) {
fn(err)
} else {
var sendargs = args.slice();
sendargs.unshift(command);
sendargs.push(fn)
self.send.apply(self, sendargs)
}
}

this.opts.passphrasecallback(command, args, function(err, passphrase, timeout) {
if (err) {
fn(err)
} else {
self.send('walletpassphrase', passphrase, timeout, retry)
}
})
},

set:function(k, v) {
var type = typeof(k);

if (typeof(k) === 'object') {
for (var key in k) {
this.set(key, k[key]);
};
return;
};

var opts = this.opts;
var k = k.toLowerCase();

if (opts.hasOwnProperty(k)) {
opts[k] = v
if (/^(user|pass)$/.test(k)) {
this.auth(opts.user, opts.pass)
}else if (k === 'host') {
opts.headers['Host'] = v
}else if (k === 'passphrasecallback' ||
k === 'https' ||
k === 'ca') {
opts[k] = v
}
}

return this;
},

get:function(k) {
//Special case for booleans
if(this.opts[k] === false){
return false;
}else {
if(this.opts[k] !== false){
var opt = this.opts[k.toLowerCase()]
}
return opt; //new Error('No such option "'+k+'" exists');
}
},

errors: errors

}

api.commands.forEach(function(command) {
var cp = Client.prototype;
var tlc = [command.toLowerCase()];

cp[command] = cp[tlc] = function() {
cp.send.apply(this, tlc.concat(([]).slice.call(arguments)));
};
})

module.exports = function(options) {
return new Client(options)
}
67 changes: 67 additions & 0 deletions commands.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

var commands = module.exports.commands = [
'addMultiSigAddress'
, 'backupWallet'
, 'createRawTransaction'
, 'decodeRawTransaction'
, 'dumpPrivKey'
, 'encryptWallet'
, 'getAccount'
, 'getAccountAddress'
, 'getAddressesByAccount'
, 'getBalance'
, 'getBlock'
, 'getBlockCount'
, 'getBlockHash'
, 'getBlockCount'
, 'getConnectionCount'
, 'getDifficulty'
, 'getGenerate'
, 'getHashesPerSec'
, 'getHashesPerSec'
, 'getInfo'
, 'getnetworkhashps'
, 'getMemoryPool'
, 'getMemoryPool'
, 'getMiningInfo'
, 'getNewAddress'
, 'getRawTransaction'
, 'getReceivedByAccount'
, 'getReceivedByAddress'
, 'getTransaction'
, 'getWork'
, 'help'
, 'importPrivKey'
, 'keyPoolRefill'
, 'listAccounts'
, 'listReceivedByAccount'
, 'listReceivedByAddress'
, 'listSinceBlock'
, 'listTransactions'
, 'listUnspent'
, 'move'
, 'sendFrom'
, 'sendMany'
, 'sendRawTransaction'
, 'sendToAddress'
, 'setAccount'
, 'setGenerate'
, 'setTxFee'
, 'signMessage'
, 'signRawTransaction'
, 'stop'
, 'validateAddress'
, 'verifyMessage'
, 'walletLock'
, 'walletPassphrase'
, 'walletPassphraseChange'
]

module.exports.isCommand = function(command) {
command = command.toLowerCase()
for (var i=0, len=commands.length; i<len; i++) {
if (commands[i].toLowerCase() === command) {
return true
}
}
}
32 changes: 32 additions & 0 deletions errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module.exports = {
RPC_INVALID_REQUEST : -32600,
RPC_METHOD_NOT_FOUND : -32601,
RPC_INVALID_PARAMS : -32602,
RPC_INTERNAL_ERROR : -32603,
RPC_PARSE_ERROR : -32700,

// General application defined errors
RPC_MISC_ERROR : -1, // std::exception thrown in command handling
RPC_FORBIDDEN_BY_SAFE_MODE : -2, // Server is in safe mode, and command is not allowed in safe mode
RPC_TYPE_ERROR : -3, // Unexpected type was passed as parameter
RPC_INVALID_ADDRESS_OR_KEY : -5, // Invalid address or key
RPC_OUT_OF_MEMORY : -7, // Ran out of memory during operation
RPC_INVALID_PARAMETER : -8, // Invalid, missing or duplicate parameter
RPC_DATABASE_ERROR : -20, // Database error
RPC_DESERIALIZATION_ERROR : -22, // Error parsing or validating structure in raw format

// P2P client errors
RPC_CLIENT_NOT_CONNECTED : -9, // Bitcoin is not connected
RPC_CLIENT_IN_INITIAL_DOWNLOAD : -10, // Still downloading initial blocks

// Wallet errors
RPC_WALLET_ERROR : -4, // Unspecified problem with wallet (key not found etc.)
RPC_WALLET_INSUFFICIENT_FUNDS : -6, // Not enough funds in wallet or account
RPC_WALLET_INVALID_ACCOUNT_NAME : -11, // Invalid account name
RPC_WALLET_KEYPOOL_RAN_OUT : -12, // Keypool ran out, call keypoolrefill first
RPC_WALLET_UNLOCK_NEEDED : -13, // Enter the wallet passphrase with walletpassphrase first
RPC_WALLET_PASSPHRASE_INCORRECT : -14, // The wallet passphrase entered was incorrect
RPC_WALLET_WRONG_ENC_STATE : -15, // Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
RPC_WALLET_ENCRYPTION_FAILED : -16, // Failed to encrypt the wallet
RPC_WALLET_ALREADY_UNLOCKED : -17 // Wallet is already unlocked
}
7 changes: 2 additions & 5 deletions package.json
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
{
"name": "node-altcoin",
"version": "0.1.1",
"version": "0.1.2",
"description": "AltCoin RPC Node Client",
"main": "lib/altcoin.js",
"directories": {
"test": "test"
},
"main": "./altcoin.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down

0 comments on commit 4c37aeb

Please sign in to comment.