From abaef56982715e53d8d1d4c181445a06dd669432 Mon Sep 17 00:00:00 2001 From: cubedro Date: Tue, 28 Apr 2015 10:43:56 +0300 Subject: [PATCH] added getHistory --- app.js | 36 +++++++++++++++++--------------- models/collection.js | 24 ++++++++++++++++++++++ models/history.js | 44 +++++++++++++++++++++++++++++++++------- models/node.js | 19 ++++++++++++++--- public/css/style.css | 2 +- public/js/controllers.js | 26 ++++++++++++++++-------- public/js/script.js | 2 +- 7 files changed, 116 insertions(+), 37 deletions(-) diff --git a/app.js b/app.js index 8d76f54..1dd40e2 100644 --- a/app.js +++ b/app.js @@ -3,6 +3,7 @@ var app = express(); var path = require('path'); var favicon = require('serve-favicon'); var bodyParser = require('body-parser'); +var askedForHistory = false; var Primus = require('primus'), api, @@ -62,13 +63,14 @@ api.on('connection', function(spark) { var info = Nodes.add(data); 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}); - - var blockPropagationChart = Nodes.blockPropagationChart(); - client.write({action: 'blockPropagationChart', data: blockPropagationChart}); - - var uncleCount = Nodes.getUncleCount(); - client.write({action: 'uncleCount', data: uncleCount}); + client.write({action: 'charts', data: Nodes.getCharts()}); } }); @@ -82,16 +84,22 @@ api.on('connection', function(spark) { if(stats !== false) { client.write({action: 'update', data: stats}); + 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}); + if(Nodes.getHistory().requiresUpdate() && !askedForHistory && Nodes.getNode({id: data.id}).canUpdate()) + { + spark.emit('history', Nodes.getHistory().getHistoryRequestInterval()); + askedForHistory = true; } } }); + 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.emit('node-pong'); }); @@ -118,11 +126,7 @@ client.on('connection', function(spark) { spark.on('ready', function(data){ spark.emit('init', {nodes: Nodes.all()}); - var blockPropagationChart = Nodes.blockPropagationChart(); - spark.write({action: 'blockPropagationChart', data: blockPropagationChart}); - - var uncleCount = Nodes.getUncleCount(); - spark.write({action: 'uncleCount', data: uncleCount}); + spark.write({action: 'charts', data: Nodes.getCharts()}); }); spark.on('client-pong', function(data) { diff --git a/models/collection.js b/models/collection.js index c460db6..c1666f7 100644 --- a/models/collection.js +++ b/models/collection.js @@ -40,6 +40,20 @@ Collection.prototype.update = function(id, stats) 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) { var node = this.getNode({ id: id }); @@ -112,4 +126,14 @@ Collection.prototype.getUncleCount = function() return this._history.getUncleCount(); } +Collection.prototype.getCharts = function() +{ + return this._history.getCharts(); +} + +Collection.prototype.getHistory = function() +{ + return this._history; +} + module.exports = Collection; \ No newline at end of file diff --git a/models/history.js b/models/history.js index ac8349c..2727f89 100644 --- a/models/history.js +++ b/models/history.js @@ -33,7 +33,7 @@ var History = function History(data) 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); @@ -68,7 +68,9 @@ History.prototype.add = function(block, id) if(prevBlock) { 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 { @@ -92,10 +94,10 @@ History.prototype.add = function(block, id) History.prototype._save = function(block) { - this._items.push(block); + this._items.unshift(block); if(this._items.length > MAX_HISTORY){ - this._items.shift(); + this._items.pop(); } this._items = _.sortByOrder(this._items, 'height', false); @@ -279,7 +281,8 @@ History.prototype.getCharts = function() .map(function(item) { var chart = { - blocktime: item.block.time, + height: item.height, + blocktime: item.block.time/1000, difficulty: item.block.difficulty, uncles: item.block.uncles.length, transactions: item.block.transactions.length, @@ -289,12 +292,39 @@ History.prototype.getCharts = function() }) .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() { - 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; diff --git a/models/node.js b/models/node.js index 8030e56..20150e9 100644 --- a/models/node.js +++ b/models/node.js @@ -1,7 +1,7 @@ var geoip = require('geoip-lite'); var _ = require('lodash'); -var MAX_HISTORY = 36; +var MAX_HISTORY = 40; var Node = function Node(data) { @@ -49,9 +49,13 @@ var Node = function Node(data) if(typeof data.id !== 'undefined') this.id = data.id; - if(typeof data.info !== 'undefined') + if(typeof data.info !== 'undefined') { this.info = data.info; + if(typeof data.info.canUpdateHistory === 'undefined') + data.info.canUpdateHistory = false; + } + if(typeof data.ip !== 'undefined'){ if(data.ip === '::ffff:127.0.0.1') data.ip = '84.117.82.122'; @@ -75,9 +79,13 @@ Node.prototype.setGeo = function(ip) Node.prototype.setInfo = function(data) { - if(typeof data.info !== 'undefined') + if(typeof data.info !== 'undefined') { this.info = data.info; + if(typeof data.info.canUpdateHistory === 'undefined') + data.info.canUpdateHistory = false; + } + if(typeof data.ip !== 'undefined'){ this.info.ip = 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()}); } +Node.prototype.canUpdate = function() +{ + return this.info.canUpdateHistory || false; +} + module.exports = Node; diff --git a/public/css/style.css b/public/css/style.css index 301c0db..df778ca 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -181,7 +181,7 @@ span.small-title span.small { .blocks-holder .block { width: 6px; height: 6px; - margin: 2px 1px 6px 1px; + margin: 2px 1px 6px 0px; float: left; -webkit-border-radius: 1px; border-radius: 1px; diff --git a/public/js/controllers.js b/public/js/controllers.js index a7fe11c..ff2b8b2 100644 --- a/public/js/controllers.js +++ b/public/js/controllers.js @@ -148,6 +148,23 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { 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": if(typeof data.stats !== 'undefined') $scope.nodes[findIndex({id: data.id})].stats = data.stats; @@ -237,11 +254,7 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { }).stats; $scope.lastBlock = $scope.bestStats.block.received; - $scope.lastBlocksTime = $scope.bestStats.blockTimes; $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') { $scope.miners = $scope.bestStats.miners; @@ -258,11 +271,6 @@ function StatsCtrl($scope, $filter, socket, _, toastr) { $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) { diff --git a/public/js/script.js b/public/js/script.js index 42f702a..07e0649 100644 --- a/public/js/script.js +++ b/public/js/script.js @@ -7,7 +7,7 @@ $.fn.sparkline.defaults.bar.height = 63; $.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.tooltipOffsetX = 0; $.fn.sparkline.defaults.bar.tooltipFormat = $.spformat('
{{prefix}}{{value}}{{suffix}}
');