commit
187ad50eb5
26
app.js
26
app.js
@ -4,6 +4,7 @@ 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 askedForHistory = false;
|
||||||
|
var askedForHistoryTime = 0;
|
||||||
|
|
||||||
var Primus = require('primus'),
|
var Primus = require('primus'),
|
||||||
api,
|
api,
|
||||||
@ -63,15 +64,6 @@ 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.canNodeUpdate(data.id))
|
|
||||||
{
|
|
||||||
var range = Nodes.getHistory().getHistoryRequestInterval();
|
|
||||||
console.log("asked " + data.id + " for history");
|
|
||||||
console.log('interval', range);
|
|
||||||
spark.emit('history', range);
|
|
||||||
askedForHistory = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
client.write({action: 'add', data: info});
|
client.write({action: 'add', data: info});
|
||||||
client.write({action: 'charts', data: Nodes.getCharts()});
|
client.write({action: 'charts', data: Nodes.getCharts()});
|
||||||
}
|
}
|
||||||
@ -90,13 +82,14 @@ api.on('connection', function(spark) {
|
|||||||
client.write({action: 'charts', data: Nodes.getCharts()});
|
client.write({action: 'charts', data: Nodes.getCharts()});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.canNodeUpdate(data.id))
|
if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000))
|
||||||
{
|
{
|
||||||
var range = Nodes.getHistory().getHistoryRequestInterval();
|
var range = Nodes.getHistory().getHistoryRequestInterval();
|
||||||
console.log("asked " + data.id + " for history");
|
console.log("asked " + data.id + " for history");
|
||||||
console.log('interval', range);
|
console.log('interval', range);
|
||||||
spark.emit('history', range);
|
spark.emit('history', range);
|
||||||
askedForHistory = true;
|
askedForHistory = true;
|
||||||
|
askedForHistoryTime = (new Date()).getTime();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -107,7 +100,8 @@ api.on('connection', function(spark) {
|
|||||||
askedForHistory = false;
|
askedForHistory = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
spark.on('node-ping', function(data){
|
spark.on('node-ping', function(data)
|
||||||
|
{
|
||||||
spark.emit('node-pong');
|
spark.emit('node-pong');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -118,6 +112,16 @@ api.on('connection', function(spark) {
|
|||||||
var stats = Nodes.updateLatency(data.id, data.latency);
|
var stats = Nodes.updateLatency(data.id, data.latency);
|
||||||
|
|
||||||
client.write({action: 'latency', data: stats});
|
client.write({action: 'latency', data: stats});
|
||||||
|
|
||||||
|
if(Nodes.getHistory().requiresUpdate() && Nodes.canNodeUpdate(data.id) && (!askedForHistory || (new Date()).getTime() - askedForHistoryTime > 120000))
|
||||||
|
{
|
||||||
|
var range = Nodes.getHistory().getHistoryRequestInterval();
|
||||||
|
console.log("asked " + data.id + " for history");
|
||||||
|
console.log('interval', range);
|
||||||
|
spark.emit('history', range);
|
||||||
|
askedForHistory = true;
|
||||||
|
askedForHistoryTime = (new Date()).getTime();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -139,9 +139,19 @@ Collection.prototype.getHistory = function()
|
|||||||
Collection.prototype.canNodeUpdate = function(id)
|
Collection.prototype.canNodeUpdate = function(id)
|
||||||
{
|
{
|
||||||
var node = this.getNode({id: id});
|
var node = this.getNode({id: id});
|
||||||
|
|
||||||
if(!node)
|
if(!node)
|
||||||
return false;
|
return false;
|
||||||
return node.canUpdate();
|
|
||||||
|
if(node.canUpdate())
|
||||||
|
{
|
||||||
|
var diff = this._history.bestBlockNumber() - node.getBlockNumber();
|
||||||
|
|
||||||
|
if(diff <= 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Collection;
|
module.exports = Collection;
|
@ -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' && (this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1)))
|
if(typeof block !== 'undefined' && typeof block.number !== 'undefined' && typeof block.uncles !== 'undefined' && typeof block.transactions !== 'undefined' && typeof block.difficulty !== 'undefined')
|
||||||
{
|
{
|
||||||
var historyBlock = this.search(block.number);
|
var historyBlock = this.search(block.number);
|
||||||
|
|
||||||
@ -82,9 +82,12 @@ History.prototype.add = function(block, id)
|
|||||||
propagTimes: []
|
propagTimes: []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(this._items.length === 0 || block.number >= (this.bestBlock().height - MAX_HISTORY + 1))
|
||||||
|
{
|
||||||
item.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
item.propagTimes.push({node: id, received: now, propagation: block.propagation});
|
||||||
this._save(item);
|
this._save(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
@ -125,11 +128,21 @@ History.prototype.prevMaxBlock = function(number)
|
|||||||
return this._items[index];
|
return this._items[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.bestBlock = function(obj)
|
History.prototype.bestBlock = function()
|
||||||
{
|
{
|
||||||
return _.max(this._items, 'height');
|
return _.max(this._items, 'height');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
History.prototype.bestBlockNumber = function()
|
||||||
|
{
|
||||||
|
var best = this.bestBlock();
|
||||||
|
|
||||||
|
if(typeof best.height !== 'undefined')
|
||||||
|
return best.height;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
History.prototype.getNodePropagation = function(id)
|
History.prototype.getNodePropagation = function(id)
|
||||||
{
|
{
|
||||||
var propagation = new Array(MAX_PEER_PROPAGATION);
|
var propagation = new Array(MAX_PEER_PROPAGATION);
|
||||||
@ -159,6 +172,7 @@ History.prototype.getNodePropagation = function(id)
|
|||||||
History.prototype.getBlockPropagation = function()
|
History.prototype.getBlockPropagation = function()
|
||||||
{
|
{
|
||||||
var propagation = [];
|
var propagation = [];
|
||||||
|
var avgPropagation = 0;
|
||||||
|
|
||||||
_.forEach(this._items, function(n, key)
|
_.forEach(this._items, function(n, key)
|
||||||
{
|
{
|
||||||
@ -171,6 +185,11 @@ History.prototype.getBlockPropagation = function()
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(propagation.length > 0)
|
||||||
|
{
|
||||||
|
var avgPropagation = Math.round(_.sum(propagation) / propagation.length);
|
||||||
|
}
|
||||||
|
|
||||||
var x = d3.scale.linear()
|
var x = d3.scale.linear()
|
||||||
.domain([MIN_PROPAGATION_RANGE, MAX_PROPAGATION_RANGE])
|
.domain([MIN_PROPAGATION_RANGE, MAX_PROPAGATION_RANGE])
|
||||||
.interpolate(d3.interpolateRound);
|
.interpolate(d3.interpolateRound);
|
||||||
@ -187,7 +206,7 @@ History.prototype.getBlockPropagation = function()
|
|||||||
return {x: val.x, dx: val.dx, y: val.y, frequency: val.length, cumulative: freqCum, cumpercent: cumPercent};
|
return {x: val.x, dx: val.dx, y: val.y, frequency: val.length, cumulative: freqCum, cumpercent: cumPercent};
|
||||||
});
|
});
|
||||||
|
|
||||||
return histogram;
|
return {histogram: histogram, avg: avgPropagation};
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.getUncleCount = function()
|
History.prototype.getUncleCount = function()
|
||||||
|
@ -27,6 +27,7 @@ var Node = function Node(data)
|
|||||||
uncles: []
|
uncles: []
|
||||||
},
|
},
|
||||||
blocktimeAvg: 0,
|
blocktimeAvg: 0,
|
||||||
|
propagationAvg: 0,
|
||||||
blockTimes: [],
|
blockTimes: [],
|
||||||
difficulty: [],
|
difficulty: [],
|
||||||
latency: 0,
|
latency: 0,
|
||||||
@ -108,6 +109,16 @@ Node.prototype.setStats = function(stats, history)
|
|||||||
if(typeof stats !== 'undefined' && typeof stats.block !== 'undefined' && typeof stats.block.number !== 'undefined')
|
if(typeof stats !== 'undefined' && typeof stats.block !== 'undefined' && typeof stats.block.number !== 'undefined')
|
||||||
{
|
{
|
||||||
this.history = history;
|
this.history = history;
|
||||||
|
|
||||||
|
var positives = _.filter(history, function(p) {
|
||||||
|
return p >= 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(positives.length > 0)
|
||||||
|
stats.propagationAvg = Math.round(_.sum(positives)/positives.length);
|
||||||
|
else
|
||||||
|
stats.propagationAvg = 0;
|
||||||
|
|
||||||
this.stats = stats;
|
this.stats = stats;
|
||||||
|
|
||||||
return this.getStats();
|
return this.getStats();
|
||||||
@ -139,6 +150,11 @@ 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.getBlockNumber = function()
|
||||||
|
{
|
||||||
|
return this.stats.block.number;
|
||||||
|
}
|
||||||
|
|
||||||
Node.prototype.canUpdate = function()
|
Node.prototype.canUpdate = function()
|
||||||
{
|
{
|
||||||
return this.info.canUpdateHistory || false;
|
return this.info.canUpdateHistory || false;
|
||||||
|
@ -14,6 +14,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
$scope.lastDifficulty = 0;
|
$scope.lastDifficulty = 0;
|
||||||
$scope.upTimeTotal = 0;
|
$scope.upTimeTotal = 0;
|
||||||
$scope.avgBlockTime = 0;
|
$scope.avgBlockTime = 0;
|
||||||
|
$scope.blockPropagationAvg = 0;
|
||||||
$scope.avgHashrate = 0;
|
$scope.avgHashrate = 0;
|
||||||
$scope.uncleCount = 0;
|
$scope.uncleCount = 0;
|
||||||
$scope.bestStats = {};
|
$scope.bestStats = {};
|
||||||
@ -140,7 +141,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "blockPropagationChart":
|
case "blockPropagationChart":
|
||||||
$scope.blockPropagationChart = data;
|
$scope.blockPropagationChart = data.histogram;
|
||||||
|
$scope.blockPropagationAvg = data.avg;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -159,7 +161,8 @@ function StatsCtrl($scope, $filter, socket, _, toastr) {
|
|||||||
$scope.difficultyChart = data.difficulty;
|
$scope.difficultyChart = data.difficulty;
|
||||||
$scope.transactionDensity = data.transactions;
|
$scope.transactionDensity = data.transactions;
|
||||||
$scope.gasSpending = data.gasSpending;
|
$scope.gasSpending = data.gasSpending;
|
||||||
$scope.blockPropagationChart = data.propagation;
|
$scope.blockPropagationChart = data.propagation.histogram;
|
||||||
|
$scope.blockPropagationAvg = data.propagation.avg;
|
||||||
$scope.uncleCountChart = data.uncleCount;
|
$scope.uncleCountChart = data.uncleCount;
|
||||||
$scope.uncleCount = data.uncleCount[0] + data.uncleCount[1];
|
$scope.uncleCount = data.uncleCount[0] + data.uncleCount[1];
|
||||||
|
|
||||||
|
@ -174,6 +174,26 @@ angular.module('netStatsApp.filters', [])
|
|||||||
return 'text-danger'
|
return 'text-danger'
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
.filter('propagationAvgTimeClass', function() {
|
||||||
|
return function(propagationAvg, active) {
|
||||||
|
if( ! active)
|
||||||
|
return 'text-gray';
|
||||||
|
|
||||||
|
if(propagationAvg == 0)
|
||||||
|
return 'text-info';
|
||||||
|
|
||||||
|
if(propagationAvg < 1000)
|
||||||
|
return 'text-success';
|
||||||
|
|
||||||
|
if(propagationAvg < 3000)
|
||||||
|
return 'text-warning';
|
||||||
|
|
||||||
|
if(propagationAvg < 7000)
|
||||||
|
return 'text-orange';
|
||||||
|
|
||||||
|
return 'text-danger'
|
||||||
|
};
|
||||||
|
})
|
||||||
.filter('latencyFilter', function() {
|
.filter('latencyFilter', function() {
|
||||||
return function(stats) {
|
return function(stats) {
|
||||||
if(stats.active === false)
|
if(stats.active === false)
|
||||||
@ -212,30 +232,33 @@ angular.module('netStatsApp.filters', [])
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('blockPropagationFilter', function() {
|
.filter('blockPropagationFilter', function() {
|
||||||
return function(ms) {
|
return function(ms, prefix) {
|
||||||
|
if(typeof prefix === 'undefined')
|
||||||
|
prefix = '+';
|
||||||
|
|
||||||
var result = 0;
|
var result = 0;
|
||||||
|
|
||||||
if(ms < 1000) {
|
if(ms < 1000) {
|
||||||
return (ms === 0 ? "" : "+") + ms + " ms";
|
return (ms === 0 ? "" : prefix) + ms + " ms";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ms < 1000*60) {
|
if(ms < 1000*60) {
|
||||||
result = ms/1000;
|
result = ms/1000;
|
||||||
return "+" + result.toFixed(1) + " s";
|
return prefix + result.toFixed(1) + " s";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ms < 1000*60*60) {
|
if(ms < 1000*60*60) {
|
||||||
result = ms/1000/60;
|
result = ms/1000/60;
|
||||||
return "+" + Math.round(result) + " min";
|
return prefix + Math.round(result) + " min";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(ms < 1000*60*60*24) {
|
if(ms < 1000*60*60*24) {
|
||||||
result = ms/1000/60/60;
|
result = ms/1000/60/60;
|
||||||
return "+" + Math.round(result) + " h";
|
return prefix + Math.round(result) + " h";
|
||||||
}
|
}
|
||||||
|
|
||||||
result = ms/1000/60/60/24;
|
result = ms/1000/60/60/24;
|
||||||
return "+" + Math.round(result) + " days";
|
return prefix + Math.round(result) + " days";
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter('avgTimeFilter', function() {
|
.filter('avgTimeFilter', function() {
|
||||||
|
@ -101,10 +101,10 @@ block content
|
|||||||
span.big-details.spark-difficulty
|
span.big-details.spark-difficulty
|
||||||
|
|
||||||
div.col-xs-3.stat-holder.xpull-right
|
div.col-xs-3.stat-holder.xpull-right
|
||||||
div.big-info.chart.xdouble-chart.text-info
|
div.big-info.chart.xdouble-chart(class="{{ blockPropagationAvg | propagationAvgTimeClass : true }}")
|
||||||
//- i.icon-gas
|
//- i.icon-gas
|
||||||
span.small-title block propagation
|
span.small-title block propagation
|
||||||
//- span.small-value {{ lastDifficulty | number }}
|
span.small-value {{ blockPropagationAvg | blockPropagationFilter : '' }}
|
||||||
histogram.big-details.d3-blockpropagation(data="blockPropagationChart")
|
histogram.big-details.d3-blockpropagation(data="blockPropagationChart")
|
||||||
|
|
||||||
div.col-xs-3.stat-holder.pull-right
|
div.col-xs-3.stat-holder.pull-right
|
||||||
@ -174,6 +174,8 @@ block content
|
|||||||
th.th-peerPropagationTime
|
th.th-peerPropagationTime
|
||||||
i.icon-gas(data-toggle="tooltip", data-placement="top", title="Propagation time", ng-click="orderTable(['-stats.active', '-stats.block.number', 'stats.block.propagation'], false)")
|
i.icon-gas(data-toggle="tooltip", data-placement="top", title="Propagation time", ng-click="orderTable(['-stats.active', '-stats.block.number', 'stats.block.propagation'], false)")
|
||||||
th.th-peerPropagationChart
|
th.th-peerPropagationChart
|
||||||
|
th.th-peerPropagationAvg
|
||||||
|
i.icon-gas(data-toggle="tooltip", data-placement="top", title="Average propagation time", ng-click="orderTable(['-stats.active', 'stats.propagationAvg'], false)")
|
||||||
th
|
th
|
||||||
i.icon-bulb(data-toggle="tooltip", data-placement="top", title="Up-time", ng-click="orderTable(['-stats.active', '-stats.uptime'], false)")
|
i.icon-bulb(data-toggle="tooltip", data-placement="top", title="Up-time", ng-click="orderTable(['-stats.active', '-stats.uptime'], false)")
|
||||||
tbody(ng-cloak)
|
tbody(ng-cloak)
|
||||||
@ -203,4 +205,5 @@ block content
|
|||||||
div.propagationBox
|
div.propagationBox
|
||||||
span {{node.stats.block.propagation | blockPropagationFilter}}
|
span {{node.stats.block.propagation | blockPropagationFilter}}
|
||||||
td.peerPropagationChart(class="{{node.id}}")
|
td.peerPropagationChart(class="{{node.id}}")
|
||||||
|
td(class="{{ node.stats.propagationAvg | propagationAvgTimeClass : node.stats.active }}") {{ node.stats.propagationAvg | blockPropagationFilter : '' }}
|
||||||
td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }}
|
td(class="{{ node.stats.uptime | upTimeClass : node.stats.active }}") {{ node.stats.uptime | upTimeFilter }}
|
||||||
|
Loading…
Reference in New Issue
Block a user