├── public ├── images │ ├── up.png │ ├── down.png │ ├── favicon.ico │ ├── twitter.png │ ├── logos │ │ ├── logo.png │ │ ├── nodejs.png │ │ └── redis.png │ ├── updating.png │ └── maintenance.png ├── javascript │ ├── google-analytics.js │ └── piwik-analytics.js └── stylesheets │ └── style.css ├── .gitignore ├── package.json ├── views ├── layout.jade ├── about.jade ├── faq.jade ├── index.jade └── stats.jade ├── README.md └── WhatStatus.js /public/images/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/up.png -------------------------------------------------------------------------------- /public/images/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/down.png -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/twitter.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | /node_modules/ 4 | 5 | *.sublime-workspace 6 | 7 | *.sublime-project 8 | -------------------------------------------------------------------------------- /public/images/logos/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/logos/logo.png -------------------------------------------------------------------------------- /public/images/updating.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/updating.png -------------------------------------------------------------------------------- /public/images/logos/nodejs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/logos/nodejs.png -------------------------------------------------------------------------------- /public/images/logos/redis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/logos/redis.png -------------------------------------------------------------------------------- /public/images/maintenance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dewey/WhatStatus/HEAD/public/images/maintenance.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name":"WhatStatus", 3 | "version":"0.0.1", 4 | "private":true, 5 | "scripts":{ 6 | "start":"node app" 7 | }, 8 | "dependencies":{ 9 | "express":"3.1.0", 10 | "jade":"*", 11 | "net":"*", 12 | "cron":"*", 13 | "time":"*", 14 | "redis": "*", 15 | "request":"*", 16 | "date-format-lite":"*" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/javascript/google-analytics.js: -------------------------------------------------------------------------------- 1 | var _gaq = _gaq || []; 2 | _gaq.push(['_setAccount', 'UA-24922611-1']); 3 | _gaq.push(['_trackPageview']); 4 | (function() { 5 | var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; 6 | ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; 7 | var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); 8 | })(); -------------------------------------------------------------------------------- /public/javascript/piwik-analytics.js: -------------------------------------------------------------------------------- 1 | var _paq = _paq || []; 2 | _paq.push(['trackPageView']); 3 | _paq.push(['enableLinkTracking']); 4 | (function() { 5 | var u="//analytics.notmyhostna.me/"; 6 | _paq.push(['setTrackerUrl', u+'piwik.php']); 7 | _paq.push(['setSiteId', 2]); 8 | var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; 9 | g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); 10 | })(); 11 | 12 | 13 | -------------------------------------------------------------------------------- /views/layout.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel="stylesheet", href="/stylesheets/style.css") 6 | link(rel="shortcut icon", href="images/favicon.ico") 7 | script(src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js") 8 | script(src="https://www.google.com/jsapi") 9 | body 10 | a(href="https://twitter.com/#!/WhatcdStatus") 11 | img(src="images/twitter.png", alt="Follow us on Twitter!", class="follow-us") 12 | block body-content 13 | footer 14 | p All infos are cached. Updated every minute. 15 | ul 16 | li 17 | a(href="about") About 18 | li 19 | a(href="faq") FAQ 20 | li 21 | a(href="stats") Stats 22 | li 23 | a(href="https://twitter.com/whatcd") @whatcd on Twitter 24 | li 25 | a(href="https://twitter.com/#!/WhatcdStatus") @WhatcdStatus on Twitter 26 | script(src="/javascript/google-analytics.js") 27 | script(src="/javascript/piwik-analytics.js") -------------------------------------------------------------------------------- /views/about.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | block body-content 3 | div#content 4 | h2 5 | a(href="/") WhatStatus.info 6 | h3 About 7 | p The services are checked every minute, if a service is down for more than 3 minutes it's reflected on the site. 8 | 9 | h3 API 10 | 11 | p The following API endpoints are available: 12 | 13 | p.api 14 | a(href="api/uptime") api/uptime 15 | p.api-description Uptime of all the components. [hours] 16 | 17 | p.api 18 | a(href="api/uptime/tracker") api/uptime/tracker 19 | p.api-description Tracker uptime history over the last ~24 hours. [hours] 20 | p.api-description Timestamp: 200320132025 [DDMMYYYYHHMM] 21 | 22 | p.api 23 | a(href="api/status") api/status 24 | p.api-description The service status. [1 for up, 0 down] 25 | 26 | p.api 27 | a(href="api/records") api/records 28 | p.api-description The uptime records for the components. [hours] 29 | 30 | h3 Bugs & Feedback 31 | p 32 | a(href="https://what.cd/user.php?id=160169") What.CD and What.CD IRC Network 33 | p 34 | a(href="https://github.com/dewey/WhatStatus") WhatStatus on GitHub 35 | p 36 | a(href="https://what.cd/forums.php?action=viewthread&threadid=136411") Laboratory Thread on What.CD 37 | 38 | h3 Powered by 39 | 40 | ul.about-logos 41 | li 42 | img(src="images/logos/nodejs.png") 43 | li 44 | img(src="images/logos/redis.png") 45 | 46 | a(href="https://twitter.com/#!/WhatcdStatus") 47 | img(src="images/twitter.png", alt="Follow us on Twitter!", class="follow-us") -------------------------------------------------------------------------------- /views/faq.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | block body-content 3 | div#content 4 | h2 5 | a(href="/faq") WhatStatus.info - Frequently Asked Questions 6 | 7 | div#twitter 8 | h3 9 | a(href="#twitter") Where can I get the latest status update if the site isn't accurate? 10 | p 11 | | Follow our Twitter account 12 | a(href="https://twitter.com/whatcdstatus") @whatcdstatus 13 | |. 14 | 15 | div#disabled 16 | h3 17 | a(href="#disabled") My account is disabled, is there anything I can do? 18 | p 19 | | If you are having any problems with your account you'll have to join #what.cd-disabled on the IRC network. This also includes other problems with your account, not just disabled accounts. 20 | 21 | div#irc 22 | h3 23 | a(href="#irc") How do I connect to the IRC network? 24 | p 25 | | You'll have to use an IRC client and connect to irc.what-network.net. The port is 6667 or 6697 if you are using SSL. 26 | 27 | div#mail 28 | h3 29 | a(href="#mail") My registration/activation mail isn't arriving 30 | p 31 | | You'll have to join #what.cd-disabled. 32 | 33 | div#invites 34 | h3 35 | a(href="#invites") How can I get invited to the site? 36 | p 37 | | Head over to 38 | a(href="http://www.whatinterviewprep.com/") whatinterviewprep.com 39 | | and read the instructions. 40 | 41 | div#irc-client 42 | h3 43 | a(href="#irc-client") How do I join IRC? The Java Applet / Mibbit isn't working. 44 | p 45 | | Use a real IRC client: 46 | h4 Mac 47 | ul.faq-list 48 | li Textual 49 | li Colloquy 50 | li irssi 51 | li weechat 52 | 53 | h4 Linux 54 | ul.faq-list 55 | li Hexchat 56 | li irssi 57 | li weechat 58 | 59 | h4 Windows 60 | ul.faq-list 61 | li Hexchat 62 | li irssi 63 | li mIRC 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /views/index.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block body-content 4 | script(type='text/javascript'). 5 | $.getJSON("/api/status", function(components) { 6 | for (var component in components) { 7 | if(components[component] == 1) { 8 | $("#status-" + component).html("Up"); 9 | $("#status-" + component).css("color", "#089a00"); 10 | $("#status-" + component + "-icon").attr('src', "images/up.png"); 11 | } else if (components[component] == 0) { 12 | $("#status-" + component).html("Down"); 13 | $("#status-" + component).css("color", "#ff1600"); 14 | $("#status-" + component + "-icon").attr('src', "images/down.png"); 15 | } else { 16 | $("#status-" + component).html("Updating..."); 17 | $("#status-" + component + "-icon").attr('src', "images/updating.png"); 18 | } 19 | } 20 | }); 21 | 22 | div#content 23 | div.logo 24 | img(src='#{logo_url}') 25 | div.status-dashboard 26 | table.service-table 27 | tr 28 | td.icon 29 | img(src, id='status-site-icon') 30 | td.service Site - what.cd 31 | td#status-site 32 | tr 33 | td.icon 34 | img(src, id='status-tracker-icon') 35 | td.service Tracker - tracker.what.cd 36 | td#status-tracker 37 | tr 38 | td.icon 39 | img(src, id='status-irc-icon') 40 | td.service IRC - irc.what-network.net 41 | td#status-irc 42 | div.disclaimer 43 | p This site is unofficial and is not affiliated with What.CD. 44 | div.twitter 45 | a.twitter-timeline(href='https://twitter.com/search?q=from%3Awhatcdstatus+OR+from%3Awhatcd+include%3Aretweets', data-widget-id='419095395902316544') Tweets by @whatcd and @WhatcdStatus 46 | script(type='text/javascript'). 47 | !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs"); 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WhatStatus 2 | ## Check health of IRC, Tracker and Site 3 | === 4 | 5 | WhatStatus is a simple status page for torrent sites. It's powered by [Espress](http://expressjs.com/) and Redis. 6 | 7 | ## Installation: 8 | === 9 | 10 | - Install [Node.JS](http://nodejs.org/) 11 | - Install [Redis](http://redis.io/) 12 | - Clone the WhatStatus repository 13 | - Navigate to the directory and run `npm install` which will install all the dependencies listed in `package.json` 14 | 15 | ## Running the site 16 | 17 | **Important:** 18 | If you are running your own instance don't forget to remove the analytics tracking code in views/layout.jade before you continue to the next steps. 19 | 20 | ### Recommended: pm2 21 | 22 | Install `pm2` with `npm install pm2 -g`. More information on: ttps://github.com/Unitech/PM2 23 | 24 | Type `pm2 list` to get a list of all the currently running processes, this will still be empty but it'll create the necessary directories for the next step. 25 | 26 | Create the pm2 config file called `whatstatus.info.json` and store it somewhere convenient like `~/.pm2/`. 27 | 28 | [{ 29 | "name" : "whatstatus.info", 30 | "script" : "WhatStatus.js", 31 | "cwd" : "/var/www/whatstatus.info/WhatStatus/", 32 | "env": { 33 | "NODE_ENV": "production" 34 | } 35 | }] 36 | 37 | Then just run `pm2 add ~/.pm2/whatstatus.info.json` and now the service should be started and should show up in `pm2 list`. 38 | 39 | ### Alternative: `screen`, `forever` etc. 40 | 41 | - Start the app in [production mode](http://www.hacksparrow.com/running-express-js-in-production-mode.html). 42 | - `NODE_ENV=production node WhatStatus.js` 43 | 44 | The app is now running on port 3000. To serve it on your regular port 443 or 80 you'll have to setup nginx like this: 45 | 46 | 47 | ### nginx configuration 48 | 49 | server { 50 | listen 443; 51 | server_name whatstatus.info; 52 | autoindex off; 53 | access_log /var/log/nginx/whatstatus.info.access_log main; 54 | error_log /var/log/nginx/whatstatus.info.error_log info; 55 | root /var/www/whatstatus.info/WhatStatus/; 56 | location / { 57 | proxy_set_header X-Real-IP $remote_addr; 58 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 59 | proxy_set_header Host $http_host; 60 | proxy_set_header X-NginX-Proxy true; 61 | proxy_pass http://127.0.0.1:3000/; 62 | proxy_redirect off; 63 | } 64 | } 65 | 66 | ## Further Information: 67 | === 68 | [WhatStatus.info/about](https://whatstatus.info/about) -------------------------------------------------------------------------------- /views/stats.jade: -------------------------------------------------------------------------------- 1 | extends layout 2 | block body-content 3 | script(type='text/javascript'). 4 | var trackerUptimeData = new Array(); 5 | 6 | $.getJSON("/api/uptime/tracker", function(uptimes) { 7 | for (var uptime in uptimes) { 8 | trackerUptimeData.push([uptime.substring(8,10) + ":" + uptime.substring(10), parseInt(uptimes[uptime])]); 9 | } 10 | }); 11 | 12 | google.load("visualization", "1", {packages:["corechart"]}); 13 | google.setOnLoadCallback(drawChartUptime); 14 | 15 | function drawChartUptime() { 16 | var data = new google.visualization.DataTable(); 17 | data.addColumn('string', 'Time'); 18 | data.addColumn('number', 'Uptime'); 19 | data.addRows(trackerUptimeData); 20 | 21 | // console.log(JSON.stringify(trackerUptimeData)); 22 | 23 | var options = { 24 | chartArea: {left:25,top:30, width:600}, 25 | colors: ['#ffd900'], 26 | legend: {position: 'none'}, 27 | interpolateNulls: true, 28 | hAxis: {baselineColor: '#757575', gridlines: {color: '#757575'}, textStyle: {color: '#757575', fontSize: 10}, showTextEvery: 2}, 29 | vAxis: {baselineColor: '#757575', gridlines: {color: '#757575'}, textStyle: {color: '#757575', fontSize: 10}}, 30 | backgroundColor: {fill: '#343434', stroke: '#757575'} 31 | }; 32 | 33 | var chart = new google.visualization.LineChart(document.getElementById('chart-tracker-uptime')); 34 | chart.draw(data, options); 35 | } 36 | 37 | script(type='text/javascript'). 38 | $.getJSON("/api/uptime", function(components) { 39 | for (var component in components) { 40 | $("#stats-uptime-" + component).html(components[component] + "h" + " (" + Math.floor(components[component]/24) +" days)"); 41 | } 42 | }); 43 | 44 | $.getJSON("/api/records", function(components) { 45 | for (var component in components) { 46 | $("#stats-uptimerecord-" + component).html(components[component] + "h" + " (" + Math.floor(components[component]/24) +" days)"); 47 | } 48 | }); 49 | div#content 50 | h2 51 | a(href="/") WhatStatus.info 52 | h3 Uptime 53 | ul.stats-list 54 | li Site - what.cd 55 | span#stats-uptime-site 56 | li Tracker - tracker.what.cd 57 | span#stats-uptime-tracker 58 | li IRC - irc.what-network.net 59 | span#stats-uptime-irc 60 | h3 Uptime Records 61 | ul.stats-list 62 | li Site - what.cd 63 | span#stats-uptimerecord-site 64 | li Tracker - tracker.what.cd 65 | span#stats-uptimerecord-tracker 66 | li IRC - irc.what-network.net 67 | span#stats-uptimerecord-irc 68 | h3 What.CD Tracker Uptime 69 | div#chart-tracker-uptime 70 | a(href="https://twitter.com/#!/WhatcdStatus") 71 | img(src="images/twitter.png", alt="Follow us on Twitter!", class="follow-us") -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | #content { 2 | margin-left: auto; 3 | margin-bottom: 0; 4 | margin-right: auto; 5 | margin-top: 50px; 6 | width: 600px; 7 | } 8 | #content-stats { 9 | margin-left: auto; 10 | margin-bottom: 0; 11 | margin-right: auto; 12 | margin-top: 50px; 13 | width: 500px; 14 | } 15 | .service-table { 16 | margin-top: 50px; 17 | width: 100%; 18 | } 19 | 20 | .stats-list { 21 | list-style-type: none; 22 | padding-left: 0; 23 | } 24 | 25 | ul span { 26 | float: right; 27 | } 28 | 29 | .down { 30 | font-weight: bold; 31 | color: #ff1600; 32 | } 33 | .maintenance { 34 | font-weight: bold; 35 | color: #ff1600; 36 | } 37 | .up { 38 | color: #089a00; 39 | font-weight: bold; 40 | } 41 | 42 | footer { 43 | text-align: center; 44 | font-size: 10px; 45 | margin-top: 50px; 46 | width: 600px; 47 | margin-right: auto; 48 | margin-left: auto; 49 | margin-bottom: 25px; 50 | } 51 | 52 | footer ul li { 53 | list-style:none; 54 | display: inline; 55 | } 56 | 57 | footer ul { 58 | padding: 0; 59 | } 60 | 61 | footer ul li:after { 62 | content:"·"; 63 | color:#666; 64 | } 65 | 66 | footer ul li:last-child:after { 67 | content:""; 68 | } 69 | 70 | footer ul li a { 71 | margin:0 8px; 72 | color:blue; 73 | } 74 | 75 | body { 76 | background: #343434; 77 | color: #757575; 78 | text-shadow: #111 0px 1px 0px; 79 | font-family: "Lucida Grande", Verdana, Arial, sans-serif; 80 | } 81 | 82 | a:link, a:visited { 83 | color: #999; 84 | text-decoration: none; 85 | } 86 | a:hover, a:visited:hover { 87 | color: #aaa; 88 | } 89 | .disclaimer { 90 | margin-top: 20px; 91 | text-align: center; 92 | font-size: 10px; 93 | } 94 | th { 95 | text-align: left; 96 | } 97 | .stats-table td { 98 | width: 500px; 99 | } 100 | h3 { 101 | padding-top: 0px; 102 | border-bottom-style: solid; 103 | border-bottom-width: 1px; 104 | padding-bottom: 3px; 105 | margin-bottom: 10px; 106 | margin-top: 20px; 107 | } 108 | 109 | .follow-us { 110 | position: absolute; 111 | top: 0; 112 | left: 0; 113 | border: 0; 114 | } 115 | 116 | .twitter{ 117 | width: 550px; 118 | margin: 0 auto 119 | } 120 | 121 | .status-dashboard { 122 | width: 550px; 123 | margin: 0 auto; 124 | } 125 | 126 | .logo { 127 | height: 140px; 128 | margin: 0 auto; 129 | width: 550px; 130 | text-align: center; 131 | } 132 | 133 | .logo img { 134 | height: 100%; 135 | } 136 | 137 | div #chart-tracker-uptime { 138 | text-shadow: none; 139 | } 140 | 141 | p.api-description { 142 | font-size: 12px; 143 | padding-left: 15px; 144 | } 145 | 146 | .about-logos { 147 | list-style: none; 148 | padding: 0; 149 | } 150 | 151 | .about-logos li { 152 | display: inline; 153 | } 154 | 155 | .about-logos li img { 156 | height: 50px; 157 | margin:0 8px; 158 | } 159 | 160 | h4 { 161 | margin-top: 5px; 162 | margin-bottom: 5px; 163 | } 164 | 165 | .faq-list { 166 | margin-top: 0px; 167 | } 168 | 169 | :target { 170 | color: yellow; 171 | } 172 | 173 | :target a:visited { 174 | color: yellow; 175 | } 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /WhatStatus.js: -------------------------------------------------------------------------------- 1 | /** 2 | * WhatStatus.info is a simple status page for torrent site. 3 | * @author dewey 4 | * https://github.com/dewey/WhatStatus 5 | */ 6 | 7 | var express = require('express'), 8 | http = require('http'), 9 | net = require('net'), 10 | path = require('path'), 11 | net = require('net'), 12 | redis = require('redis'), 13 | cronJob = require('cron').CronJob, 14 | date = require('date-format-lite'), 15 | request = require('request'); 16 | 17 | var app = express(); 18 | var db = redis.createClient(); 19 | 20 | // Catch connection errors if redis-server isn't running 21 | db.on("error", function(err) { 22 | console.log(err.toString()); 23 | console.log(" Make sure redis-server is started and listening for connections."); 24 | }); 25 | 26 | app.configure(function() { 27 | app.set('port', process.env.PORT || 3000); 28 | app.set('views', __dirname + '/views'); 29 | app.set('view engine', 'jade'); 30 | app.use(express.favicon('images/favicon.ico')); 31 | app.use(express.bodyParser()); 32 | app.use(express.methodOverride()); 33 | app.use(app.router); 34 | app.use(express.static(path.join(__dirname, 'public'))); 35 | }); 36 | 37 | app.configure('development', function() { 38 | app.use(express.errorHandler()); 39 | app.locals.pretty = true; 40 | app.use(express.logger('dev')); 41 | }); 42 | 43 | 44 | // If there's an outtage reset uptime record counter. 45 | function reset_uptime(component) { 46 | db.set('uptime:' + component, 0); 47 | } 48 | 49 | // Render the index page 50 | app.get('/', function(req, res) { 51 | res.render('index', { 52 | title: 'WhatStatus', 53 | logo_url: 'images/logos/logo.png' 54 | }); 55 | }) 56 | 57 | // Render the Stats page 58 | app.get('/stats', function(req, res) { 59 | res.render('stats', { 60 | title: 'WhatStatus' 61 | }); 62 | }) 63 | 64 | // Render the About page 65 | app.get('/about', function(req, res) { 66 | res.render('about', { 67 | title: 'WhatStatus' 68 | }); 69 | }) 70 | 71 | // Render the FAQ page 72 | app.get('/faq', function(req, res) { 73 | res.render('faq', { 74 | title: 'WhatStatus' 75 | }); 76 | }) 77 | 78 | // JSON Response for uptime values 79 | app.get('/api/uptime', function(req, res) { 80 | db.get('uptime:site', function(err, uptimeSite) { 81 | db.get('uptime:irc', function(err, uptimeIrc) { 82 | db.get('uptime:tracker', function(err, uptimeTracker) { 83 | res.json({ 84 | site: uptimeSite, 85 | irc: uptimeIrc, 86 | tracker: uptimeTracker 87 | }) 88 | }); 89 | }); 90 | }); 91 | }) 92 | 93 | // JSON Response for uptime records 94 | app.get('/api/records', function(req, res) { 95 | db.get('uptimerecord:site', function(err, uptimeRecordSite) { 96 | db.get('uptimerecord:irc', function(err, uptimeRecordIrc) { 97 | db.get('uptimerecord:tracker', function(err, uptimeRecordTracker) { 98 | res.json({ 99 | site: uptimeRecordSite, 100 | irc: uptimeRecordIrc, 101 | tracker: uptimeRecordTracker 102 | }) 103 | }); 104 | }); 105 | }); 106 | }) 107 | 108 | // JSON Response for current component status 109 | app.get('/api/status', function(req, res) { 110 | db.get('site-status', function(err, siteStatus) { 111 | db.get('irc-status', function(err, ircStatus) { 112 | db.get('tracker-status', function(err, trackerStatus) { 113 | res.json({ 114 | site: siteStatus, 115 | irc: ircStatus, 116 | tracker: trackerStatus 117 | }) 118 | }); 119 | }); 120 | }); 121 | }) 122 | 123 | // JSON Response for tracker uptime with time stamps 124 | app.get('/api/uptime/tracker', function(req, res) { 125 | db.lrange('trackeruptime', 0, -1, function(err, uptimesTrackerHistory) { 126 | var jsonObj = {}; 127 | for (var i = 0; i < uptimesTrackerHistory.length; i++) { 128 | var tokens = uptimesTrackerHistory[i].split(':') 129 | jsonObj[tokens[0]] = tokens[1] 130 | } 131 | res.json(jsonObj) 132 | }) 133 | }) 134 | 135 | // JSON Response for tracker uptime with time stamps [array] 136 | app.get('/api/2/uptime/tracker', function(req, res) { 137 | db.lrange('trackeruptime', 0, -1, function(err, uptimesTrackerHistory) { 138 | var jsonArray = []; 139 | for (var i = 0; i < uptimesTrackerHistory.length; i++) { 140 | var tokens = uptimesTrackerHistory[i].split(':') 141 | jsonArray.push({ 142 | timestamp: tokens[0], 143 | status: tokens[1] 144 | }); 145 | } 146 | res.json(jsonArray) 147 | }) 148 | }) 149 | 150 | // Check all components every minute 151 | var site_status_counter = 0 152 | var tracker_status_counter = 0 153 | var irc_status_counter = 0 154 | 155 | // Check Site Components (Cronjob running every minute) 156 | new cronJob('*/1 * * * *', function() { 157 | 158 | // Get Site Status 159 | request('https://what.cd', function(error, response) { 160 | if (!error && response.statusCode == 200) { 161 | db.set('site-status', '1') 162 | site_status_counter = 0; 163 | } else { 164 | site_status_counter++; 165 | console.log("[Check-Site] Status counter: " + site_status_counter); 166 | if (site_status_counter > 2) { 167 | db.set('site-status', '0') 168 | reset_uptime('site'); 169 | console.log("[Check-Site] Site down"); 170 | } 171 | } 172 | }); 173 | 174 | // Get Tracker Status 175 | request('http://tracker.what.cd:34000', function(error, response, body) { 176 | if(!error && body.length > 0 && body.indexOf('is down') == -1) { 177 | db.set('tracker-status', '1') 178 | tracker_status_counter = 0; 179 | } else { 180 | tracker_status_counter++; 181 | console.log("[Check-Tracker] Status counter: " + tracker_status_counter); 182 | if (tracker_status_counter > 2) { 183 | db.set('tracker-status', '0') 184 | reset_uptime('tracker'); 185 | console.log("[Check-Tracker] Tracker down"); 186 | } 187 | } 188 | }); 189 | 190 | // Get IRC Status 191 | var client = net.connect(6667, 'irc.what-network.net', function() { 192 | db.set('irc-status', '1') 193 | irc_status_counter = 0; 194 | }); 195 | 196 | // Socket connection closed 197 | client.on('end', function() { 198 | 199 | }); 200 | 201 | // Error on connecting to target host 202 | client.on('error', function() { 203 | irc_status_counter++; 204 | console.log("[Check-IRC] Status counter: " + irc_status_counter); 205 | if (irc_status_counter > 2) { 206 | db.set('irc-status', '0') 207 | reset_uptime('irc'); 208 | console.log("[Check-IRC] IRC down"); 209 | } 210 | 211 | client.end(); 212 | }); 213 | 214 | client.on('timeout', function() { 215 | console.log("[Check-IRC] Timeout"); 216 | client.end(); 217 | }); 218 | }, null, true, "Europe/Vienna"); 219 | 220 | /* 221 | Statistics (hourly) 222 | 223 | This cronjob is incrementing the uptime counters for the various monitored components 224 | and updating the uptime records if the current uptime > the old record. 225 | */ 226 | 227 | // Initialize Redis Keys to prevent "null" values 228 | function initializeRedis(component) { 229 | db.exists(component, function(err, reply) { 230 | if (reply != 1) { 231 | db.set(component, 0); 232 | } 233 | }); 234 | } 235 | 236 | initializeRedis('uptimerecord:site') 237 | initializeRedis('uptimerecord:tracker') 238 | initializeRedis('uptimerecord:irc') 239 | initializeRedis('uptime:site') 240 | initializeRedis('uptime:tracker') 241 | initializeRedis('uptime:irc') 242 | 243 | new cronJob('0 * * * *', function() { 244 | console.log("[Stats] Cronjob started") 245 | 246 | // Hourly Increment Uptime if Component is Up 247 | db.get('site-status', function(err, siteStatus) { 248 | if (siteStatus != 0) { 249 | db.incr('uptime:site'); 250 | } 251 | 252 | // Update Site Uptime Record 253 | db.get('uptime:site', function(err, uptimeSite) { 254 | db.get('uptimerecord:site', function(err, uptimerecordSite) { 255 | if (parseInt(uptimeSite) > parseInt(uptimerecordSite)) { 256 | console.log("[Stats-Site] Site Records updated [" + uptimerecordSite + " to " + uptimeSite + "]"); 257 | db.set('uptimerecord:site', uptimeSite); 258 | } 259 | }); 260 | }); 261 | }); 262 | 263 | // Hourly Increment Uptime if Component is Up 264 | db.get('tracker-status', function(err, trackerStatus) { 265 | if (trackerStatus != 0) { 266 | db.incr('uptime:tracker'); 267 | } 268 | // Update Tracker Uptime Record 269 | db.get('uptime:tracker', function(err, uptimeTracker) { 270 | db.get('uptimerecord:tracker', function(err, uptimerecordTracker) { 271 | if (parseInt(uptimeTracker) > parseInt(uptimerecordTracker)) { 272 | console.log("[Stats-Tracker] Tracker Records updated [" + uptimerecordTracker + " to " + uptimeTracker + "]"); 273 | db.set('uptimerecord:tracker', uptimeTracker); 274 | } 275 | }); 276 | }); 277 | 278 | /* 279 | Building string for Google Charts used to graph tracker uptime. 280 | String written to redis: DDMMYYYYhhmm|int where int is the current tracker uptime. 281 | */ 282 | db.get('uptime:tracker', function(err, uptimeTracker) { 283 | // Initialize new timestamp 284 | var now = new Date().format('DDMMYYYYhhmm'); 285 | db.llen('trackeruptime', function(err, uptimesTrackerCount) { 286 | // Add new timestamp to redis, if there are more than 24 objects pop the oldest value. 287 | if (uptimesTrackerCount <= 24) { 288 | // Pushing Strings to Redis (I'm sorry!) 289 | db.rpush('trackeruptime', now + ":" + uptimeTracker); 290 | } else { 291 | db.lpop('trackeruptime'); 292 | } 293 | }); 294 | }); 295 | }); 296 | 297 | // Hourly Increment Uptime if Component is Up 298 | db.get('irc-status', function(err, ircStatus) { 299 | if (ircStatus != 0) { 300 | db.incr('uptime:irc'); 301 | } 302 | // Update IRC Uptime Record 303 | db.get('uptime:irc', function(err, uptimeIrc) { 304 | db.get('uptimerecord:irc', function(err, uptimerecordIrc) { 305 | if (parseInt(uptimeIrc) > parseInt(uptimerecordIrc)) { 306 | console.log("[Stats-Irc] Irc Records updated [" + uptimerecordIrc + " to " + uptimeIrc + "]") 307 | db.set('uptimerecord:irc', uptimeIrc); 308 | } 309 | }); 310 | }); 311 | }); 312 | 313 | }, null, true, "Europe/Vienna"); 314 | 315 | http.createServer(app).listen(app.get('port'), function() { 316 | console.log("WhatStatus server listening on port: " + app.get('port')); 317 | }); --------------------------------------------------------------------------------