diff --git a/bin/start.js b/bin/start.js index 7b65c58c..9b9f716a 100644 --- a/bin/start.js +++ b/bin/start.js @@ -141,3 +141,33 @@ node.chain.on('addblock', function(block) { }, 10000); } }); + +process.stdin.resume();//so the program will not close instantly + +function exitHandler(options, err) { + if (err) { + log.error('uncaught exception:', err); + if(err.stack) { + console.log(err.stack); + } + process.exit(-1); + } + if (options.sigint) { + log.info('Stopping Services'); + node.stop(function(err) { + if(err) { + log.error('Failed to stop services: ' + err); + return process.exit(1); + } + + log.info('Halted'); + process.exit(0); + }); + } +} + +//catches ctrl+c event +process.on('SIGINT', exitHandler.bind(null, {sigint:true})); + +//catches uncaught exceptions +process.on('uncaughtException', exitHandler.bind(null, {exit:true})); diff --git a/lib/chain.js b/lib/chain.js index f9e7c200..7e93d38b 100644 --- a/lib/chain.js +++ b/lib/chain.js @@ -50,6 +50,15 @@ function Chain(options) { util.inherits(Chain, BaseChain); +Chain.prototype.start = function(callback) { + this.on('initialized', callback); + this.initialize(); +}; + +Chain.prototype.stop = function(callback) { + setImmediate(callback); +}; + Chain.prototype._writeBlock = function(block, callback) { // Update hashes this.cache.hashes[block.hash] = block.prevHash; diff --git a/lib/daemon.js b/lib/daemon.js index 429efa9f..23cc18d0 100644 --- a/lib/daemon.js +++ b/lib/daemon.js @@ -35,7 +35,7 @@ function Daemon(options) { this.on('newListener', function(name) { if (name === 'open') { - self.start(); + //self.start(); } }); } @@ -67,22 +67,9 @@ Daemon.prototype.__defineGetter__('global', function() { return Daemon.global; }); -Daemon.prototype.start = function(options, callback) { +Daemon.prototype.start = function(callback) { var self = this; - if (!callback) { - callback = options; - options = null; - } - - if (!options) { - options = {}; - } - - if (!callback) { - callback = function() {}; - } - if (this.instances[this.datadir]) { return; } @@ -97,12 +84,12 @@ Daemon.prototype.start = function(options, callback) { var errorCaught = none; Object.keys(this.options).forEach(function(key) { - if (options[key] == null) { - options[key] = self.options[key]; + if (self.options[key] == null) { + self.options[key] = self.options[key]; } }); - bitcoind.start(options, function(err, status) { + bitcoind.start(this.options, function(err, status) { self._started = true; // Poll for queued packet @@ -179,23 +166,12 @@ Daemon.prototype.start = function(options, callback) { }); setTimeout(function callee() { - // Wait until wallet is loaded: - if (callback) { - callback(err ? err : null); - } - if (err) { self.emit('error', err); + callback(err); } else { - if (callback) { - self.emit('open', status); - } else { - self.emit('status', status); - } - } - - if (callback) { - callback = null; + self.emit('open', status); + callback(); } }, 100); }); diff --git a/lib/db.js b/lib/db.js index cdb01423..43733b02 100644 --- a/lib/db.js +++ b/lib/db.js @@ -40,7 +40,7 @@ function DB(options) { util.inherits(DB, BaseDB); -DB.prototype.initialize = function() { +DB.prototype.start = function(callback) { // Add all db option modules if(this._modules && this._modules.length) { for(var i = 0; i < this._modules.length; i++) { @@ -49,7 +49,12 @@ DB.prototype.initialize = function() { } this.bitcoind.on('tx', this.transactionHandler.bind(this)); this.emit('ready'); -} + callback(); +}; + +DB.prototype.stop = function(callback) { + this.store.close(callback); +}; DB.prototype.getBlock = function(hash, callback) { var self = this; diff --git a/lib/module.js b/lib/module.js index b9e39e66..0f15fb3b 100644 --- a/lib/module.js +++ b/lib/module.js @@ -45,4 +45,12 @@ Module.prototype.getAPIMethods = function() { // // }; +Module.prototype.start = function() { + +}; + +Module.prototype.stop = function() { + +}; + module.exports = Module; diff --git a/lib/node.js b/lib/node.js index a4f6bee7..d3f5c804 100644 --- a/lib/node.js +++ b/lib/node.js @@ -25,6 +25,12 @@ function Node(config) { util.inherits(Node, BaseNode); +var defaultServices = { + 'bitcoind': [], + 'db': ['bitcoind'], + 'chain': ['db'], +}; + Node.prototype.openBus = function() { return new Bus({db: this.db}); }; @@ -372,15 +378,23 @@ Node.prototype._loadConsensus = function(config) { this.chain = new Chain(config.consensus); }; -Node.prototype._initializeBitcoind = function() { +Node.prototype._initialize = function() { var self = this; + // DB References + this.db.chain = this.chain; + this.db.Block = this.Block; + this.db.bitcoind = this.bitcoind; + + // Chain References + this.chain.db = this.db; + + // Bitcoind this.bitcoind.on('ready', function(status) { log.info('Bitcoin Daemon Ready'); // Set the current chain height var info = self.bitcoind.getInfo(); self.bitcoindHeight = info.blocks; - self.db.initialize(); }); this.bitcoind.on('open', function(status) { @@ -400,27 +414,6 @@ Node.prototype._initializeBitcoind = function() { self.emit('error', err); }); -}; - -Node.prototype._initializeDatabase = function() { - var self = this; - - // Database - this.db.on('ready', function() { - log.info('Bitcoin Database Ready'); - self.chain.initialize(); - }); - - this.db.on('error', function(err) { - Error.captureStackTrace(err); - self.emit('error', err); - }); - -}; - -Node.prototype._initializeChain = function() { - var self = this; - // Chain this.chain.on('ready', function() { log.info('Bitcoin Chain Ready'); @@ -432,23 +425,74 @@ Node.prototype._initializeChain = function() { Error.captureStackTrace(err); self.emit('error', err); }); + + // Database + this.db.on('ready', function() { + log.info('Bitcoin Database Ready'); + }); + + this.db.on('error', function(err) { + Error.captureStackTrace(err); + self.emit('error', err); + }); + + this.start(function(err) { + if(err) { + log.error('Failed starting services: ' + err); + } + }); }; -Node.prototype._initialize = function() { +Node.prototype.getServiceOrder = function(services, keys, stack) { + if(!services) { + services = defaultServices; + } - // DB References - this.db.chain = this.chain; - this.db.Block = this.Block; - this.db.bitcoind = this.bitcoind; + if(!keys) { + keys = Object.keys(services); + } - // Chain References - this.chain.db = this.db; + if(!stack) { + stack = []; + } - // Setup Chain of Events - this._initializeBitcoind(); - this._initializeDatabase(); - this._initializeChain(); + for(var i = 0; i < keys.length; i++) { + this.getServiceOrder(services, services[keys[i]], stack); + if(stack.indexOf(keys[i]) === -1) { + stack.push(keys[i]); + } + } + return stack; }; +Node.prototype.start = function(callback) { + var self = this; + var services = this.getServiceOrder(); + + async.eachSeries( + services, + function(service, next) { + log.info('Starting ' + service); + self[service].start(next); + }, + callback + ); +}; + +Node.prototype.stop = function(callback) { + var self = this; + var services = this.getServiceOrder().reverse(); + + async.eachSeries( + services, + function(service, next) { + log.info('Stopping ' + service); + self[service].stop(next); + }, + callback + ); +}; + + module.exports = Node; diff --git a/test/node.unit.js b/test/node.unit.js index 674f3ed4..203476ad 100644 --- a/test/node.unit.js +++ b/test/node.unit.js @@ -533,4 +533,20 @@ describe('Bitcoind Node', function() { }); }); + + describe('#getServiceOrder', function() { + var services = { + 'chain': ['db'], + 'db': ['daemon', 'p2p'], + 'daemon': [], + 'p2p': [] + }; + + it('should return the services in the correct order', function() { + var node = new Node({}); + var order = node.getServiceOrder(services); + + order.should.deep.equal(['daemon', 'p2p', 'db', 'chain']); + }); + }); });