bitcore-node-zcash/lib/node.js

213 lines
4.8 KiB
JavaScript

'use strict';
var util = require('util');
var EventEmitter = require('events').EventEmitter;
var async = require('async');
var bitcore = require('bitcore');
var Networks = bitcore.Networks;
var $ = bitcore.util.preconditions;
var _ = bitcore.deps._;
var index = require('./');
var log = index.log;
var Bus = require('./bus');
var BaseService = require('./service');
var errors = require('./errors');
function Node(config) {
if(!(this instanceof Node)) {
return new Node(config);
}
var self = this;
this.errors = errors; // So services can use errors without having to have bitcore-node as a dependency
this.log = log;
this.network = null;
this.services = {};
this._unloadedServices = [];
// TODO type check the arguments of config.services
if (config.services) {
$.checkArgument(Array.isArray(config.services));
this._unloadedServices = config.services;
}
$.checkState(config.datadir, 'Node config expects "datadir"');
this.datadir = config.datadir;
this.port = config.port;
this._setNetwork(config);
this.start(function(err) {
if(err) {
return self.emit('error', err);
}
self.emit('ready');
});
}
util.inherits(Node, EventEmitter);
util.inherits(Node, EventEmitter);
Node.prototype._setNetwork = function(config) {
if (config.network === 'testnet') {
this.network = Networks.get('testnet');
} else if (config.network === 'regtest') {
Networks.remove(Networks.testnet);
Networks.add({
name: 'regtest',
alias: 'regtest',
pubkeyhash: 0x6f,
privatekey: 0xef,
scripthash: 0xc4,
xpubkey: 0x043587cf,
xprivkey: 0x04358394,
networkMagic: 0xfabfb5da,
port: 18444,
dnsSeeds: [ ]
});
this.network = Networks.get('regtest');
} else {
this.network = Networks.defaultNetwork;
}
$.checkState(this.network, 'Unrecognized network');
};
Node.prototype.openBus = function() {
return new Bus({node: this});
};
Node.prototype.getAllAPIMethods = function() {
var methods = [];
for(var i in this.services) {
var mod = this.services[i];
methods = methods.concat(mod.getAPIMethods());
}
return methods;
};
Node.prototype.getAllPublishEvents = function() {
var events = [];
for (var i in this.services) {
var mod = this.services[i];
events = events.concat(mod.getPublishEvents());
}
return events;
};
Node.prototype.getServiceOrder = function() {
var services = this._unloadedServices;
// organize data for sorting
var names = [];
var servicesByName = {};
for (var i = 0; i < services.length; i++) {
var service = services[i];
names.push(service.name);
servicesByName[service.name] = service;
}
var stackNames = {};
var stack = [];
function addToStack(names) {
for(var i = 0; i < names.length; i++) {
var name = names[i];
var service = servicesByName[name];
$.checkState(service, 'Required dependency "' + name + '" not available.');
// first add the dependencies
addToStack(service.module.dependencies);
// add to the stack if it hasn't been added
if(!stackNames[name]) {
stack.push(service);
stackNames[name] = true;
}
}
}
addToStack(names);
return stack;
};
Node.prototype._instantiateService = function(service) {
var self = this;
$.checkState(_.isObject(service.config));
$.checkState(!service.config.node);
var config = service.config;
config.node = this;
var mod = new service.module(config);
$.checkState(
mod instanceof BaseService,
'Unexpected module instance type for service:' + service.name
);
// include in loaded services
this.services[service.name] = mod;
// add API methods
var methodData = mod.getAPIMethods();
methodData.forEach(function(data) {
var name = data[0];
var instance = data[1];
var method = data[2];
if (self[name]) {
throw new Error('Existing API method exists: ' + name);
} else {
self[name] = function() {
return method.apply(instance, arguments);
};
}
});
};
Node.prototype.start = function(callback) {
var self = this;
var servicesOrder = this.getServiceOrder();
async.eachSeries(
servicesOrder,
function(service, next) {
log.info('Starting ' + service.name);
try {
self._instantiateService(service);
} catch(err) {
return callback(err);
}
self.services[service.name].start(next);
},
callback
);
};
Node.prototype.stop = function(callback) {
log.info('Beginning shutdown');
var self = this;
var services = this.getServiceOrder().reverse();
this.stopping = true;
this.emit('stopping');
async.eachSeries(
services,
function(service, next) {
log.info('Stopping ' + service.name);
self.services[service.name].stop(next);
},
callback
);
};
module.exports = Node;