flocore-node/lib/bitcoind.js
Christopher Jeffrey 4038258347 emit blocks.
2014-09-22 18:21:08 -07:00

247 lines
5.7 KiB
JavaScript

/**
* bitcoind.js
* Copyright (c) 2014, BitPay (MIT License)
* A bitcoind node.js binding.
*/
var net = require('net');
var EventEmitter = require('events').EventEmitter;
var bitcoindjs = require('../build/Release/bitcoindjs.node');
var util = require('util');
var net = require('net');
/**
* Bitcoin
*/
function Bitcoin(options) {
var self = this;
if (!(this instanceof Bitcoin)) {
return new Bitcoin(options);
}
EventEmitter.call(this);
this.options = options;
}
Bitcoin.prototype.__proto__ = EventEmitter.prototype;
Bitcoin.prototype.start = function(callback) {
var self = this;
var none = {};
var isSignal = {};
var sigint = { name: 'SIGINT', signal: isSignal };
var sighup = { name: 'SIGHUP', signal: isSignal };
var sigquit = { name: 'SIGQUIT', signal: isSignal };
var exitCaught = none;
var errorCaught = none;
this.log_pipe = bitcoindjs.start(function(err, status) {
[sigint, sighup, sigquit].forEach(function(signal) {
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;
}
});
});
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);
}
self.stop();
};
process.on('uncaughtException', function(err) {
if (process.listeners('uncaughtException').length > 1) {
return;
}
errorCaught = err;
if (!self._shutdown) {
if (err && err.stack) {
console.error(err.stack);
}
self._exit(1);
return;
}
self.stop();
});
if (callback) {
callback(err);
callback = null;
}
if (err) {
self.emit('error', err);
} else {
self.emit('open', status);
}
});
// bitcoind's boost threads aren't in the thread pool
// or on node's event loop, so we need to keep node open.
this._shutdown = setInterval(function() {
if (!self._stoppingSaid && bitcoindjs.stopping()) {
self._stoppingSaid = true;
self.log('shutting down...');
}
if (bitcoindjs.stopped()) {
self.log('shut down.');
clearInterval(self._shutdown);
delete self._shutdown;
if (exitCaught !== none) {
if (exitCaught.signal === isSignal) {
process.removeListener(exitCaught.name, exitCaught.listener);
setImmediate(function() {
process.kill(process.pid, exitCaught.name);
});
return;
}
return self._exit(exitCaught);
}
if (errorCaught !== none) {
if (errorCaught && errorCaught.stack) {
console.error(errorCaught.stack);
}
return self._exit(0);
}
}
}, 1000);
this.pollInterval = 300;
(function next() {
bitcoindjs.pollBlocks(function(err, blocks) {
if (err) return setTimeout(next, self.pollInterval);
utils.forEach(blocks, function(block, nextBlock) {
self.emit('block', block);
setImmediate(function() {
nextBlock();
});
}, function() {
setTimeout(next, self.pollInterval);
});
});
})();
if (this.log_pipe !== -1) {
this.log('log pipe opened: %d', this.log_pipe);
this._pipe = new net.Socket(this.log_pipe);
this._pipe.on('data', function(data) {
return process.stdout.write('bitcoind: ' + data + '\n');
});
this._pipe.on('error', function(err) {
; // ignore for now
});
this._pipe.resume();
}
};
Bitcoin.prototype.getBlock = function(blockHash, callback) {
return bitcoindjs.getBlock(blockHash, callback);
};
Bitcoin.prototype.getTx = function(txHash, blockHash, callback) {
if (!callback) {
callback = blockHash;
blockHash = '';
}
// if (txHash[1] === 'x') txHash = txHash.slice(2);
// txHash = utils.revHex(txHash);
// if (blockHash) {
// if (blockHash[1] === 'x') blockHash = blockHash.slice(2);
// blockHash = utils.revHex(blockHash);
// }
return bitcoindjs.getTx(txHash, blockHash, callback);
};
Bitcoin.prototype.log =
Bitcoin.prototype.info = function() {
if (typeof arguments[0] !== 'string') {
var out = util.inspect(arguments[0], null, 20, true);
return process.stdout.write('bitcoind.js: ' + out + '\n');
}
var out = util.format.apply(util, arguments);
return process.stdout.write('bitcoind.js: ' + out + '\n');
};
Bitcoin.prototype.error = function() {
if (typeof arguments[0] !== 'string') {
var out = util.inspect(arguments[0], null, 20, true);
return process.stderr.write('bitcoind.js: ' + out + '\n');
}
var out = util.format.apply(util, arguments);
return process.stderr.write('bitcoind.js: ' + out + '\n');
};
Bitcoin.prototype.stop =
Bitcoin.prototype.close = function(callback) {
var self = this;
return bitcoindjs.stop(function(err, status) {
if (err) {
self.error(err.message);
} else {
self.log(status);
}
if (!callback) return;
return callback(err, status);
});
};
/**
* Utils
*/
var utils = {};
utils.revHex = function revHex(s) {
var r = '';
for (var i = 0; i < s.length; i += 2) {
r = s.slice(i, i + 2) + r;
}
return r;
};
utils.forEach = function(obj, iter, done) {
var pending = obj.length;
if (!pending) return done();
var next = function() {
if (!--pending) done();
};
obj.forEach(function(item) {
iter(item, next);
});
};
/**
* Expose
*/
module.exports = exports = Bitcoin;
exports.Bitcoin = Bitcoin;
exports.native = bitcoindjs;
exports.utils = utils;