241 lines
7.0 KiB
JavaScript
241 lines
7.0 KiB
JavaScript
var fs = require('fs');
|
|
var async = require('async');
|
|
var http = require('http');
|
|
var apiInterfaces = require('./apiInterfaces.js')(config.daemon, config.wallet, config.api);
|
|
|
|
var logSystem = 'charts';
|
|
require('./exceptionWriter.js')(logSystem);
|
|
|
|
log('info', logSystem, 'Started');
|
|
|
|
function startDataCollectors() {
|
|
async.each(Object.keys(config.charts.pool), function(chartName) {
|
|
var settings = config.charts.pool[chartName];
|
|
if(settings.enabled) {
|
|
setInterval(function() {
|
|
collectPoolStatWithInterval(chartName, settings);
|
|
}, settings.updateInterval * 1000);
|
|
}
|
|
});
|
|
|
|
var settings = config.charts.user.hashrate;
|
|
if(settings.enabled) {
|
|
setInterval(function() {
|
|
collectUsersHashrate('hashrate', settings);
|
|
}, settings.updateInterval * 1000)
|
|
}
|
|
}
|
|
|
|
function getChartDataFromRedis(chartName, callback) {
|
|
redisClient.get(getStatsRedisKey(chartName), function(error, data) {
|
|
callback(data ? JSON.parse(data) : []);
|
|
});
|
|
}
|
|
|
|
function getUserHashrateChartData(address, callback) {
|
|
getChartDataFromRedis('hashrate:' + address, callback);
|
|
}
|
|
|
|
function convertPaymentsDataToChart(paymentsData) {
|
|
var data = [];
|
|
if(paymentsData && paymentsData.length) {
|
|
for(var i = 0; paymentsData[i]; i += 2) {
|
|
data.push([+paymentsData[i + 1], paymentsData[i].split(':')[1] / config.coinUnits]);
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
function getUserChartsData(address, paymentsData, callback) {
|
|
var stats = {};
|
|
var chartsFuncs = {
|
|
hashrate: function(callback) {
|
|
getUserHashrateChartData(address, function(data) {
|
|
callback(null, data);
|
|
});
|
|
},
|
|
|
|
payments: function(callback) {
|
|
callback(null, convertPaymentsDataToChart(paymentsData));
|
|
}
|
|
};
|
|
for(var chartName in chartsFuncs) {
|
|
if(!config.charts.user[chartName].enabled) {
|
|
delete chartsFuncs[chartName];
|
|
}
|
|
}
|
|
async.parallel(chartsFuncs, callback);
|
|
}
|
|
|
|
function getStatsRedisKey(chartName) {
|
|
return config.coin + ':charts:' + chartName;
|
|
}
|
|
|
|
var chartStatFuncs = {
|
|
hashrate: getPoolHashrate,
|
|
workers: getPoolWorkers,
|
|
difficulty: getNetworkDifficulty,
|
|
price: getCoinPrice,
|
|
profit: getCoinProfit
|
|
};
|
|
|
|
var statValueHandler = {
|
|
avg: function(set, value) {
|
|
set[1] = (set[1] * set[2] + value) / (set[2] + 1);
|
|
},
|
|
round: function(set, value) {
|
|
statValueHandler.avg(set, value);
|
|
set[1] = Math.round(set[1]);
|
|
},
|
|
max: function(set, value) {
|
|
if(value > set[1]) {
|
|
set[1] = value;
|
|
}
|
|
}
|
|
};
|
|
|
|
var preSaveFunctions = {
|
|
hashrate: statValueHandler.avg,
|
|
workers: statValueHandler.max,
|
|
difficulty: statValueHandler.round,
|
|
price: statValueHandler.avg,
|
|
profit: statValueHandler.avg
|
|
};
|
|
|
|
function storeCollectedValues(chartName, values, settings) {
|
|
for(var i in values) {
|
|
storeCollectedValue(chartName + ':' + i, values[i], settings);
|
|
}
|
|
}
|
|
|
|
function storeCollectedValue(chartName, value, settings) {
|
|
var now = new Date() / 1000 | 0;
|
|
getChartDataFromRedis(chartName, function(sets) {
|
|
var lastSet = sets[sets.length - 1]; // [time, avgValue, updatesCount]
|
|
if(!lastSet || now - lastSet[0] > settings.stepInterval) {
|
|
lastSet = [now, value, 1];
|
|
sets.push(lastSet);
|
|
while(now - sets[0][0] > settings.maximumPeriod) { // clear old sets
|
|
sets.shift();
|
|
}
|
|
}
|
|
else {
|
|
preSaveFunctions[chartName]
|
|
? preSaveFunctions[chartName](lastSet, value)
|
|
: statValueHandler.round(lastSet, value);
|
|
lastSet[2]++;
|
|
}
|
|
redisClient.set(getStatsRedisKey(chartName), JSON.stringify(sets));
|
|
log('info', logSystem, chartName + ' chart collected value ' + value + '. Total sets count ' + sets.length);
|
|
log('info', logSystem, chartName + ' data: ' + JSON.stringify(sets));
|
|
});
|
|
}
|
|
|
|
function collectPoolStatWithInterval(chartName, settings) {
|
|
async.waterfall([
|
|
chartStatFuncs[chartName],
|
|
function(value, callback) {
|
|
storeCollectedValue(chartName, value, settings, callback);
|
|
}
|
|
]);
|
|
}
|
|
|
|
function getPoolStats(callback) {
|
|
apiInterfaces.pool('/stats', callback);
|
|
}
|
|
|
|
function getPoolHashrate(callback) {
|
|
getPoolStats(function(error, stats) {
|
|
callback(error, stats.pool ? Math.round(stats.pool.hashrate) : null);
|
|
});
|
|
}
|
|
|
|
function getPoolWorkers(callback) {
|
|
getPoolStats(function(error, stats) {
|
|
callback(error, stats.pool ? stats.pool.miners : null);
|
|
});
|
|
}
|
|
|
|
function getNetworkDifficulty(callback) {
|
|
getPoolStats(function(error, stats) {
|
|
callback(error, stats.pool ? stats.network.difficulty : null);
|
|
});
|
|
}
|
|
|
|
function getUsersHashrates(callback) {
|
|
apiInterfaces.pool('/miners_hashrate', function(error, data) {
|
|
callback(data.minersHashrate);
|
|
});
|
|
}
|
|
|
|
function collectUsersHashrate(chartName, settings) {
|
|
var redisBaseKey = getStatsRedisKey(chartName) + ':';
|
|
redisClient.keys(redisBaseKey + '*', function(keys) {
|
|
var hashrates = {};
|
|
for(var i in keys) {
|
|
hashrates[keys[i].substr(keys[i].length)] = 0;
|
|
}
|
|
getUsersHashrates(function(newHashrates) {
|
|
for(var address in newHashrates) {
|
|
hashrates[address] = newHashrates[address];
|
|
}
|
|
storeCollectedValues(chartName, hashrates, settings);
|
|
});
|
|
});
|
|
}
|
|
|
|
function getCoinPrice(callback) {
|
|
apiInterfaces.jsonHttpRequest('www.cryptonator.com', 443, '', function(error, response) {
|
|
callback(response.error ? response.error : error, response.success ? +response.ticker.price : null);
|
|
}, '/api/ticker/' + config.symbol.toLowerCase() + '-usd');
|
|
}
|
|
|
|
function getCoinProfit(callback) {
|
|
getCoinPrice(function(error, price) {
|
|
if(error) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
getPoolStats(function(error, stats) {
|
|
if(error) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
callback(null, stats.network.reward * price / stats.network.difficulty / config.coinUnits);
|
|
});
|
|
});
|
|
}
|
|
|
|
function getPoolChartsData(callback) {
|
|
var chartsNames = [];
|
|
var redisKeys = [];
|
|
for(var chartName in config.charts.pool) {
|
|
if(config.charts.pool[chartName].enabled) {
|
|
chartsNames.push(chartName);
|
|
redisKeys.push(getStatsRedisKey(chartName));
|
|
}
|
|
}
|
|
if(redisKeys.length) {
|
|
redisClient.mget(redisKeys, function(error, data) {
|
|
var stats = {};
|
|
if(data) {
|
|
for(var i in data) {
|
|
if(data[i]) {
|
|
stats[chartsNames[i]] = JSON.parse(data[i]);
|
|
}
|
|
}
|
|
}
|
|
callback(error, stats);
|
|
});
|
|
}
|
|
else {
|
|
callback(null, {});
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
startDataCollectors: startDataCollectors,
|
|
getUserChartsData: getUserChartsData,
|
|
getPoolChartsData: getPoolChartsData
|
|
};
|