Skip to content

Commit

Permalink
Merge pull request #135 from braydonf/cli
Browse files Browse the repository at this point in the history
CLI and Module Architecture
  • Loading branch information
pnagurny committed Aug 25, 2015
2 parents 51837fc + 7559a4f commit 2168309
Show file tree
Hide file tree
Showing 16 changed files with 1,077 additions and 192 deletions.
25 changes: 20 additions & 5 deletions README.md
Expand Up @@ -5,16 +5,31 @@ A Node.js module that adds a native interface to Bitcoin Core for querying infor

## Install

Here is how you can you install and start your node:

```bash
git clone https://github.com/bitpay/bitcore-node.git
cd bitcore-node
npm install
npm install -g bitcore-node@0.2.0-beta.4
bitcore-node start
```
Note: For convenience, we distribute binaries for x86_64 Linux and x86_64 Mac OS X. Upon npm install, the binaries for your platform will be downloaded. This greatly speeds up the process of using this project. If you don't want to compile the project for yourself, then please skip down to "Example Usage" section for next steps. Please see detailed instructions below for complete build details and dependencies needed for installation if you choose to build the project from source.

Note: For your convenience, we distribute binaries for x86_64 Linux and x86_64 Mac OS X. Upon npm install, the binaries for your platform will be downloaded. If you want to compile the project yourself, then please see the [Build & Install](#build--install) for full detailed instructions to build the project from source.

## Configuration

Bitcore Node includes a Command Line Interface (CLI) for managing, configuring and interfacing with your Bitcore Node. At the minimum, your node can function with all of the features from Bitcoin Core running as a full node. However you can enable additional features to make your node more useful such as exposing new APIs, adding new indexes for addresses, running a block explorer and custom modules.

```bash
bitcore-node create -d <bitcoin-data-dir> mynode "My Node"
cd mynode
bitcore-node add <module>
bitcore-node add https://github.com/yourname/helloworld
```

This will create a directory with configuration files for your node and install the necessary dependencies. If you're interested in developing a module, please see the [Module Development Guide](#modules).

## Build & Install

There are two main parts of the build, compiling Bitcoin Core as a static library and the Node.js bindings.
This includes a detailed instructions for compiling. There are two main parts of the build, compiling Bitcoin Core as a static library and the Node.js bindings.

### Ubuntu 14.04 (Unix/Linux)

Expand Down
4 changes: 2 additions & 2 deletions RELEASE.md
Expand Up @@ -32,7 +32,7 @@ Ensure you've followed the instructions in the README.md for building the projec

When publishing to npm, the .gitignore file is used to exclude files from the npm publishing process. Be sure that the bitcore-node directory has only the directories and files that you would like to publish to npm. You might need to run the commands below on each platform that you intend to publish (e.g. Mac and Linux).

To make a release, bump the version of the package.json:
To make a release, bump the `version` and `lastBuild` of the `package.json`:

```bash
git checkout master
Expand All @@ -44,7 +44,7 @@ npm run upload
npm publish
```

And then update the version of the package.json for development (e.g. "0.3.2-dev"):
And then update the `version` of the `package.json` for development (e.g. "0.3.2-dev"):

```bash
git commit -a -m "Bump development version to <version>"
Expand Down
175 changes: 3 additions & 172 deletions bin/start.js
@@ -1,175 +1,6 @@
'use strict';

var BitcoinNode = require('..').Node;
var chainlib = require('chainlib');
var socketio = require('socket.io');
var log = chainlib.log;
log.debug = function() {};
var start = require('../lib/scaffold/start');
var defaultConfig = require('../lib/scaffold/default-config');

var configuration = {
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
network: process.env.BITCORENODE_NETWORK || 'livenet',
port: 3000
};

var node = new BitcoinNode(configuration);

var count = 0;
var interval = false;

function logSyncStatus() {
log.info('Sync Status: Tip:', node.chain.tip.hash, 'Height:', node.chain.tip.__height, 'Rate:', count/10, 'blocks per second');
}

node.on('synced', function() {
// Stop logging of sync status
clearInterval(interval);
interval = false;
logSyncStatus();
});

node.on('ready', function() {

var io = socketio(configuration.port);

io.on('connection', function(socket) {

var bus = node.openBus();

var methods = node.getAllAPIMethods();
var methodsMap = {};

methods.forEach(function(data) {
var name = data[0];
var instance = data[1];
var method = data[2];
var args = data[3];
methodsMap[name] = {
fn: function() {
return method.apply(instance, arguments);
},
args: args
};
});

socket.on('message', function(message, socketCallback) {
if (methodsMap[message.method]) {
var params = message.params;

if(!params || !params.length) {
params = [];
}

if(params.length !== methodsMap[message.method].args) {
return socketCallback({
error: {
message: 'Expected ' + methodsMap[message.method].args + ' parameters'
}
});
}

var callback = function(err, result) {
var response = {};
if(err) {
response.error = {
message: err.toString()
};
}

if(result) {
response.result = result;
}

socketCallback(response);
};

params = params.concat(callback);
methodsMap[message.method].fn.apply(this, params);
} else {
socketCallback({
error: {
message: 'Method Not Found'
}
});
}
});

socket.on('subscribe', function(name, params) {
bus.subscribe(name, params);
});

socket.on('unsubscribe', function(name, params) {
bus.unsubscribe(name, params);
});

var events = node.getAllPublishEvents();

events.forEach(function(event) {
bus.on(event.name, function() {
if(socket.connected) {
var results = [];

for(var i = 0; i < arguments.length; i++) {
results.push(arguments[i]);
}

var params = [event.name].concat(results);
socket.emit.apply(socket, params);
}
});
});

socket.on('disconnect', function() {
bus.close();
});

});

});

node.on('error', function(err) {
log.error(err);
});

node.chain.on('addblock', function(block) {
count++;
// Initialize logging if not already instantiated
if (!interval) {
interval = setInterval(function() {
logSyncStatus();
count = 0;
}, 10000);
}
});

node.on('stopping', function() {
clearInterval(interval);
});

function exitHandler(options, err) {
if (err) {
log.error('uncaught exception:', err);
if(err.stack) {
console.log(err.stack);
}
process.exit(-1);
}
if (options.sigint) {
node.stop(function(err) {
if(err) {
log.error('Failed to stop services: ' + err);
return process.exit(1);
}

log.info('Halted');
process.exit(0);
});
}
}

//catches uncaught exceptions


process.on('uncaughtException', exitHandler.bind(null, {exit:true}));
//catches ctrl+c event
process.on('SIGINT', exitHandler.bind(null, {sigint:true}));
start(defaultConfig());
85 changes: 85 additions & 0 deletions cli/bitcore-node.js
@@ -0,0 +1,85 @@
#!/usr/bin/env node

'use strict';

var program = require('commander');
var version = require(__dirname + '/../package.json').version;
var bitcore = require('bitcore');
var $ = bitcore.util.preconditions;
var path = require('path');
var create = require('../lib/scaffold/create');
var add = require('../lib/scaffold/add');
var start = require('../lib/scaffold/start');
var findConfig = require('../lib/scaffold/find-config');
var defaultConfig = require('../lib/scaffold/default-config');

program
.version(version);

program
.command('create <directory> [name]')
.description('Create a new node')
.option('-d, --datadir <dir>', 'Specify the bitcoin database directory')
.action(function(dirname, name, cmd){
if (cmd.datadir) {
cmd.datadir = path.resolve(process.cwd(), cmd.datadir);
}
var opts = {
cwd: process.cwd(),
dirname: dirname,
name: name,
datadir: cmd.datadir || './data',
isGlobal: false
};
create(opts, function(err) {
if (err) {
throw err;
}
console.log('Successfully created node in directory: ', dirname);
});
});

program
.command('start')
.description('Start the current node')
.option('-c, --config <dir>', 'Specify the directory with Bitcore Node configuration')
.action(function(cmd){
if (cmd.config) {
cmd.config = path.resolve(process.cwd(), cmd.config);
}
var configInfo = findConfig(cmd.config || process.cwd());
if (!configInfo) {
configInfo = defaultConfig();
}
start(configInfo);
});

program
.command('add <modules...>')
.alias('install')
.description('Install a module for the current node')
.action(function(modules){
var configInfo = findConfig(process.cwd());
if (!configInfo) {
throw new Error('Could not find configuration, see `bitcore-node create --help`');
}
var opts = {
path: configInfo.path,
modules: modules
};
add(opts, function() {
console.log('Successfully added modules: ', modules.join(', '));
});
}).on('--help', function() {
console.log(' Examples:');
console.log();
console.log(' $ bitcore-node add wallet-service');
console.log(' $ bitcore-node add insight-api');
console.log();
});

program.parse(process.argv);

if (process.argv.length === 2) {
program.help();
}
14 changes: 6 additions & 8 deletions lib/node.js
Expand Up @@ -57,12 +57,11 @@ Node.DEFAULT_DAEMON_CONFIG = 'whitelist=127.0.0.1\n' + 'txindex=1\n';

Node.prototype._loadBitcoinConf = function(config) {
$.checkArgument(config.datadir, 'Please specify "datadir" in configuration options');
var datadir = config.datadir.replace(/^~/, process.env.HOME);
var configPath = datadir + '/bitcoin.conf';
var configPath = config.datadir + '/bitcoin.conf';
this.bitcoinConfiguration = {};

if (!fs.existsSync(datadir)) {
mkdirp.sync(datadir);
if (!fs.existsSync(config.datadir)) {
mkdirp.sync(config.datadir);
}

if (!fs.existsSync(configPath)) {
Expand Down Expand Up @@ -329,13 +328,12 @@ Node.prototype._loadDB = function(config) {
$.checkArgument(config.datadir, 'Please specify "datadir" in configuration options');
$.checkState(this.network, 'Network property not defined');
var regtest = Networks.get('regtest');
var datadir = config.datadir.replace(/^~/, process.env.HOME);
if (this.network === Networks.livenet) {
options.path = datadir + '/bitcore-node.db';
options.path = config.datadir + '/bitcore-node.db';
} else if (this.network === Networks.testnet) {
options.path = datadir + '/testnet3/bitcore-node.db';
options.path = config.datadir + '/testnet3/bitcore-node.db';
} else if (this.network === regtest) {
options.path = datadir + '/regtest/bitcore-node.db';
options.path = config.datadir + '/regtest/bitcore-node.db';
} else {
throw new Error('Unknown network: ' + this.network);
}
Expand Down

0 comments on commit 2168309

Please sign in to comment.