Merge pull request #412 from braydonf/feature/cache
Added configurable caching.
This commit is contained in:
commit
abe5075dd3
@ -3,7 +3,6 @@
|
|||||||
var common = require('./common');
|
var common = require('./common');
|
||||||
var async = require('async');
|
var async = require('async');
|
||||||
var bitcore = require('bitcore-lib');
|
var bitcore = require('bitcore-lib');
|
||||||
var BufferUtil = bitcore.util.buffer;
|
|
||||||
var pools = require('../pools.json');
|
var pools = require('../pools.json');
|
||||||
var BN = bitcore.crypto.BN;
|
var BN = bitcore.crypto.BN;
|
||||||
|
|
||||||
|
|||||||
78
lib/index.js
78
lib/index.js
@ -15,6 +15,15 @@ var $ = bitcore.util.preconditions;
|
|||||||
var Transaction = bitcore.Transaction;
|
var Transaction = bitcore.Transaction;
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A service for Bitcore to enable HTTP routes to query information about the blockchain.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @param {Boolean} options.enableCache - This will enable cache-control headers
|
||||||
|
* @param {Number} options.cacheShortSeconds - The time to cache short lived cache responses.
|
||||||
|
* @param {Number} options.cacheLongSeconds - The time to cache long lived cache responses.
|
||||||
|
* @param {String} options.routePrefix - The URL route prefix
|
||||||
|
*/
|
||||||
var InsightAPI = function(options) {
|
var InsightAPI = function(options) {
|
||||||
BaseService.call(this, options);
|
BaseService.call(this, options);
|
||||||
|
|
||||||
@ -25,6 +34,13 @@ var InsightAPI = function(options) {
|
|||||||
inv: []
|
inv: []
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!_.isUndefined(options.enableCache)) {
|
||||||
|
$.checkArgument(_.isBoolean(options.enableCache));
|
||||||
|
this.enableCache = options.enableCache;
|
||||||
|
}
|
||||||
|
this.cacheShortSeconds = options.cacheShortSeconds;
|
||||||
|
this.cacheLongSeconds = options.cacheLongSeconds;
|
||||||
|
|
||||||
if (!_.isUndefined(options.routePrefix)) {
|
if (!_.isUndefined(options.routePrefix)) {
|
||||||
this.routePrefix = options.routePrefix;
|
this.routePrefix = options.routePrefix;
|
||||||
} else {
|
} else {
|
||||||
@ -38,6 +54,26 @@ InsightAPI.dependencies = ['address', 'web'];
|
|||||||
|
|
||||||
inherits(InsightAPI, BaseService);
|
inherits(InsightAPI, BaseService);
|
||||||
|
|
||||||
|
InsightAPI.prototype.cache = function(maxAge) {
|
||||||
|
var self = this;
|
||||||
|
return function(req, res, next) {
|
||||||
|
if (self.enableCache) {
|
||||||
|
res.header('Cache-Control', 'public, max-age=' + maxAge);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
InsightAPI.prototype.cacheShort = function() {
|
||||||
|
var seconds = this.cacheShortSeconds || 30; // thirty seconds
|
||||||
|
return this.cache(seconds);
|
||||||
|
};
|
||||||
|
|
||||||
|
InsightAPI.prototype.cacheLong = function() {
|
||||||
|
var seconds = this.cacheLongSeconds || 86400; // one day
|
||||||
|
return this.cache(seconds);
|
||||||
|
};
|
||||||
|
|
||||||
InsightAPI.prototype.getRoutePrefix = function() {
|
InsightAPI.prototype.getRoutePrefix = function() {
|
||||||
return this.routePrefix;
|
return this.routePrefix;
|
||||||
};
|
};
|
||||||
@ -49,6 +85,7 @@ InsightAPI.prototype.start = function(callback) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
InsightAPI.prototype.setupRoutes = function(app) {
|
InsightAPI.prototype.setupRoutes = function(app) {
|
||||||
|
|
||||||
//Enable CORS
|
//Enable CORS
|
||||||
app.use(function(req, res, next) {
|
app.use(function(req, res, next) {
|
||||||
res.header('Access-Control-Allow-Origin', '*');
|
res.header('Access-Control-Allow-Origin', '*');
|
||||||
@ -58,48 +95,47 @@ InsightAPI.prototype.setupRoutes = function(app) {
|
|||||||
|
|
||||||
//Block routes
|
//Block routes
|
||||||
var blocks = new BlockController(this.node);
|
var blocks = new BlockController(this.node);
|
||||||
app.get('/blocks', blocks.list.bind(blocks));
|
app.get('/blocks', this.cacheShort(), blocks.list.bind(blocks));
|
||||||
|
|
||||||
|
|
||||||
app.get('/block/:blockHash', blocks.show.bind(blocks));
|
app.get('/block/:blockHash', this.cacheLong(), blocks.show.bind(blocks));
|
||||||
app.param('blockHash', blocks.block.bind(blocks));
|
app.param('blockHash', blocks.block.bind(blocks));
|
||||||
|
|
||||||
app.get('/block-index/:height', blocks.blockIndex.bind(blocks));
|
app.get('/block-index/:height', this.cacheLong(), blocks.blockIndex.bind(blocks));
|
||||||
app.param('height', blocks.blockIndex.bind(blocks));
|
app.param('height', blocks.blockIndex.bind(blocks));
|
||||||
|
|
||||||
|
|
||||||
// Transaction routes
|
// Transaction routes
|
||||||
var transactions = new TxController(this.node);
|
var transactions = new TxController(this.node);
|
||||||
app.get('/tx/:txid', transactions.show.bind(transactions));
|
app.get('/tx/:txid', this.cacheLong(), transactions.show.bind(transactions));
|
||||||
app.param('txid', transactions.transaction.bind(transactions));
|
app.param('txid', transactions.transaction.bind(transactions));
|
||||||
app.get('/txs', transactions.list.bind(transactions));
|
app.get('/txs', this.cacheShort(), transactions.list.bind(transactions));
|
||||||
app.post('/tx/send', transactions.send.bind(transactions));
|
app.post('/tx/send', transactions.send.bind(transactions));
|
||||||
|
|
||||||
// Raw Routes
|
// Raw Routes
|
||||||
app.get('/rawtx/:txid', transactions.showRaw.bind(transactions));
|
app.get('/rawtx/:txid', this.cacheLong(), transactions.showRaw.bind(transactions));
|
||||||
app.param('txid', transactions.rawTransaction.bind(transactions));
|
app.param('txid', transactions.rawTransaction.bind(transactions));
|
||||||
|
|
||||||
// Address routes
|
// Address routes
|
||||||
var addresses = new AddressController(this.node);
|
var addresses = new AddressController(this.node);
|
||||||
app.get('/addr/:addr', addresses.checkAddr.bind(addresses), addresses.show.bind(addresses));
|
app.get('/addr/:addr', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.show.bind(addresses));
|
||||||
app.get('/addr/:addr/utxo', addresses.checkAddr.bind(addresses), addresses.utxo.bind(addresses));
|
app.get('/addr/:addr/utxo', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.utxo.bind(addresses));
|
||||||
app.get('/addrs/:addrs/utxo', addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
app.get('/addrs/:addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
||||||
app.post('/addrs/utxo', addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
app.post('/addrs/utxo', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multiutxo.bind(addresses));
|
||||||
app.get('/addrs/:addrs/txs', addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
app.get('/addrs/:addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
||||||
app.post('/addrs/txs', addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
app.post('/addrs/txs', this.cacheShort(), addresses.checkAddrs.bind(addresses), addresses.multitxs.bind(addresses));
|
||||||
|
|
||||||
// Address property routes
|
// Address property routes
|
||||||
app.get('/addr/:addr/balance', addresses.checkAddr.bind(addresses), addresses.balance.bind(addresses));
|
app.get('/addr/:addr/balance', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.balance.bind(addresses));
|
||||||
app.get('/addr/:addr/totalReceived', addresses.checkAddr.bind(addresses), addresses.totalReceived.bind(addresses));
|
app.get('/addr/:addr/totalReceived', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.totalReceived.bind(addresses));
|
||||||
app.get('/addr/:addr/totalSent', addresses.checkAddr.bind(addresses), addresses.totalSent.bind(addresses));
|
app.get('/addr/:addr/totalSent', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.totalSent.bind(addresses));
|
||||||
app.get('/addr/:addr/unconfirmedBalance', addresses.checkAddr.bind(addresses), addresses.unconfirmedBalance.bind(addresses));
|
app.get('/addr/:addr/unconfirmedBalance', this.cacheShort(), addresses.checkAddr.bind(addresses), addresses.unconfirmedBalance.bind(addresses));
|
||||||
|
|
||||||
// Status route
|
// Status route
|
||||||
var status = new StatusController(this.node);
|
var status = new StatusController(this.node);
|
||||||
app.get('/status', status.show.bind(status));
|
app.get('/status', this.cacheShort(), status.show.bind(status));
|
||||||
app.get('/sync', status.sync.bind(status));
|
app.get('/sync', this.cacheShort(), status.sync.bind(status));
|
||||||
app.get('/peer', status.peer.bind(status));
|
app.get('/peer', this.cacheShort(), status.peer.bind(status));
|
||||||
app.get('/version', status.version.bind(status));
|
app.get('/version', this.cacheShort(), status.version.bind(status));
|
||||||
|
|
||||||
// Address routes
|
// Address routes
|
||||||
var messages = new MessagesController(this.node);
|
var messages = new MessagesController(this.node);
|
||||||
|
|||||||
110
test/index.js
Normal file
110
test/index.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var should = require('should');
|
||||||
|
var sinon = require('sinon');
|
||||||
|
var InsightAPI = require('../lib/index');
|
||||||
|
|
||||||
|
describe('Index', function() {
|
||||||
|
describe('#cache', function() {
|
||||||
|
it('will set cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: true
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cache(10);
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(1);
|
||||||
|
res.header.args[0][0].should.equal('Cache-Control');
|
||||||
|
res.header.args[0][1].should.equal('public, max-age=10');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('will NOT set cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: false
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cache(10);
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(0);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#cacheShort', function() {
|
||||||
|
it('will set SHORT cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: true,
|
||||||
|
cacheShortSeconds: 35
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cacheShort();
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(1);
|
||||||
|
res.header.args[0][0].should.equal('Cache-Control');
|
||||||
|
res.header.args[0][1].should.equal('public, max-age=35');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('will set SHORT DEFAULT cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: true
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cacheShort();
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(1);
|
||||||
|
res.header.args[0][0].should.equal('Cache-Control');
|
||||||
|
res.header.args[0][1].should.equal('public, max-age=30');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#cacheLong', function() {
|
||||||
|
it('will set LONG cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: true,
|
||||||
|
cacheLongSeconds: 86400000
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cacheLong();
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(1);
|
||||||
|
res.header.args[0][0].should.equal('Cache-Control');
|
||||||
|
res.header.args[0][1].should.equal('public, max-age=86400000');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('will set LONG DEFAULT cache control header', function(done) {
|
||||||
|
var index = new InsightAPI({
|
||||||
|
enableCache: true
|
||||||
|
});
|
||||||
|
var req = {};
|
||||||
|
var res = {
|
||||||
|
header: sinon.stub()
|
||||||
|
};
|
||||||
|
var middle = index.cacheLong();
|
||||||
|
middle(req, res, function() {
|
||||||
|
res.header.callCount.should.equal(1);
|
||||||
|
res.header.args[0][0].should.equal('Cache-Control');
|
||||||
|
res.header.args[0][1].should.equal('public, max-age=86400');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user