188 lines
4.1 KiB
JavaScript
188 lines
4.1 KiB
JavaScript
'use strict';
|
|
|
|
var util = require('util');
|
|
var EventEmitter = require('events').EventEmitter;
|
|
var LRU = require('lru-cache');
|
|
var assert = require('assert');
|
|
var constants = require('./constants');
|
|
|
|
var Service = function(options) {
|
|
EventEmitter.call(this);
|
|
|
|
this.node = options.node;
|
|
this.name = options.name;
|
|
};
|
|
|
|
util.inherits(Service, EventEmitter);
|
|
|
|
/**
|
|
* Describes the dependencies that should be loaded before this service.
|
|
*/
|
|
Service.dependencies = [];
|
|
|
|
/**
|
|
* blockHandler
|
|
* @param {Block} block - the block being added or removed from the chain
|
|
* @param {Boolean} add - whether the block is being added or removed
|
|
* @param {Function} callback - call with the leveldb database operations to perform
|
|
*/
|
|
Service.prototype.blockHandler = function(block, add, callback) {
|
|
// implement in the child class
|
|
setImmediate(function() {
|
|
callback(null, []);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* the bus events available for subscription
|
|
* @return {Array} an array of event info
|
|
*/
|
|
Service.prototype.getPublishEvents = function() {
|
|
// Example:
|
|
// return [
|
|
// ['eventname', this, this.subscribeEvent, this.unsubscribeEvent],
|
|
// ];
|
|
return [];
|
|
};
|
|
|
|
/**
|
|
* the API methods to expose
|
|
* @return {Array} return array of methods
|
|
*/
|
|
Service.prototype.getAPIMethods = function() {
|
|
// Example:
|
|
// return [
|
|
// ['getData', this, this.getData, 1]
|
|
// ];
|
|
|
|
return [];
|
|
};
|
|
|
|
// Example:
|
|
// Service.prototype.getData = function(arg1, callback) {
|
|
//
|
|
// };
|
|
|
|
/**
|
|
* Function which is called when module is first initialized
|
|
*/
|
|
Service.prototype.start = function(done) {
|
|
setImmediate(done);
|
|
};
|
|
|
|
/**
|
|
* Function to be called when bitcore-node is stopped
|
|
*/
|
|
Service.prototype.stop = function(done) {
|
|
setImmediate(done);
|
|
};
|
|
|
|
/**
|
|
* Setup express routes
|
|
* @param {Express} app
|
|
*/
|
|
Service.prototype.setupRoutes = function() {
|
|
// Setup express routes here
|
|
};
|
|
|
|
Service.prototype.getRoutePrefix = function() {
|
|
return this.name;
|
|
};
|
|
|
|
Service.prototype._createConcurrencyCache = function(opts) {
|
|
this._concurrencyCache = LRU(opts || 500);
|
|
};
|
|
|
|
Service.prototype._createCache = function(opts) {
|
|
this._cache = LRU(opts || 500);
|
|
};
|
|
|
|
Service.prototype._retrieveCachedItems = function(key, valueItem, prevKey, fn) {
|
|
var self = this;
|
|
|
|
var prev = self._concurrencyCache.get(prevKey);
|
|
|
|
if (prev && !prev.prevKey) {
|
|
|
|
if (fn) {
|
|
valueItem = fn.call(self, valueItem, prev.valueItem);
|
|
}
|
|
|
|
self._concurrencyCache.del(prevKey);
|
|
self._concurrencyCache.set(key, { valueItem: valueItem });
|
|
return [{ key: key, value: valueItem }];
|
|
}
|
|
|
|
self._concurrencyCache.set(key, { valueItem: valueItem, prevKey: prevKey });
|
|
|
|
var resolvedDeps = [];
|
|
var depKey = key;
|
|
|
|
self._concurrencyCache.rforEach(function(value, key) {
|
|
|
|
if (depKey === value.prevKey) {
|
|
|
|
valueItem = fn.call(self, value.valueItem, depKey.valueItem);
|
|
resolvedDeps.push({ key: key, value: valueItem });
|
|
depKey = key;
|
|
self._concurrencyCache.del(key);
|
|
|
|
}
|
|
});
|
|
|
|
return resolvedDeps;
|
|
};
|
|
|
|
Service.prototype._getGenesisBlock = function() {
|
|
|
|
this.genesis = {};
|
|
this.genesis.height = 0;
|
|
this.genesis.hash = constants.BITCOIN_GENESIS_HASH[this.node.getNetworkName()];
|
|
return this.genesis;
|
|
|
|
};
|
|
|
|
Service.prototype._decodeTipData = function(tipBuf) {
|
|
|
|
assert(tipBuf && Buffer.isBuffer(tipBuf) && tipBuf.length === 36,
|
|
'tip data: ' + tipBuf.toString('hex') + ' if not in the proper format');
|
|
|
|
var hash = tipBuf.slice(0, 32).toString('hex');
|
|
var height = tipBuf.slice(32).toString('hex').readUInt32BE();
|
|
return {
|
|
hash: hash,
|
|
height: height
|
|
};
|
|
};
|
|
|
|
Service.prototype._loadTip = function(callback) {
|
|
|
|
var self = this;
|
|
|
|
self.db.get(new Buffer('00', 'hex') + self.name, function(err, tipBuf) {
|
|
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
|
|
if (!tipBuf) {
|
|
self.tip = self._getGenesisBlock();
|
|
self._lastHeight = 0;
|
|
return callback();
|
|
}
|
|
|
|
self.tip = self._decodeTipData(tipData);
|
|
self._lastHeight = self.tip.height;
|
|
|
|
log.info('Loaded tip for: ' + self.name + ' service, hash: ' +
|
|
self.tip.hash + ' height: ' + self.tip.height);
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
|
|
};
|
|
|
|
module.exports = Service;
|