2014-12-04 22:35:09 +01:00
|
|
|
var geoip = require('geoip-lite');
|
2015-04-17 11:10:20 +02:00
|
|
|
var _ = require('lodash');
|
2014-12-04 22:35:09 +01:00
|
|
|
|
2015-04-28 09:43:56 +02:00
|
|
|
var MAX_HISTORY = 40;
|
2015-05-11 21:10:19 +02:00
|
|
|
var MAX_INACTIVE_TIME = 1000*60*60*4;
|
2015-04-06 16:08:36 +02:00
|
|
|
|
2015-02-17 06:12:44 +01:00
|
|
|
var Node = function Node(data)
|
2015-01-20 19:29:31 +01:00
|
|
|
{
|
2015-02-17 03:04:15 +01:00
|
|
|
this.id = null;
|
|
|
|
this.info = {};
|
|
|
|
this.geo = {}
|
|
|
|
this.stats = {
|
2015-01-20 19:29:31 +01:00
|
|
|
active: false,
|
|
|
|
mining: false,
|
2015-06-01 23:04:34 +02:00
|
|
|
hashrate: 0,
|
2015-02-17 03:04:15 +01:00
|
|
|
peers: 0,
|
|
|
|
pending: 0,
|
|
|
|
gasPrice: 0,
|
2015-02-17 10:30:41 +01:00
|
|
|
block: {
|
|
|
|
difficulty: 0,
|
|
|
|
number: 0,
|
|
|
|
gasLimit: 0,
|
2015-02-23 18:10:17 +01:00
|
|
|
timestamp: 0,
|
2015-04-29 07:49:43 +02:00
|
|
|
time: 0,
|
2015-02-23 18:10:17 +01:00
|
|
|
arrival: 0,
|
2015-03-27 10:44:07 +01:00
|
|
|
propagation: 0,
|
2015-03-27 20:05:43 +01:00
|
|
|
received: 0,
|
2015-04-24 07:37:03 +02:00
|
|
|
transactions: [],
|
|
|
|
uncles: []
|
2015-02-17 10:30:41 +01:00
|
|
|
},
|
2015-04-28 17:22:11 +02:00
|
|
|
propagationAvg: 0,
|
2015-02-23 14:57:41 +01:00
|
|
|
latency: 0,
|
2015-02-17 06:12:44 +01:00
|
|
|
uptime: 0,
|
2015-02-17 03:04:15 +01:00
|
|
|
lastUpdate: 0
|
|
|
|
};
|
2015-04-29 07:49:43 +02:00
|
|
|
|
2015-04-17 11:10:20 +02:00
|
|
|
this.history = new Array(MAX_HISTORY);
|
2015-04-29 07:49:43 +02:00
|
|
|
|
2015-03-27 11:28:55 +01:00
|
|
|
this.uptime = {
|
|
|
|
started: null,
|
|
|
|
history: []
|
|
|
|
};
|
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
this.init(data);
|
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node.prototype.init = function(data)
|
|
|
|
{
|
2015-04-17 11:10:20 +02:00
|
|
|
_.fill(this.history, -1);
|
2015-04-07 19:02:17 +02:00
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( this.id === null )
|
|
|
|
{
|
|
|
|
this.uptime.started = _.now();
|
2015-03-27 11:28:55 +01:00
|
|
|
this.setState(true);
|
|
|
|
}
|
2015-01-20 19:29:31 +01:00
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(data.id) )
|
2015-02-17 06:12:44 +01:00
|
|
|
this.id = data.id;
|
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
this.setInfo(data);
|
2015-02-18 07:06:41 +01:00
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(data.latency) )
|
2015-02-23 15:20:05 +01:00
|
|
|
this.stats.latency = data.latency;
|
|
|
|
|
2015-01-20 19:29:31 +01:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2015-02-17 10:30:41 +01:00
|
|
|
Node.prototype.setInfo = function(data)
|
|
|
|
{
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(data.info) )
|
|
|
|
{
|
2015-02-17 10:30:41 +01:00
|
|
|
this.info = data.info;
|
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( _.isUndefined(data.info.canUpdateHistory) )
|
2015-04-28 09:43:56 +02:00
|
|
|
data.info.canUpdateHistory = false;
|
|
|
|
}
|
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(data.ip) )
|
|
|
|
{
|
|
|
|
if(data.ip === '::ffff:127.0.0.1')
|
|
|
|
data.ip = '84.117.82.122';
|
|
|
|
|
2015-02-17 10:30:41 +01:00
|
|
|
this.info.ip = data.ip;
|
2015-04-29 07:49:43 +02:00
|
|
|
this.setGeo();
|
2015-02-17 10:30:41 +01:00
|
|
|
}
|
2015-02-18 07:06:41 +01:00
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(data.spark) )
|
2015-02-18 07:06:41 +01:00
|
|
|
this.spark = data.spark;
|
2015-03-27 11:28:55 +01:00
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
var uptimeCnt = this.uptime.history.length;
|
|
|
|
|
|
|
|
if( uptimeCnt > 0 && this.uptime.history[uptimeCnt - 1].status === 'down' )
|
2015-03-27 11:28:55 +01:00
|
|
|
this.setState(true);
|
2015-04-29 07:49:43 +02:00
|
|
|
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node.prototype.setGeo = function()
|
|
|
|
{
|
|
|
|
this.geo = geoip.lookup(this.info.ip);
|
|
|
|
|
|
|
|
return this;
|
2015-02-17 10:30:41 +01:00
|
|
|
}
|
|
|
|
|
2015-02-17 06:12:44 +01:00
|
|
|
Node.prototype.getInfo = function()
|
|
|
|
{
|
2015-04-29 07:49:43 +02:00
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
info: this.info,
|
|
|
|
geo: this.geo,
|
|
|
|
stats: this.stats,
|
|
|
|
history: this.history
|
|
|
|
};
|
2015-02-17 06:12:44 +01:00
|
|
|
}
|
|
|
|
|
2015-04-17 11:10:20 +02:00
|
|
|
Node.prototype.setStats = function(stats, history)
|
2015-03-27 10:44:07 +01:00
|
|
|
{
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(stats) && !_.isUndefined(stats.block) && !_.isUndefined(stats.block.number) )
|
2015-03-27 10:44:07 +01:00
|
|
|
{
|
2015-04-17 11:10:20 +02:00
|
|
|
this.history = history;
|
2015-04-28 17:22:11 +02:00
|
|
|
|
|
|
|
var positives = _.filter(history, function(p) {
|
|
|
|
return p >= 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
if(positives.length > 0)
|
2015-04-29 07:49:43 +02:00
|
|
|
stats.propagationAvg = Math.round( _.sum(positives) / positives.length );
|
2015-04-28 17:22:11 +02:00
|
|
|
else
|
|
|
|
stats.propagationAvg = 0;
|
|
|
|
|
2015-06-01 20:42:50 +02:00
|
|
|
if( !_.isUndefined(this.stats.latency) )
|
|
|
|
stats.latency = this.stats.latency;
|
|
|
|
|
2015-03-27 10:44:07 +01:00
|
|
|
this.stats = stats;
|
|
|
|
|
|
|
|
return this.getStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-01 21:51:31 +02:00
|
|
|
Node.prototype.setBlock = function(block, history)
|
|
|
|
{
|
2015-06-01 22:22:34 +02:00
|
|
|
if( !_.isUndefined(block) && !_.isUndefined(block.number) )
|
2015-06-01 21:51:31 +02:00
|
|
|
{
|
|
|
|
this.history = history;
|
|
|
|
var propagationAvg = 0;
|
|
|
|
|
|
|
|
var positives = _.filter(history, function(p) {
|
|
|
|
return p >= 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
if(positives.length > 0)
|
|
|
|
propagationAvg = Math.round( _.sum(positives) / positives.length );
|
|
|
|
else
|
|
|
|
propagationAvg = 0;
|
|
|
|
|
|
|
|
this.stats.block = block;
|
|
|
|
this.stats.propagationAvg = propagationAvg;
|
|
|
|
|
|
|
|
return this.getBlockStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-01 20:42:50 +02:00
|
|
|
Node.prototype.setPending = function(stats)
|
|
|
|
{
|
|
|
|
if( !_.isUndefined(stats) && !_.isUndefined(stats.pending) )
|
|
|
|
{
|
|
|
|
this.stats.pending = stats.pending;
|
|
|
|
|
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
pending: this.stats.pending
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-06-01 23:04:34 +02:00
|
|
|
Node.prototype.setBasicStats = function(stats)
|
|
|
|
{
|
|
|
|
if( !_.isUndefined(stats) )
|
|
|
|
{
|
|
|
|
this.stats.active = stats.active;
|
|
|
|
this.stats.mining = stats.mining;
|
|
|
|
this.stats.hashrate = stats.hashrate;
|
|
|
|
this.stats.peers = stats.peers;
|
|
|
|
this.stats.gasPrice = stats.gasPrice;
|
|
|
|
this.stats.uptime = stats.uptime;
|
|
|
|
|
|
|
|
return this.getBasicStats();
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-04-03 06:00:06 +02:00
|
|
|
Node.prototype.setLatency = function(latency)
|
|
|
|
{
|
2015-04-29 07:49:43 +02:00
|
|
|
if( !_.isUndefined(latency) )
|
2015-04-03 06:00:06 +02:00
|
|
|
{
|
|
|
|
this.stats.latency = latency;
|
|
|
|
|
2015-04-29 07:49:43 +02:00
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
latency: latency
|
|
|
|
};
|
2015-04-03 06:00:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-17 06:12:44 +01:00
|
|
|
Node.prototype.getStats = function()
|
|
|
|
{
|
2015-04-29 07:49:43 +02:00
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
stats: this.stats,
|
|
|
|
history: this.history
|
|
|
|
};
|
2015-02-17 06:12:44 +01:00
|
|
|
}
|
|
|
|
|
2015-06-01 21:51:31 +02:00
|
|
|
Node.prototype.getBlockStats = function()
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
block: this.stats.block,
|
|
|
|
propagationAvg: this.stats.propagationAvg,
|
|
|
|
history: this.history
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-06-01 23:04:34 +02:00
|
|
|
Node.prototype.getBasicStats = function()
|
|
|
|
{
|
|
|
|
return {
|
|
|
|
id: this.id,
|
|
|
|
stats: {
|
|
|
|
active: this.stats.active,
|
|
|
|
mining: this.stats.mining,
|
|
|
|
hashrate: this.stats.hashrate,
|
|
|
|
peers: this.stats.peers,
|
|
|
|
gasPrice: this.stats.gasPrice,
|
|
|
|
uptime: this.stats.uptime
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-03-27 11:28:55 +01:00
|
|
|
Node.prototype.setState = function(active)
|
|
|
|
{
|
|
|
|
this.stats.active = active;
|
2015-04-29 07:49:43 +02:00
|
|
|
this.uptime.history.push({
|
|
|
|
status: (active ? 'up' : 'down'),
|
|
|
|
time: _.now()
|
|
|
|
});
|
2015-03-27 11:28:55 +01:00
|
|
|
}
|
|
|
|
|
2015-04-29 01:33:49 +02:00
|
|
|
Node.prototype.getBlockNumber = function()
|
|
|
|
{
|
|
|
|
return this.stats.block.number;
|
|
|
|
}
|
|
|
|
|
2015-04-28 09:43:56 +02:00
|
|
|
Node.prototype.canUpdate = function()
|
|
|
|
{
|
|
|
|
return this.info.canUpdateHistory || false;
|
|
|
|
}
|
|
|
|
|
2015-05-11 20:41:37 +02:00
|
|
|
Node.prototype.isInactiveAndOld = function()
|
|
|
|
{
|
|
|
|
if(this.stats.active)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
var lastState = this.uptime.history[this.uptime.history.length -1];
|
|
|
|
|
|
|
|
if( !_.isUndefined(lastState) && !_.isUndefined(lastState.status) && !_.isUndefined(lastState.time) )
|
|
|
|
{
|
|
|
|
if( lastState.status === 'down' && (_.now() - lastState.time) > MAX_INACTIVE_TIME )
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-02-11 11:56:33 +01:00
|
|
|
module.exports = Node;
|