Merge pull request #188 from pnagurny/feature/more-changes
More changes
This commit is contained in:
commit
d068681283
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,3 +29,4 @@ libbitcoind
|
|||||||
libbitcoind*
|
libbitcoind*
|
||||||
libbitcoind.includes
|
libbitcoind.includes
|
||||||
*.log
|
*.log
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@ -145,6 +145,7 @@ Node.prototype._instantiateService = function(service) {
|
|||||||
|
|
||||||
var config = service.config;
|
var config = service.config;
|
||||||
config.node = this;
|
config.node = this;
|
||||||
|
config.name = service.name;
|
||||||
var mod = new service.module(config);
|
var mod = new service.module(config);
|
||||||
|
|
||||||
// include in loaded services
|
// include in loaded services
|
||||||
|
|||||||
@ -9,16 +9,7 @@ var path = require('path');
|
|||||||
var packageFile = require('../../package.json');
|
var packageFile = require('../../package.json');
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var defaultConfig = require('./default-config');
|
||||||
var BASE_CONFIG = {
|
|
||||||
name: 'My Node',
|
|
||||||
services: [
|
|
||||||
'address'
|
|
||||||
],
|
|
||||||
datadir: './data',
|
|
||||||
network: 'livenet',
|
|
||||||
port: 3001
|
|
||||||
};
|
|
||||||
|
|
||||||
var version;
|
var version;
|
||||||
if (packageFile.version.match('-dev')) {
|
if (packageFile.version.match('-dev')) {
|
||||||
@ -59,19 +50,19 @@ function createBitcoinDirectory(datadir, done) {
|
|||||||
/**
|
/**
|
||||||
* Will create a base Bitcore Node configuration directory and files.
|
* Will create a base Bitcore Node configuration directory and files.
|
||||||
* @param {String} configDir - The absolute path
|
* @param {String} configDir - The absolute path
|
||||||
* @param {String} name - The name of the node
|
|
||||||
* @param {String} datadir - The bitcoin database directory
|
* @param {String} datadir - The bitcoin database directory
|
||||||
* @param {Boolean} isGlobal - If the configuration depends on globally installed node services.
|
* @param {Boolean} isGlobal - If the configuration depends on globally installed node services.
|
||||||
* @param {Function} done - The callback function called when finished
|
* @param {Function} done - The callback function called when finished
|
||||||
*/
|
*/
|
||||||
function createConfigDirectory(configDir, name, datadir, isGlobal, done) {
|
function createConfigDirectory(configDir, datadir, isGlobal, done) {
|
||||||
mkdirp(configDir, function(err) {
|
mkdirp(configDir, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = BASE_CONFIG;
|
var configInfo = defaultConfig();
|
||||||
config.name = name || 'Bitcore Node';
|
var config = configInfo.config;
|
||||||
|
|
||||||
config.datadir = datadir;
|
config.datadir = datadir;
|
||||||
var configJSON = JSON.stringify(config, null, 2);
|
var configJSON = JSON.stringify(config, null, 2);
|
||||||
var packageJSON = JSON.stringify(BASE_PACKAGE, null, 2);
|
var packageJSON = JSON.stringify(BASE_PACKAGE, null, 2);
|
||||||
@ -95,7 +86,6 @@ function createConfigDirectory(configDir, name, datadir, isGlobal, done) {
|
|||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
* @param {String} options.cwd - The current working directory
|
* @param {String} options.cwd - The current working directory
|
||||||
* @param {String} options.dirname - The name of the bitcore node configuration directory
|
* @param {String} options.dirname - The name of the bitcore node configuration directory
|
||||||
* @param {String} options.name - The name of the bitcore node
|
|
||||||
* @param {String} options.datadir - The path to the bitcoin datadir
|
* @param {String} options.datadir - The path to the bitcoin datadir
|
||||||
* @param {Function} done - A callback function called when finished
|
* @param {Function} done - A callback function called when finished
|
||||||
*/
|
*/
|
||||||
@ -106,13 +96,11 @@ function create(options, done) {
|
|||||||
$.checkArgument(_.isFunction(done));
|
$.checkArgument(_.isFunction(done));
|
||||||
$.checkArgument(_.isString(options.cwd));
|
$.checkArgument(_.isString(options.cwd));
|
||||||
$.checkArgument(_.isString(options.dirname));
|
$.checkArgument(_.isString(options.dirname));
|
||||||
$.checkArgument(_.isString(options.name) || _.isUndefined(options.name));
|
|
||||||
$.checkArgument(_.isBoolean(options.isGlobal));
|
$.checkArgument(_.isBoolean(options.isGlobal));
|
||||||
$.checkArgument(_.isString(options.datadir));
|
$.checkArgument(_.isString(options.datadir));
|
||||||
|
|
||||||
var cwd = options.cwd;
|
var cwd = options.cwd;
|
||||||
var dirname = options.dirname;
|
var dirname = options.dirname;
|
||||||
var name = options.name;
|
|
||||||
var datadir = options.datadir;
|
var datadir = options.datadir;
|
||||||
var isGlobal = options.isGlobal;
|
var isGlobal = options.isGlobal;
|
||||||
|
|
||||||
@ -123,7 +111,7 @@ function create(options, done) {
|
|||||||
function(next) {
|
function(next) {
|
||||||
// Setup the the bitcore-node directory and configuration
|
// Setup the the bitcore-node directory and configuration
|
||||||
if (!fs.existsSync(absConfigDir)) {
|
if (!fs.existsSync(absConfigDir)) {
|
||||||
createConfigDirectory(absConfigDir, name, datadir, isGlobal, next);
|
createConfigDirectory(absConfigDir, datadir, isGlobal, next);
|
||||||
} else {
|
} else {
|
||||||
next(new Error('Directory "' + absConfigDir+ '" already exists.'));
|
next(new Error('Directory "' + absConfigDir+ '" already exists.'));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ var Service = function(options) {
|
|||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
this.node = options.node;
|
this.node = options.node;
|
||||||
|
this.name = options.name;
|
||||||
};
|
};
|
||||||
|
|
||||||
util.inherits(Service, EventEmitter);
|
util.inherits(Service, EventEmitter);
|
||||||
@ -81,4 +82,10 @@ Service.prototype.setupRoutes = function(app) {
|
|||||||
// Setup express routes here
|
// Setup express routes here
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Service.prototype.getRoutePrefix = function() {
|
||||||
|
return this.name;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = Service;
|
module.exports = Service;
|
||||||
|
|||||||
@ -247,13 +247,13 @@ DB.prototype.estimateFee = function(blocks, callback) {
|
|||||||
DB.prototype.getPublishEvents = function() {
|
DB.prototype.getPublishEvents = function() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'transaction',
|
name: 'db/transaction',
|
||||||
scope: this,
|
scope: this,
|
||||||
subscribe: this.subscribe.bind(this, 'transaction'),
|
subscribe: this.subscribe.bind(this, 'transaction'),
|
||||||
unsubscribe: this.unsubscribe.bind(this, 'transaction')
|
unsubscribe: this.unsubscribe.bind(this, 'transaction')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'block',
|
name: 'db/block',
|
||||||
scope: this,
|
scope: this,
|
||||||
subscribe: this.subscribe.bind(this, 'block'),
|
subscribe: this.subscribe.bind(this, 'block'),
|
||||||
unsubscribe: this.unsubscribe.bind(this, 'block')
|
unsubscribe: this.unsubscribe.bind(this, 'block')
|
||||||
@ -435,12 +435,15 @@ DB.prototype.getHashes = function getHashes(tipHash, callback) {
|
|||||||
if (hash === self.genesis.hash) {
|
if (hash === self.genesis.hash) {
|
||||||
// Stop at the genesis block
|
// Stop at the genesis block
|
||||||
self.cache.chainHashes[tipHash] = hashes;
|
self.cache.chainHashes[tipHash] = hashes;
|
||||||
|
|
||||||
callback(null, hashes);
|
callback(null, hashes);
|
||||||
} else if(self.cache.chainHashes[hash]) {
|
} else if(self.cache.chainHashes[hash]) {
|
||||||
hashes.shift();
|
hashes.shift();
|
||||||
hashes = self.cache.chainHashes[hash].concat(hashes);
|
hashes = self.cache.chainHashes[hash].concat(hashes);
|
||||||
delete self.cache.chainHashes[hash];
|
|
||||||
self.cache.chainHashes[tipHash] = hashes;
|
self.cache.chainHashes[tipHash] = hashes;
|
||||||
|
if(hash !== tipHash) {
|
||||||
|
delete self.cache.chainHashes[hash];
|
||||||
|
}
|
||||||
callback(null, hashes);
|
callback(null, hashes);
|
||||||
} else {
|
} else {
|
||||||
// Continue with the previous hash
|
// Continue with the previous hash
|
||||||
@ -643,8 +646,15 @@ DB.prototype.sync = function() {
|
|||||||
// This block doesn't progress the current tip, so we'll attempt
|
// This block doesn't progress the current tip, so we'll attempt
|
||||||
// to rewind the chain to the common ancestor of the block and
|
// to rewind the chain to the common ancestor of the block and
|
||||||
// then we can resume syncing.
|
// then we can resume syncing.
|
||||||
self.syncRewind(block, done);
|
log.warn('Beginning reorg! Current tip: ' + self.tip.hash + '; New tip: ' + block.hash);
|
||||||
|
self.syncRewind(block, function(err) {
|
||||||
|
if(err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn('Reorg complete. New tip is ' + self.tip.hash);
|
||||||
|
done();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
|
|||||||
@ -6,6 +6,8 @@ var bodyParser = require('body-parser');
|
|||||||
var socketio = require('socket.io');
|
var socketio = require('socket.io');
|
||||||
var BaseService = require('../service');
|
var BaseService = require('../service');
|
||||||
var inherits = require('util').inherits;
|
var inherits = require('util').inherits;
|
||||||
|
var index = require('../');
|
||||||
|
var log = index.log;
|
||||||
|
|
||||||
var WebService = function(options) {
|
var WebService = function(options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -13,6 +15,7 @@ var WebService = function(options) {
|
|||||||
this.port = options.port || this.node.port || 3456;
|
this.port = options.port || this.node.port || 3456;
|
||||||
|
|
||||||
this.node.on('ready', function() {
|
this.node.on('ready', function() {
|
||||||
|
self.eventNames = self.getEventNames();
|
||||||
self.setupAllRoutes();
|
self.setupAllRoutes();
|
||||||
self.server.listen(self.port);
|
self.server.listen(self.port);
|
||||||
self.createMethodsMap();
|
self.createMethodsMap();
|
||||||
@ -50,7 +53,15 @@ WebService.prototype.stop = function(callback) {
|
|||||||
|
|
||||||
WebService.prototype.setupAllRoutes = function() {
|
WebService.prototype.setupAllRoutes = function() {
|
||||||
for(var key in this.node.services) {
|
for(var key in this.node.services) {
|
||||||
this.node.services[key].setupRoutes(this.app);
|
var subApp = new express.Router();
|
||||||
|
var service = this.node.services[key];
|
||||||
|
|
||||||
|
if(service.getRoutePrefix && service.setupRoutes) {
|
||||||
|
this.app.use('/' + this.node.services[key].getRoutePrefix(), subApp);
|
||||||
|
this.node.services[key].setupRoutes(subApp, express);
|
||||||
|
} else {
|
||||||
|
log.info('Not setting up routes for ' + service.name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,7 +82,32 @@ WebService.prototype.createMethodsMap = function() {
|
|||||||
args: args
|
args: args
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
|
WebService.prototype.getEventNames = function() {
|
||||||
|
var events = this.node.getAllPublishEvents();
|
||||||
|
var eventNames = [];
|
||||||
|
|
||||||
|
function addEventName(name) {
|
||||||
|
if(eventNames.indexOf(name) > -1) {
|
||||||
|
throw new Error('Duplicate event ' + name);
|
||||||
|
}
|
||||||
|
|
||||||
|
eventNames.push(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
events.forEach(function(event) {
|
||||||
|
addEventName(event.name);
|
||||||
|
|
||||||
|
if(event.extraEvents) {
|
||||||
|
event.extraEvents.forEach(function(name) {
|
||||||
|
addEventName(name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return eventNames;
|
||||||
|
};
|
||||||
|
|
||||||
WebService.prototype.socketHandler = function(socket) {
|
WebService.prototype.socketHandler = function(socket) {
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -88,10 +124,8 @@ WebService.prototype.socketHandler = function(socket) {
|
|||||||
bus.unsubscribe(name, params);
|
bus.unsubscribe(name, params);
|
||||||
});
|
});
|
||||||
|
|
||||||
var events = self.node.getAllPublishEvents();
|
this.eventNames.forEach(function(eventName) {
|
||||||
|
bus.on(eventName, function() {
|
||||||
events.forEach(function(event) {
|
|
||||||
bus.on(event.name, function() {
|
|
||||||
if(socket.connected) {
|
if(socket.connected) {
|
||||||
var results = [];
|
var results = [];
|
||||||
|
|
||||||
@ -99,7 +133,7 @@ WebService.prototype.socketHandler = function(socket) {
|
|||||||
results.push(arguments[i]);
|
results.push(arguments[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var params = [event.name].concat(results);
|
var params = [eventName].concat(results);
|
||||||
socket.emit.apply(socket, params);
|
socket.emit.apply(socket, params);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -74,8 +74,7 @@ describe('#create', function() {
|
|||||||
should.equal(fs.existsSync(bitcoinConfig), true);
|
should.equal(fs.existsSync(bitcoinConfig), true);
|
||||||
|
|
||||||
var config = JSON.parse(fs.readFileSync(configPath));
|
var config = JSON.parse(fs.readFileSync(configPath));
|
||||||
config.name.should.equal('My Node 1');
|
config.services.should.deep.equal(['bitcoind', 'db', 'address', 'web']);
|
||||||
config.services.should.deep.equal(['address']);
|
|
||||||
config.datadir.should.equal('./data');
|
config.datadir.should.equal('./data');
|
||||||
config.network.should.equal('livenet');
|
config.network.should.equal('livenet');
|
||||||
|
|
||||||
|
|||||||
@ -39,15 +39,20 @@ describe('WebService', function() {
|
|||||||
on: sinon.spy(),
|
on: sinon.spy(),
|
||||||
services: {
|
services: {
|
||||||
one: {
|
one: {
|
||||||
setupRoutes: sinon.spy()
|
setupRoutes: sinon.spy(),
|
||||||
|
getRoutePrefix: sinon.stub().returns('one')
|
||||||
},
|
},
|
||||||
two: {
|
two: {
|
||||||
setupRoutes: sinon.spy()
|
setupRoutes: sinon.spy(),
|
||||||
|
getRoutePrefix: sinon.stub().returns('two')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var web = new WebService({node: node});
|
var web = new WebService({node: node});
|
||||||
|
web.app = {
|
||||||
|
use: sinon.spy()
|
||||||
|
};
|
||||||
|
|
||||||
web.setupAllRoutes();
|
web.setupAllRoutes();
|
||||||
node.services.one.setupRoutes.callCount.should.equal(1);
|
node.services.one.setupRoutes.callCount.should.equal(1);
|
||||||
@ -97,6 +102,54 @@ describe('WebService', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#getEventNames', function() {
|
||||||
|
it('should get event names', function() {
|
||||||
|
var Module1 = function() {};
|
||||||
|
Module1.prototype.getPublishEvents = function() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'event1',
|
||||||
|
extraEvents: ['event2']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var module1 = new Module1();
|
||||||
|
var node = {
|
||||||
|
on: sinon.spy(),
|
||||||
|
getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents())
|
||||||
|
};
|
||||||
|
|
||||||
|
var web = new WebService({node: node});
|
||||||
|
var events = web.getEventNames();
|
||||||
|
|
||||||
|
events.should.deep.equal(['event1', 'event2']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw an error if there is a duplicate event', function() {
|
||||||
|
var Module1 = function() {};
|
||||||
|
Module1.prototype.getPublishEvents = function() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'event1',
|
||||||
|
extraEvents: ['event1']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var module1 = new Module1();
|
||||||
|
var node = {
|
||||||
|
on: sinon.spy(),
|
||||||
|
getAllPublishEvents: sinon.stub().returns(module1.getPublishEvents())
|
||||||
|
};
|
||||||
|
|
||||||
|
var web = new WebService({node: node});
|
||||||
|
(function() {
|
||||||
|
var events = web.getEventNames();
|
||||||
|
}).should.throw('Duplicate event event1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('#socketHandler', function() {
|
describe('#socketHandler', function() {
|
||||||
var bus = new EventEmitter();
|
var bus = new EventEmitter();
|
||||||
|
|
||||||
@ -104,7 +157,8 @@ describe('WebService', function() {
|
|||||||
Module1.prototype.getPublishEvents = function() {
|
Module1.prototype.getPublishEvents = function() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
name: 'event1'
|
name: 'event1',
|
||||||
|
extraEvents: ['event2']
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@ -121,6 +175,7 @@ describe('WebService', function() {
|
|||||||
|
|
||||||
it('on message should call socketMessageHandler', function(done) {
|
it('on message should call socketMessageHandler', function(done) {
|
||||||
web = new WebService({node: node});
|
web = new WebService({node: node});
|
||||||
|
web.eventNames = web.getEventNames();
|
||||||
web.socketMessageHandler = function(param1) {
|
web.socketMessageHandler = function(param1) {
|
||||||
param1.should.equal('data');
|
param1.should.equal('data');
|
||||||
done();
|
done();
|
||||||
@ -149,13 +204,13 @@ describe('WebService', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('publish events from bus should be emitted from socket', function(done) {
|
it('publish events from bus should be emitted from socket', function(done) {
|
||||||
socket.once('event1', function(param1, param2) {
|
socket.once('event2', function(param1, param2) {
|
||||||
param1.should.equal('param1');
|
param1.should.equal('param1');
|
||||||
param2.should.equal('param2');
|
param2.should.equal('param2');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
socket.connected = true;
|
socket.connected = true;
|
||||||
bus.emit('event1', 'param1', 'param2');
|
bus.emit('event2', 'param1', 'param2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('on disconnect should close bus', function(done) {
|
it('on disconnect should close bus', function(done) {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user