Browse Source

Merge pull request #222 from isocolsky/stats

Refactor stats
activeAddress
Matias Alejo Garcia 10 years ago
parent
commit
62bdb543e7
  1. 14
      lib/expressapp.js
  2. 243
      lib/stats.js
  3. 1
      lib/storage.js
  4. 2
      package.json

14
lib/expressapp.js

@ -9,7 +9,7 @@ var querystring = require('querystring');
var bodyParser = require('body-parser') var bodyParser = require('body-parser')
var WalletService = require('./server'); var WalletService = require('./server');
var stats = require('./stats'); var Stats = require('./stats');
log.disableColor(); log.disableColor();
log.debug = log.verbose; log.debug = log.verbose;
@ -340,18 +340,20 @@ ExpressApp.prototype.start = function(opts, cb) {
}); });
}); });
router.get('/v1/stats/:from/:to/', function(req, res) { router.get('/v1/stats/', function(req, res) {
var opts = {}; var opts = {};
opts.from = req.params['from']; if (req.query.network) opts.network = req.query.network;
opts.to = req.params['to']; if (req.query.from) opts.from = req.query.from;
stats.getStats(opts, function(err, data) { if (req.query.to) opts.to = req.query.to;
var stats = new Stats(opts);
stats.run(function(err, data) {
if (err) return returnError(err, res, req); if (err) return returnError(err, res, req);
res.json(data); res.json(data);
res.end(); res.end();
}); });
}); });
this.app.use(opts.basePath || '/bws/api', router); this.app.use(opts.basePath || '/bws/api', router);
WalletService.initialize(opts, cb); WalletService.initialize(opts, cb);

243
lib/stats.js

@ -3,155 +3,150 @@
'use strict'; 'use strict';
var _ = require('lodash'); var _ = require('lodash');
var $ = require('preconditions').singleton();
var async = require('async');
var log = require('npmlog');
log.debug = log.verbose;
log.disableColor();
var mongodb = require('mongodb'); var mongodb = require('mongodb');
var moment = require('moment'); var moment = require('moment');
var async = require('async');
var config = require('../config');
var config = require('../config');
var storage = require('./storage');
var c = config.storageOpts.mongoDb; function Stats(opts) {
var url = c.uri; opts = opts || {};
var startDate = moment();
var endDate = moment();
var stats = {};
var wallets = {};
var bwsStats = {};
bwsStats.cleanUp = function() { this.network = opts.network || 'livenet';
stats = { this.from = moment(opts.from || '2015-01-01');
'livenet': {}, this.to = moment(opts.to);
'testnet': {} this.fromTs = Math.floor(this.from.startOf('day').valueOf() / 1000);
}; this.toTs = Math.floor(this.to.endOf('day').valueOf() / 1000);
}; };
Stats.prototype.run = function(cb) {
var self = this;
bwsStats.AddingWalletToCache = function(data) { var uri = config.storageOpts.mongoDb.uri;
if (!data) return; mongodb.MongoClient.connect(uri, function(err, db) {
wallets[data.id] = data.network; if (err) {
}; log.error('Unable to connect to the mongoDB', err);
return cb(err, null);
bwsStats.TotalNewWallets = function(data) { }
if (!data) return; log.info('Connection established to ' + uri);
var day = moment(data.createdOn * 1000).format('YYYYMMDD'); self.db = db;
if (!stats[data.network][day]) { self._getStats(function(err, stats) {
stats[data.network][day] = { if (err) return cb(err);
totalTx: 0, return cb(null, stats);
totalAmount: 0, });
totalNewWallets: 0 });
};
}
stats[data.network][day].totalNewWallets++;
}; };
bwsStats.TotalTxps = function(data) { Stats.prototype._getStats = function(cb) {
if (!data) return; var self = this;
var day = moment(data.createdOn * 1000).format('YYYYMMDD'); var result = {};
var network = wallets[data.walletId]; async.parallel([
if (!stats[network][day]) {
stats[network][day] = { function(next) {
totalTx: 0, self._getNewWallets(next);
totalAmount: 0, },
totalNewWallets: 0 function(next) {
}; self._getTxProposals(next);
} },
stats[network][day].totalTx++; ], function(err, results) {
stats[network][day].totalAmount += data.amount; if (err) return cb(err);
result.newWallets = results[0];
result.txProposals = results[1];
return cb(null, result);
});
}; };
bwsStats.ProcessData = function(DB, cb) { Stats.prototype._countBy = function(data, key) {
bwsStats.ProccesWallets(DB, function() { return _.map(_.groupBy(data, key), function(v, k) {
bwsStats.ProccesNewWallets(DB, function() { var item = {};
bwsStats.ProccesTxs(DB, function() { item[key] = k;
DB.close(); item['count'] = v.length;
cb(); return item;
});
});
}); });
}; };
bwsStats.ProccesWallets = function(DB, cb) { Stats.prototype._sumBy = function(data, key, attr) {
var collection = DB.collection('wallets'); return _.map(_.groupBy(data, key), function(v, k) {
collection.find({}).toArray(function(err, items) { var item = {};
if (err) { item[key] = k;
console.log('Error.', err); item[attr] = _.reduce(v, function(memo, x) {
return cb(err); return memo + x[attr];
} }, 0);
return item;
items.forEach(function(it) {
bwsStats.AddingWalletToCache(it);
});
cb();
}); });
}; };
bwsStats.ProccesNewWallets = function(DB, cb) { Stats.prototype._getNewWallets = function(cb) {
var collection = DB.collection('wallets'); var self = this;
var start = Math.floor(startDate.startOf('day').valueOf() / 1000);
var end = Math.floor(endDate.endOf('day').valueOf() / 1000); self.db.collection(storage.collections.WALLETS)
.find({
network: self.network,
createdOn: {
$gte: self.fromTs,
$lte: self.toTs,
},
})
.toArray(function(err, wallets) {
if (err) return cb(err);
var data = _.map(wallets, function(wallet) {
return {
day: moment(wallet.createdOn * 1000).format('YYYYMMDD'),
type: (wallet.m == 1 && wallet.n == 1) ? 'personal' : 'shared',
config: wallet.m + '-of-' + wallet.n,
};
});
collection.find({ var stats = {
createdOn: { byDay: self._countBy(data, 'day'),
$gt: start, byConfig: self._countBy(data, 'config'),
$lt: end };
}
}).toArray(function(err, items) {
if (err) {
console.log('Error.', err);
return cb(err);
}
items.forEach(function(it) {
bwsStats.TotalNewWallets(it);
});
cb();
});
};
bwsStats.ProccesTxs = function(DB, cb) { stats.byTypeThenDay = _.groupBy(data, 'type');
var collection = DB.collection('txs'); _.each(stats.byTypeThenDay, function(v, k) {
var start = Math.floor(startDate.startOf('day').valueOf() / 1000); stats.byTypeThenDay[k] = self._countBy(v, 'day');
var end = Math.floor(endDate.endOf('day').valueOf() / 1000); });
collection.find({ return cb(null, stats);
createdOn: {
$gt: start,
$lt: end
}
}).toArray(
function(err, items) {
if (err) {
console.log('Error.', err);
return cb(err);
} else {
items.forEach(function(it) {
bwsStats.TotalTxps(it);
});
}
cb();
}); });
}; };
bwsStats.getStats = function(opts, cb) { Stats.prototype._getTxProposals = function(cb) {
if (opts) { var self = this;
startDate = moment(opts.from);
endDate = moment(opts.to); self.db.collection(storage.collections.TXS)
} .find({
bwsStats.cleanUp(); network: self.network,
status: 'broadcasted',
createdOn: {
$gte: self.fromTs,
$lte: self.toTs,
},
})
.toArray(function(err, txps) {
if (err) return cb(err);
var data = _.map(txps, function(txp) {
return {
day: moment(txp.createdOn * 1000).format('YYYYMMDD'),
amount: txp.amount,
};
});
mongodb.MongoClient.connect(url, function(err, db) { var stats = {
if (err) { nbByDay: self._countBy(data, 'day'),
console.log('Unable to connect to the mongoDB server. Error:', err); amountByDay: self._sumBy(data, 'day', 'amount'),
return cb(err, null); };
}
console.log('Connection established to ', url); return cb(null, stats);
bwsStats.ProcessData(db, function(err) {
if (err) {
console.log('Error.', err);
return cb(err, null);
}
cb(null, stats);
}); });
});
}; };
module.exports = bwsStats; module.exports = Stats;

1
lib/storage.js

@ -426,4 +426,5 @@ Storage.prototype._dump = function(cb, fn) {
}); });
}; };
Storage.collections = collections;
module.exports = Storage; module.exports = Storage;

2
package.json

@ -2,7 +2,7 @@
"name": "bitcore-wallet-service", "name": "bitcore-wallet-service",
"description": "A service for Mutisig HD Bitcoin Wallets", "description": "A service for Mutisig HD Bitcoin Wallets",
"author": "BitPay Inc", "author": "BitPay Inc",
"version": "0.0.31", "version": "0.0.32",
"keywords": [ "keywords": [
"bitcoin", "bitcoin",
"copay", "copay",

Loading…
Cancel
Save