bitcore-node-zcash/lib/daemon.js

315 lines
7.6 KiB
JavaScript
Raw Normal View History

'use strict';
2014-08-12 12:03:04 -07:00
var EventEmitter = require('events').EventEmitter;
2015-07-31 08:40:15 -07:00
var bitcoind = require('bindings')('bitcoind.node');
var chainlib = require('chainlib');
var log = chainlib.log;
2014-09-02 19:28:20 -07:00
var util = require('util');
var bitcore = require('bitcore');
var $ = bitcore.util.preconditions;
2014-08-12 12:03:04 -07:00
2015-07-16 14:03:43 -07:00
function Daemon(options) {
2014-08-12 12:03:04 -07:00
var self = this;
2015-07-16 14:03:43 -07:00
if (!(this instanceof Daemon)) {
return new Daemon(options);
2014-08-12 12:03:04 -07:00
}
2014-10-17 12:54:58 -07:00
if (Object.keys(this.instances).length) {
throw new Error('Daemon cannot be instantiated more than once.');
2014-10-17 12:54:58 -07:00
}
2014-08-12 12:03:04 -07:00
EventEmitter.call(this);
$.checkArgument(options.datadir, 'Please specify a datadir');
this.options = options || {};
2014-10-16 13:53:47 -07:00
this.options.datadir = this.options.datadir.replace(/^~/, process.env.HOME);
2014-11-11 13:36:08 -08:00
this.datadir = this.options.datadir;
2014-11-11 13:36:08 -08:00
this.config = this.datadir + '/bitcoin.conf';
2014-10-03 18:27:06 -07:00
Object.keys(exports).forEach(function(key) {
self[key] = exports[key];
});
2014-09-25 14:28:08 -07:00
this.on('newListener', function(name) {
if (name === 'open') {
self.start();
}
});
2014-09-11 17:18:36 -07:00
}
util.inherits(Daemon, EventEmitter);
// Make sure signal handlers are not overwritten
2015-07-16 14:03:43 -07:00
Daemon._signalQueue = [];
Daemon._processOn = process.on;
process.addListener =
process.on = function(name, listener) {
if (~['SIGINT', 'SIGHUP', 'SIGQUIT'].indexOf(name.toUpperCase())) {
2015-07-16 14:03:43 -07:00
if (!Daemon.global || !Daemon.global._started) {
Daemon._signalQueue.push([name, listener]);
return;
}
}
2015-07-16 14:03:43 -07:00
return Daemon._processOn.apply(this, arguments);
};
2015-07-16 14:03:43 -07:00
Daemon.instances = {};
Daemon.prototype.instances = Daemon.instances;
2015-07-16 14:03:43 -07:00
Daemon.__defineGetter__('global', function() {
return Daemon.instances[Object.keys(Daemon.instances)[0]];
});
2015-07-16 14:03:43 -07:00
Daemon.prototype.__defineGetter__('global', function() {
return Daemon.global;
});
2015-07-16 14:03:43 -07:00
Daemon.prototype.start = function(options, callback) {
2014-09-11 17:18:36 -07:00
var self = this;
2014-08-29 13:54:54 -07:00
2014-10-15 16:38:10 -07:00
if (!callback) {
callback = options;
2014-10-16 13:53:47 -07:00
options = null;
}
if (!options) {
2014-10-15 16:38:10 -07:00
options = {};
}
2014-10-16 13:53:47 -07:00
2014-10-15 16:38:10 -07:00
if (!callback) {
callback = function() {};
2014-10-15 16:38:10 -07:00
}
2014-11-11 13:36:08 -08:00
if (this.instances[this.datadir]) {
return;
}
2014-11-11 13:36:08 -08:00
this.instances[this.datadir] = true;
2014-09-25 14:28:08 -07:00
2014-09-17 14:21:28 -07:00
var none = {};
2014-09-22 14:35:11 -07:00
var isSignal = {};
var sigint = { name: 'SIGINT', signal: isSignal };
var sighup = { name: 'SIGHUP', signal: isSignal };
var sigquit = { name: 'SIGQUIT', signal: isSignal };
2014-09-17 14:21:28 -07:00
var exitCaught = none;
var errorCaught = none;
2014-10-16 13:53:47 -07:00
Object.keys(this.options).forEach(function(key) {
if (options[key] == null) {
options[key] = self.options[key];
}
});
2015-07-31 08:40:15 -07:00
bitcoind.start(options, function(err, status) {
self._started = true;
2015-07-09 09:55:53 -07:00
// Poll for queued packet
[sigint, sighup, sigquit].forEach(function(signal) {
2014-09-22 14:35:11 -07:00
process.on(signal.name, signal.listener = function() {
if (process.listeners(signal.name).length > 1) {
return;
}
if (!self._shutdown) {
process.exit(0);
} else {
self.stop();
exitCaught = signal;
}
});
2014-09-19 16:45:46 -07:00
});
2014-09-17 14:21:28 -07:00
// Finally set signal handlers
2015-07-16 14:03:43 -07:00
process.on = process.addListener = Daemon._processOn;
Daemon._signalQueue.forEach(function(event) {
process.on(event[0], event[1]);
});
2014-09-17 14:21:28 -07:00
var exit = process.exit;
self._exit = function() {
return exit.apply(process, arguments);
};
process.exit = function(code) {
exitCaught = code || 0;
if (!self._shutdown) {
return self._exit(code);
2014-09-17 14:21:28 -07:00
}
self.stop();
};
2014-09-17 14:08:26 -07:00
2014-09-17 14:21:28 -07:00
process.on('uncaughtException', function(err) {
if (process.listeners('uncaughtException').length > 1) {
return;
}
2014-09-17 14:21:28 -07:00
errorCaught = err;
2015-08-06 14:14:14 -07:00
log.error('Uncaught error: shutting down safely before throwing...');
2014-09-17 14:21:28 -07:00
if (!self._shutdown) {
if (err && err.stack) {
2015-08-06 14:14:14 -07:00
log.error(err.stack);
}
self._exit(1);
return;
2014-09-17 14:21:28 -07:00
}
self.stop();
});
2014-09-17 14:25:19 -07:00
2015-07-31 08:40:15 -07:00
bitcoind.onBlocksReady(function(err, result) {
2015-07-07 14:02:03 -07:00
function onTipUpdateListener(result) {
if (result) {
// Emit and event that the tip was updated
self.emit('tip', result);
// Recursively wait until the next update
2015-07-31 08:40:15 -07:00
bitcoind.onTipUpdate(onTipUpdateListener);
}
}
2015-07-31 08:40:15 -07:00
bitcoind.onTipUpdate(onTipUpdateListener);
self.emit('ready', result);
2015-07-31 08:40:15 -07:00
bitcoind.startTxMon(function(txs) {
for(var i = 0; i < txs.length; i++) {
self.emit('tx', txs[i]);
}
});
});
setTimeout(function callee() {
// Wait until wallet is loaded:
if (callback) {
callback(err ? err : null);
}
if (err) {
self.emit('error', err);
} else {
if (callback) {
self.emit('open', status);
} else {
self.emit('status', status);
}
}
if (callback) {
callback = null;
}
}, 100);
2014-08-12 12:03:04 -07:00
});
2014-09-02 19:28:20 -07:00
2014-09-10 16:57:18 -07:00
// bitcoind's boost threads aren't in the thread pool
// or on node's event loop, so we need to keep node open.
2014-09-17 14:08:26 -07:00
this._shutdown = setInterval(function() {
2015-07-31 08:40:15 -07:00
if (!self._stoppingSaid && bitcoind.stopping()) {
2014-09-17 14:08:26 -07:00
self._stoppingSaid = true;
}
2014-09-17 14:21:28 -07:00
2015-07-31 08:40:15 -07:00
if (bitcoind.stopped()) {
2014-09-17 14:21:28 -07:00
2014-09-17 14:08:26 -07:00
clearInterval(self._shutdown);
delete self._shutdown;
2014-09-17 14:21:28 -07:00
if (exitCaught !== none) {
2014-09-22 14:35:11 -07:00
if (exitCaught.signal === isSignal) {
process.removeListener(exitCaught.name, exitCaught.listener);
setImmediate(function() {
process.kill(process.pid, exitCaught.name);
});
return;
2014-09-17 14:21:28 -07:00
}
return self._exit(exitCaught);
2014-09-17 14:21:28 -07:00
}
2015-08-06 14:14:14 -07:00
if (errorCaught !== none) {
if (errorCaught && errorCaught.stack) {
log.error(errorCaught.stack);
}
return self._exit(0);
}
2014-09-17 12:52:35 -07:00
}
2014-09-17 14:08:26 -07:00
}, 1000);
2014-09-23 13:57:49 -07:00
};
Daemon.prototype.isSynced = function() {
return bitcoind.isSynced();
};
Daemon.prototype.syncPercentage = function() {
return bitcoind.syncPercentage();
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.getBlock = function(blockhash, callback) {
return bitcoind.getBlock(blockhash, callback);
2014-11-04 16:08:31 -08:00
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.isSpent = function(txid, outputIndex) {
2015-07-31 08:40:15 -07:00
return bitcoind.isSpent(txid, outputIndex);
2015-07-15 14:45:36 -07:00
};
Daemon.prototype.getBlockIndex = function(blockHash) {
2015-07-31 08:40:15 -07:00
return bitcoind.getBlockIndex(blockHash);
};
2015-07-28 13:03:55 -07:00
Daemon.prototype.estimateFee = function(blocks) {
2015-07-31 08:40:15 -07:00
return bitcoind.estimateFee(blocks);
2015-07-28 13:03:55 -07:00
};
Daemon.prototype.sendTransaction = function(transaction, allowAbsurdFees) {
2015-07-31 08:40:15 -07:00
return bitcoind.sendTransaction(transaction, allowAbsurdFees);
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.getTransaction = function(txid, queryMempool, callback) {
2015-07-31 08:40:15 -07:00
return bitcoind.getTransaction(txid, queryMempool, callback);
2014-09-22 12:05:17 -07:00
};
2015-07-29 14:13:51 -07:00
Daemon.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
2015-07-31 08:40:15 -07:00
return bitcoind.getTransactionWithBlockInfo(txid, queryMempool, callback);
2015-07-29 14:13:51 -07:00
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.getMempoolOutputs = function(address) {
2015-07-31 08:40:15 -07:00
return bitcoind.getMempoolOutputs(address);
2015-07-17 12:55:36 -07:00
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.addMempoolUncheckedTransaction = function(txBuffer) {
2015-07-31 08:40:15 -07:00
return bitcoind.addMempoolUncheckedTransaction(txBuffer);
};
2015-07-16 14:03:43 -07:00
Daemon.prototype.getInfo = function() {
2015-07-31 08:40:15 -07:00
return bitcoind.getInfo();
2014-10-17 13:26:27 -07:00
};
Daemon.prototype.stop = function(callback) {
if (Daemon.stopping) return [];
2014-09-11 17:18:36 -07:00
var self = this;
2015-07-31 08:40:15 -07:00
return bitcoind.stop(function(err, status) {
2014-09-11 17:18:36 -07:00
if (err) {
self.error(err.message);
} else {
log.info(status);
2014-09-11 17:18:36 -07:00
}
if (!callback) return;
return callback(err, status);
});
2014-09-10 16:57:18 -07:00
};
2014-09-02 19:28:20 -07:00
2015-07-16 14:03:43 -07:00
Daemon.prototype.__defineGetter__('stopping', function() {
2015-07-31 08:40:15 -07:00
return bitcoind.stopping() || bitcoind.stopped();
2014-12-12 11:00:24 -08:00
});
2015-07-16 14:03:43 -07:00
Daemon.prototype.__defineGetter__('stopped', function() {
2015-07-31 08:40:15 -07:00
return bitcoind.stopped();
2014-12-12 11:00:24 -08:00
});
2015-07-16 14:03:43 -07:00
Daemon.__defineGetter__('stopping', function() {
2015-07-31 08:40:15 -07:00
return bitcoind.stopping() || bitcoind.stopped();
2014-12-12 11:00:24 -08:00
});
2015-07-16 14:03:43 -07:00
Daemon.__defineGetter__('stopped', function() {
2015-07-31 08:40:15 -07:00
return bitcoind.stopped();
2014-12-12 11:00:24 -08:00
});
module.exports = Daemon;