diff --git a/libs/api.js b/libs/api.js index 9fcac7d..53ec46c 100644 --- a/libs/api.js +++ b/libs/api.js @@ -1,14 +1,49 @@ +var redis = require('redis'); var os = require('os'); module.exports = function(logger, poolConfigs){ - //Every 10 minutes clear out old hashrate stat data from redis - setInterval(function(){ - var tenMinutesAgo = (Date.now() / 1000 | 0) - (60 * 10); - connection.zremrangebyscore([coin + '_hashrate', '-inf', tenMinutesAgo]); - }, 10 * 60 * 1000); + var redisClients = []; + Object.keys(poolConfigs).forEach(function(coin){ + var poolConfig = poolConfigs[coin]; + var internalConfig = poolConfig.shareProcessing.internal; + var redisConfig = internalConfig.redis; + for (var i = 0; i < redisClients.length; i++){ + var client = redisClients[i]; + if (client.client.port === redisConfig.port && client.client.host === redisConfig.host){ + client.coins.push(coin); + return; + } + } + redisClients.push({ + coins: [coin], + client: redis.createClient(redisConfig.port, redisConfig.host) + }); + }); + + //Every 10 minutes clear out old hashrate stats for each coin from redis + var clearExpiredHashrates = function(){ + redisClients.forEach(function(client){ + var tenMinutesAgo = (Date.now() / 1000 | 0) - (60 * 10); + var redisCommands = client.coins.map(function(coin){ + return ['zremrangebyscore', coin + '_hashrate', '-inf', tenMinutesAgo]; + }); + client.client.multi(redisCommands).exec(function(err, replies){ + if (err) + console.log('error with clearing old hashrates ' + JSON.stringify(err)); + }); + }); + }; + setInterval(clearExpiredHashrates, 10 * 60 * 1000); + clearExpiredHashrates(); + + this.getStats = function(callback){ + + //get stats like hashrate and in/valid shares/blocks and workers in current round + + }; }; diff --git a/libs/website.js b/libs/website.js index c4fd2c0..17031ff 100644 --- a/libs/website.js +++ b/libs/website.js @@ -24,10 +24,14 @@ We will use fs.watch to detect changes to anything in the /website folder and up */ +var fs = require('fs'); +var path = require('path'); +var async = require('async'); var dot = require('dot'); var express = require('express'); +var api = require('./api.js'); module.exports = function(logger){ @@ -35,6 +39,9 @@ module.exports = function(logger){ var portalConfig = JSON.parse(process.env.portalConfig); var poolConfigs = JSON.parse(process.env.pools); + + var portalApi = new api(logger, poolConfigs); + var logIdentify = 'Website'; var websiteLogger = { @@ -49,10 +56,90 @@ module.exports = function(logger){ } }; + var pageResources = ''; + var pageTemplate; + var pageProcessed = ''; + + var loadWebPage = function(callback){ + fs.readdir('website', function(err, files){ + async.map(files, function(fileName, callback){ + var filePath = 'website/' + fileName; + fs.readFile(filePath, 'utf8', function(err, data){ + callback(null, {name: fileName, data: data, ext: path.extname(filePath)}); + }); + }, function(err, fileObjects){ + + var indexPage = fileObjects.filter(function(f){ + return f.name === 'index.html'; + })[0].data; + + var jsCode = ''; + cssCode += ''; + + var bodyIndex = indexPage.indexOf('
'); + pageTemplate = dot.template(indexPage.slice(bodyIndex)); + + + pageResources = indexPage.slice(0, bodyIndex); + var headIndex = pageResources.indexOf(''); + pageResources = pageResources.slice(0, headIndex) + + jsCode + '\n\n\n\n' + + cssCode + '\n\n\n\n' + + pageResources.slice(headIndex); + + applyTemplateInfo(); + callback || function(){}(); + }) + }); + }; + + loadWebPage(); + + var applyTemplateInfo = function(){ + + portalApi.getStats(function(stats){ + + //need to give template info about pools and stats + + pageProcessed = pageTemplate({test: 'visitor', time: Date.now()}); + }); + }; + + setInterval(function(){ + applyTemplateInfo(); + }, 5000); + + + var reloadTimeout; + fs.watch('website', function(){ + clearTimeout(reloadTimeout); + reloadTimeout = setTimeout(function(){ + loadWebPage(); + }, 500); + }); + + var app = express(); + //need to create a stats api endpoint for eventsource live stat updates which are triggered on the applytemplateinfo interval + + + + app.get('/', function(req, res){ - res.send('hello'); + res.send(pageResources + pageProcessed); }); app.use(function(err, req, res, next){ diff --git a/website/Chart.min.js b/website/Chart.min.js new file mode 100644 index 0000000..ab63588 --- /dev/null +++ b/website/Chart.min.js @@ -0,0 +1,39 @@ +var Chart=function(s){function v(a,c,b){a=A((a-c.graphMin)/(c.steps*c.stepValue),1,0);return b*c.steps*a}function x(a,c,b,e){function h(){g+=f;var k=a.animation?A(d(g),null,0):1;e.clearRect(0,0,q,u);a.scaleOverlay?(b(k),c()):(c(),b(k));if(1>=g)D(h);else if("function"==typeof a.onAnimationComplete)a.onAnimationComplete()}var f=a.animation?1/A(a.animationSteps,Number.MAX_VALUE,1):1,d=B[a.animationEasing],g=a.animation?0:1;"function"!==typeof c&&(c=function(){});D(h)}function C(a,c,b,e,h,f){var d;a= +Math.floor(Math.log(e-h)/Math.LN10);h=Math.floor(h/(1*Math.pow(10,a)))*Math.pow(10,a);e=Math.ceil(e/(1*Math.pow(10,a)))*Math.pow(10,a)-h;a=Math.pow(10,a);for(d=Math.round(e/a);dc;)a=dc?c:!isNaN(parseFloat(b))&& +isFinite(b)&&a)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r").join("\\'")+"');}return p.join('');");return c? +b(c):b}var r=this,B={linear:function(a){return a},easeInQuad:function(a){return a*a},easeOutQuad:function(a){return-1*a*(a-2)},easeInOutQuad:function(a){return 1>(a/=0.5)?0.5*a*a:-0.5*(--a*(a-2)-1)},easeInCubic:function(a){return a*a*a},easeOutCubic:function(a){return 1*((a=a/1-1)*a*a+1)},easeInOutCubic:function(a){return 1>(a/=0.5)?0.5*a*a*a:0.5*((a-=2)*a*a+2)},easeInQuart:function(a){return a*a*a*a},easeOutQuart:function(a){return-1*((a=a/1-1)*a*a*a-1)},easeInOutQuart:function(a){return 1>(a/=0.5)? +0.5*a*a*a*a:-0.5*((a-=2)*a*a*a-2)},easeInQuint:function(a){return 1*(a/=1)*a*a*a*a},easeOutQuint:function(a){return 1*((a=a/1-1)*a*a*a*a+1)},easeInOutQuint:function(a){return 1>(a/=0.5)?0.5*a*a*a*a*a:0.5*((a-=2)*a*a*a*a+2)},easeInSine:function(a){return-1*Math.cos(a/1*(Math.PI/2))+1},easeOutSine:function(a){return 1*Math.sin(a/1*(Math.PI/2))},easeInOutSine:function(a){return-0.5*(Math.cos(Math.PI*a/1)-1)},easeInExpo:function(a){return 0==a?1:1*Math.pow(2,10*(a/1-1))},easeOutExpo:function(a){return 1== +a?1:1*(-Math.pow(2,-10*a/1)+1)},easeInOutExpo:function(a){return 0==a?0:1==a?1:1>(a/=0.5)?0.5*Math.pow(2,10*(a-1)):0.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return 1<=a?a:-1*(Math.sqrt(1-(a/=1)*a)-1)},easeOutCirc:function(a){return 1*Math.sqrt(1-(a=a/1-1)*a)},easeInOutCirc:function(a){return 1>(a/=0.5)?-0.5*(Math.sqrt(1-a*a)-1):0.5*(Math.sqrt(1-(a-=2)*a)+1)},easeInElastic:function(a){var c=1.70158,b=0,e=1;if(0==a)return 0;if(1==(a/=1))return 1;b||(b=0.3);e