added getHistory

This commit is contained in:
cubedro 2015-04-28 10:43:56 +03:00
parent df47834021
commit abaef56982
7 changed files with 116 additions and 37 deletions

36
app.js
View File

@ -3,6 +3,7 @@ var app = express();
var path = require('path'); var path = require('path');
var favicon = require('serve-favicon'); var favicon = require('serve-favicon');
var bodyParser = require('body-parser'); var bodyParser = require('body-parser');
var askedForHistory = false;
var Primus = require('primus'), var Primus = require('primus'),
api, api,
@ -62,13 +63,14 @@ api.on('connection', function(spark) {
var info = Nodes.add(data); var info = Nodes.add(data);
spark.emit('ready'); spark.emit('ready');
if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.getNode({id: data.id}).canUpdate())
{
spark.emit('history', Nodes.getHistory().getHistoryRequestInterval());
askedForHistory = true;
}
client.write({action: 'add', data: info}); client.write({action: 'add', data: info});
client.write({action: 'charts', data: Nodes.getCharts()});
var blockPropagationChart = Nodes.blockPropagationChart();
client.write({action: 'blockPropagationChart', data: blockPropagationChart});
var uncleCount = Nodes.getUncleCount();
client.write({action: 'uncleCount', data: uncleCount});
} }
}); });
@ -82,16 +84,22 @@ api.on('connection', function(spark) {
if(stats !== false) if(stats !== false)
{ {
client.write({action: 'update', data: stats}); client.write({action: 'update', data: stats});
client.write({action: 'charts', data: Nodes.getCharts()});
}
var blockPropagationChart = Nodes.blockPropagationChart(); if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.getNode({id: data.id}).canUpdate())
client.write({action: 'blockPropagationChart', data: blockPropagationChart}); {
spark.emit('history', Nodes.getHistory().getHistoryRequestInterval());
var uncleCount = Nodes.getUncleCount(); askedForHistory = true;
client.write({action: 'uncleCount', data: uncleCount});
} }
} }
}); });
spark.on('history', function(data){
client.write({action: 'charts', data: Nodes.addHistory(data.id, data.history)});
askedForHistory = false;
});
spark.on('node-ping', function(data){ spark.on('node-ping', function(data){
spark.emit('node-pong'); spark.emit('node-pong');
}); });
@ -118,11 +126,7 @@ client.on('connection', function(spark) {
spark.on('ready', function(data){ spark.on('ready', function(data){
spark.emit('init', {nodes: Nodes.all()}); spark.emit('init', {nodes: Nodes.all()});
var blockPropagationChart = Nodes.blockPropagationChart(); spark.write({action: 'charts', data: Nodes.getCharts()});
spark.write({action: 'blockPropagationChart', data: blockPropagationChart});
var uncleCount = Nodes.getUncleCount();
spark.write({action: 'uncleCount', data: uncleCount});
}); });
spark.on('client-pong', function(data) { spark.on('client-pong', function(data) {

View File

@ -40,6 +40,20 @@ Collection.prototype.update = function(id, stats)
return node.setStats(stats, propagationHistory); return node.setStats(stats, propagationHistory);
} }
Collection.prototype.addHistory = function(id, blocks)
{
var node = this.getNode({ id: id });
if(!node)
return false;
for (var i = blocks.length - 1; i >= 0; i--) {
this._history.add(blocks[i], id);
};
return this.getCharts();
}
Collection.prototype.updateLatency = function(id, latency) Collection.prototype.updateLatency = function(id, latency)
{ {
var node = this.getNode({ id: id }); var node = this.getNode({ id: id });
@ -112,4 +126,14 @@ Collection.prototype.getUncleCount = function()
return this._history.getUncleCount(); return this._history.getUncleCount();
} }
Collection.prototype.getCharts = function()
{
return this._history.getCharts();
}
Collection.prototype.getHistory = function()
{
return this._history;
}
module.exports = Collection; module.exports = Collection;

View File

@ -33,7 +33,7 @@ var History = function History(data)
History.prototype.add = function(block, id) History.prototype.add = function(block, id)
{ {
if(typeof block !== 'undefined' && typeof block.number !== 'undefined' && typeof block.uncles !== 'undefined' && typeof block.transactions !== 'undefined' && typeof block.difficulty !== 'undefined') if(typeof block !== 'undefined' && typeof block.number !== 'undefined' && typeof block.uncles !== 'undefined' && typeof block.transactions !== 'undefined' && typeof block.difficulty !== 'undefined' && (this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1)))
{ {
var historyBlock = this.search(block.number); var historyBlock = this.search(block.number);
@ -68,7 +68,9 @@ History.prototype.add = function(block, id)
if(prevBlock) if(prevBlock)
{ {
block.time = block.arrived - prevBlock.block.arrived; block.time = block.arrived - prevBlock.block.arrived;
block.time_old = block.timestamp - prevBlock.block.timestamp;
if(block.number < this.bestBlock().height)
block.time = (block.timestamp - prevBlock.block.timestamp)*1000;
} }
else else
{ {
@ -92,10 +94,10 @@ History.prototype.add = function(block, id)
History.prototype._save = function(block) History.prototype._save = function(block)
{ {
this._items.push(block); this._items.unshift(block);
if(this._items.length > MAX_HISTORY){ if(this._items.length > MAX_HISTORY){
this._items.shift(); this._items.pop();
} }
this._items = _.sortByOrder(this._items, 'height', false); this._items = _.sortByOrder(this._items, 'height', false);
@ -279,7 +281,8 @@ History.prototype.getCharts = function()
.map(function(item) .map(function(item)
{ {
var chart = { var chart = {
blocktime: item.block.time, height: item.height,
blocktime: item.block.time/1000,
difficulty: item.block.difficulty, difficulty: item.block.difficulty,
uncles: item.block.uncles.length, uncles: item.block.uncles.length,
transactions: item.block.transactions.length, transactions: item.block.transactions.length,
@ -289,12 +292,39 @@ History.prototype.getCharts = function()
}) })
.value(); .value();
return chartHistory; var chart = {
height: _.pluck(chartHistory, 'height'),
blocktime: _.pluck(chartHistory, 'blocktime'),
difficulty: _.pluck(chartHistory, 'difficulty'),
uncles: _.pluck(chartHistory, 'uncles'),
transactions: _.pluck(chartHistory, 'transactions'),
gasSpending: _.pluck(chartHistory, 'gasSpending'),
propagation: this.getBlockPropagation(),
uncleCount: this.getUncleCount()
}
return chart;
} }
History.prototype.history = function() History.prototype.history = function()
{ {
return _.chain(this._items).sortBy('height').reverse().value(); return this._items;
}
History.prototype.requiresUpdate = function()
{
return ! (this._items.length === MAX_HISTORY);
}
History.prototype.getHistoryRequestInterval = function()
{
if(this._items.length === 0)
return null;
var max = _.min(this._items, 'height').height - 1;
var min = max - Math.min(100, (MAX_HISTORY - this._items.length + 1)) + 1;
return {max: max, min: min};
} }
module.exports = History; module.exports = History;

View File

@ -1,7 +1,7 @@
var geoip = require('geoip-lite'); var geoip = require('geoip-lite');
var _ = require('lodash'); var _ = require('lodash');
var MAX_HISTORY = 36; var MAX_HISTORY = 40;
var Node = function Node(data) var Node = function Node(data)
{ {
@ -49,9 +49,13 @@ var Node = function Node(data)
if(typeof data.id !== 'undefined') if(typeof data.id !== 'undefined')
this.id = data.id; this.id = data.id;
if(typeof data.info !== 'undefined') if(typeof data.info !== 'undefined') {
this.info = data.info; this.info = data.info;
if(typeof data.info.canUpdateHistory === 'undefined')
data.info.canUpdateHistory = false;
}
if(typeof data.ip !== 'undefined'){ if(typeof data.ip !== 'undefined'){
if(data.ip === '::ffff:127.0.0.1') if(data.ip === '::ffff:127.0.0.1')
data.ip = '84.117.82.122'; data.ip = '84.117.82.122';
@ -75,9 +79,13 @@ Node.prototype.setGeo = function(ip)
Node.prototype.setInfo = function(data) Node.prototype.setInfo = function(data)
{ {
if(typeof data.info !== 'undefined') if(typeof data.info !== 'undefined') {
this.info = data.info; this.info = data.info;
if(typeof data.info.canUpdateHistory === 'undefined')
data.info.canUpdateHistory = false;
}
if(typeof data.ip !== 'undefined'){ if(typeof data.ip !== 'undefined'){
this.info.ip = data.ip; this.info.ip = data.ip;
this.setGeo(data.ip); this.setGeo(data.ip);
@ -131,4 +139,9 @@ Node.prototype.setState = function(active)
this.uptime.history.push({status: (active ? 'up' : 'down'), time: (new Date()).getTime()}); this.uptime.history.push({status: (active ? 'up' : 'down'), time: (new Date()).getTime()});
} }
Node.prototype.canUpdate = function()
{
return this.info.canUpdateHistory || false;
}
module.exports = Node; module.exports = Node;

View File

@ -181,7 +181,7 @@ span.small-title span.small {
.blocks-holder .block { .blocks-holder .block {
width: 6px; width: 6px;
height: 6px; height: 6px;
margin: 2px 1px 6px 1px; margin: 2px 1px 6px 0px;
float: left; float: left;
-webkit-border-radius: 1px; -webkit-border-radius: 1px;
border-radius: 1px; border-radius: 1px;

View File

@ -148,6 +148,23 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
break; break;
case "charts":
$scope.lastBlocksTime = data.blocktime;
$scope.difficultyChart = data.difficulty;
$scope.transactionDensity = data.transactions;
$scope.gasSpending = data.gasSpending;
$scope.blockPropagationChart = data.propagation;
$scope.uncleCountChart = data.uncleCount;
$scope.uncleCount = data.uncleCount[0] + data.uncleCount[1];
jQuery('.spark-blocktimes').sparkline($scope.lastBlocksTime, {type: 'bar', tooltipSuffix: ' s'});
jQuery('.spark-difficulty').sparkline($scope.difficultyChart, {type: 'bar'});
jQuery('.spark-transactions').sparkline($scope.transactionDensity, {type: 'bar'});
jQuery('.spark-gasspending').sparkline($scope.gasSpending, {type: 'bar'});
jQuery('.spark-uncles').sparkline($scope.uncleCountChart.reverse(), {type: 'bar', barSpacing: 1});
break;
case "inactive": case "inactive":
if(typeof data.stats !== 'undefined') if(typeof data.stats !== 'undefined')
$scope.nodes[findIndex({id: data.id})].stats = data.stats; $scope.nodes[findIndex({id: data.id})].stats = data.stats;
@ -237,11 +254,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
}).stats; }).stats;
$scope.lastBlock = $scope.bestStats.block.received; $scope.lastBlock = $scope.bestStats.block.received;
$scope.lastBlocksTime = $scope.bestStats.blockTimes;
$scope.lastDifficulty = $scope.bestStats.block.difficulty; $scope.lastDifficulty = $scope.bestStats.block.difficulty;
$scope.difficultyChart = $scope.bestStats.difficulty;
$scope.transactionDensity = $scope.bestStats.txDensity;
$scope.gasSpending = $scope.bestStats.gasSpending;
if(typeof $scope.bestStats.miners !== 'undefined') { if(typeof $scope.bestStats.miners !== 'undefined') {
$scope.miners = $scope.bestStats.miners; $scope.miners = $scope.bestStats.miners;
@ -258,11 +271,6 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
$scope.miners[key].name = name; $scope.miners[key].name = name;
}); });
} }
jQuery('.spark-blocktimes').sparkline($scope.lastBlocksTime.reverse(), {type: 'bar', tooltipSuffix: ' s'});
jQuery('.spark-difficulty').sparkline($scope.difficultyChart.reverse(), {type: 'bar'});
jQuery('.spark-transactions').sparkline($scope.transactionDensity.reverse(), {type: 'bar'});
jQuery('.spark-gasspending').sparkline($scope.gasSpending.reverse(), {type: 'bar'});
} }
$scope.avgBlockTime = _.max($scope.nodes, function(node) { $scope.avgBlockTime = _.max($scope.nodes, function(node) {

View File

@ -7,7 +7,7 @@
$.fn.sparkline.defaults.bar.height = 63; $.fn.sparkline.defaults.bar.height = 63;
$.fn.sparkline.defaults.bar.barWidth = 6; $.fn.sparkline.defaults.bar.barWidth = 6;
$.fn.sparkline.defaults.bar.barSpacing = 2; $.fn.sparkline.defaults.bar.barSpacing = 1;
$.fn.sparkline.defaults.bar.tooltipClassname = 'jqstooltip'; $.fn.sparkline.defaults.bar.tooltipClassname = 'jqstooltip';
$.fn.sparkline.defaults.bar.tooltipOffsetX = 0; $.fn.sparkline.defaults.bar.tooltipOffsetX = 0;
$.fn.sparkline.defaults.bar.tooltipFormat = $.spformat('<div class="tooltip-arrow"></div><div class="tooltip-inner">{{prefix}}{{value}}{{suffix}}</div>'); $.fn.sparkline.defaults.bar.tooltipFormat = $.spformat('<div class="tooltip-arrow"></div><div class="tooltip-inner">{{prefix}}{{value}}{{suffix}}</div>');