diff --git a/init.js b/init.js index e1332f1..511cac1 100644 --- a/init.js +++ b/init.js @@ -14,6 +14,7 @@ var PoolWorker = require('./libs/poolWorker.js'); var PaymentProcessor = require('./libs/paymentProcessor.js'); var Website = require('./libs/website.js'); var ProfitSwitch = require('./libs/profitSwitch.js'); +var NetworkStats = require('./libs/networkStats.js'); var algos = require('stratum-pool/lib/algoProperties.js'); @@ -80,6 +81,9 @@ if (cluster.isWorker){ case 'profitSwitch': new ProfitSwitch(logger); break; + case 'networkStats': + new NetworkStats(logger); + break; } return; @@ -447,7 +451,6 @@ var startPaymentProcessor = function(){ }); }; - var startWebsite = function(){ if (!portalConfig.website.enabled) return; @@ -480,7 +483,24 @@ var startProfitSwitch = function(){ worker.on('exit', function(code, signal){ logger.error('Master', 'Profit', 'Profit switching process died, spawning replacement...'); setTimeout(function(){ - startWebsite(portalConfig, poolConfigs); + startProfitSwitch(portalConfig, poolConfigs); + }, 2000); + }); +}; + +var startNetworkStats = function(){ + + if (!portalConfig.website.enabled) return; + + var worker = cluster.fork({ + workerType: 'networkStats', + pools: JSON.stringify(poolConfigs), + portalConfig: JSON.stringify(portalConfig) + }); + worker.on('exit', function(code, signal){ + logger.error('Master', 'Website', 'Website process died, spawning replacement...'); + setTimeout(function(){ + startNetworkStats(portalConfig, poolConfigs); }, 2000); }); }; @@ -493,6 +513,8 @@ var startProfitSwitch = function(){ startPaymentProcessor(); + startNetworkStats(); + startWebsite(); startProfitSwitch(); diff --git a/libs/networkStats.js b/libs/networkStats.js new file mode 100644 index 0000000..55e3ce9 --- /dev/null +++ b/libs/networkStats.js @@ -0,0 +1,119 @@ +var fs = require('fs'); +var request = require('request'); + +var redis = require('redis'); +var async = require('async'); + +var Stratum = require('stratum-pool'); +var util = require('stratum-pool/lib/util.js'); + +module.exports = function(logger){ + var poolConfigs = JSON.parse(process.env.pools); + + var enabledPools = []; + + Object.keys(poolConfigs).forEach(function(coin) { + enabledPools.push(coin); + }); + + async.filter(enabledPools, function(coin, callback){ + SetupForStats(logger, poolConfigs[coin], function(setupResults){ + callback(null, setupResults); + }); + }, function(err, results){ + results.forEach(function(coin){ + + var poolOptions = poolConfigs[coin]; + var processingConfig = poolOptions.paymentProcessing; + var logSystem = 'Payments'; + var logComponent = coin; + + logger.debug(logSystem, logComponent, 'Payment processing setup with daemon (' + + processingConfig.daemon.user + '@' + processingConfig.daemon.host + ':' + processingConfig.daemon.port + + ') and redis (' + poolOptions.redis.host + ':' + poolOptions.redis.port + ')'); + }); + }); +}; + +function SetupForStats(logger, poolOptions, setupFinished) { + + var coin = poolOptions.coin.name; + var processingConfig = poolOptions.paymentProcessing; + + var logSystem = 'Payments'; + var logComponent = coin; + + var daemon = new Stratum.daemon.interface([processingConfig.daemon], function(severity, message){ + logger[severity](logSystem, logComponent, message); + }); + + var redisClient = redis.createClient(poolOptions.redis.port, poolOptions.redis.host); + // redis auth if enabled + if (poolOptions.redis.password) { + redisClient.auth(poolOptions.redis.password); + } + + function cacheNetworkStats () { + var params = null; + daemon.cmd('getmininginfo', params, + function (result) { + if (!result || result.error || result[0].error || !result[0].response) { + logger.error(logSystem, logComponent, 'Error with RPC call getmininginfo '+JSON.stringify(result[0].error)); + return; + } + + var coin = logComponent; + var finalRedisCommands = []; + + if (result[0].response.blocks !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]); + } + if (result[0].response.difficulty !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]); + } + if (result[0].response.networkhashps !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networkhashps]); + } + + daemon.cmd('getnetworkinfo', params, + function (result) { + if (!result || result.error || result[0].error || !result[0].response) { + logger.error(logSystem, logComponent, 'Error with RPC call getnetworkinfo '+JSON.stringify(result[0].error)); + return; + } + + if (result[0].response.connections !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]); + } + if (result[0].response.version !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkVersion', result[0].response.version]); + } + if (result[0].response.subversion !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkSubVersion', result[0].response.subversion]); + } + if (result[0].response.protocolversion !== null) { + finalRedisCommands.push(['hset', coin + ':stats', 'networkProtocolVersion', result[0].response.protocolversion]); + } + + if (finalRedisCommands.length <= 0) + return; + + redisClient.multi(finalRedisCommands).exec(function(error, results){ + if (error){ + logger.error(logSystem, logComponent, 'Error with redis during call to cacheNetworkStats() ' + JSON.stringify(error)); + return; + } + }); + } + ); + } + ); + } + + // network stats caching every 58 seconds + var stats_interval = 58 * 1000; + var statsInterval = setInterval(function() { + // update network stats using coin daemon + cacheNetworkStats(); + }, stats_interval); +} diff --git a/libs/paymentProcessor.js b/libs/paymentProcessor.js index 5e24b4d..2ff9696 100644 --- a/libs/paymentProcessor.js +++ b/libs/paymentProcessor.js @@ -351,63 +351,6 @@ function SetupForPool(logger, poolOptions, setupFinished){ }); } - function cacheNetworkStats () { - var params = null; - daemon.cmd('getmininginfo', params, - function (result) { - if (!result || result.error || result[0].error || !result[0].response) { - logger.error(logSystem, logComponent, 'Error with RPC call getmininginfo '+JSON.stringify(result[0].error)); - return; - } - - var coin = logComponent; - var finalRedisCommands = []; - - if (result[0].response.blocks !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkBlocks', result[0].response.blocks]); - } - if (result[0].response.difficulty !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkDiff', result[0].response.difficulty]); - } - if (result[0].response.networkhashps !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkSols', result[0].response.networkhashps]); - } - - daemon.cmd('getnetworkinfo', params, - function (result) { - if (!result || result.error || result[0].error || !result[0].response) { - logger.error(logSystem, logComponent, 'Error with RPC call getnetworkinfo '+JSON.stringify(result[0].error)); - return; - } - - if (result[0].response.connections !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkConnections', result[0].response.connections]); - } - if (result[0].response.version !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkVersion', result[0].response.version]); - } - if (result[0].response.subversion !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkSubVersion', result[0].response.subversion]); - } - if (result[0].response.protocolversion !== null) { - finalRedisCommands.push(['hset', coin + ':stats', 'networkProtocolVersion', result[0].response.protocolversion]); - } - - if (finalRedisCommands.length <= 0) - return; - - redisClient.multi(finalRedisCommands).exec(function(error, results){ - if (error){ - logger.error(logSystem, logComponent, 'Error with redis during call to cacheNetworkStats() ' + JSON.stringify(error)); - return; - } - }); - } - ); - } - ); - } - // run shielding process every x minutes var shieldIntervalState = 0; // do not send ZtoT and TtoZ and same time, this results in operation failed! var shielding_interval = Math.max(parseInt(poolOptions.walletInterval || 1), 1) * 60 * 1000; // run every x minutes @@ -426,14 +369,7 @@ function SetupForPool(logger, poolOptions, setupFinished){ } }, shielding_interval); } - - // network stats caching every 58 seconds - var stats_interval = 58 * 1000; - var statsInterval = setInterval(function() { - // update network stats using coin daemon - cacheNetworkStats(); - }, stats_interval); - + // market stats caching every 5 minutes if (getMarketStats === true) { var market_stats_interval = 300 * 1000; diff --git a/website/pages/stats.html b/website/pages/stats.html index 3504db1..6a50566 100644 --- a/website/pages/stats.html +++ b/website/pages/stats.html @@ -190,7 +190,7 @@ {{blockscomb.push(block);}} {{ } }} {{ } }} - + {{if (blockscomb.length > 0) { }}