Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🗿 Added a real-time Dashboard with Socket.io #23

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ lib-cov
*.pid
*.gz
*.swp
*.css

pids
logs
Expand Down
78 changes: 72 additions & 6 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ var path = require('path');
var mongoose = require('mongoose');
var passport = require('passport');
var expressValidator = require('express-validator');

var http = require('http');
var io = require('socket.io');
var app = express()
, server = require('http').createServer(app)
, io = io.listen(server);

/**
* Load controllers.
Expand All @@ -20,6 +24,7 @@ var homeController = require('./controllers/home');
var userController = require('./controllers/user');
var apiController = require('./controllers/api');
var contactController = require('./controllers/contact');
var dashboardController = require('./controllers/dashboard');

/**
* API keys + Passport configuration.
Expand All @@ -37,11 +42,15 @@ mongoose.connection.on('error', function() {
console.log('✗ MongoDB Connection Error. Please make sure MongoDB is running.'.red);
});

var app = express();

/**
* Express configuration.
*/

var hour = 3600000; //milliseconds
var day = (hour * 24);
var week = (day * 7);
var month = (day * 30);

app.locals.cacheBuster = Date.now();
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
Expand Down Expand Up @@ -69,17 +78,26 @@ app.use(function(req, res, next) {
app.use(flash());
app.use(less({ src: __dirname + '/public', compress: true }));
app.use(app.router);
app.use(express.static( path.join(__dirname, 'public'), { maxAge: 864000000 } ));
app.use(express.static( path.join(__dirname, 'public'), { maxAge: week } ));
app.use(function(req, res) {
res.render('404', { status: 404 });
});
app.use(express.errorHandler());

/**
* Start Server
*/

server.listen(app.get('port'), function(){
console.log("✔ Express server listening on port %d in %s mode", app.get('port'), app.settings.env);
});

/**
* Application routes.
*/

app.get('/', homeController.index);
app.get('/dashboard', dashboardController.getDashboard);
app.get('/login', userController.getLogin);
app.post('/login', userController.postLogin);
app.get('/logout', userController.logout);
Expand Down Expand Up @@ -118,6 +136,54 @@ app.get('/auth/foursquare/callback', passport.authorize('foursquare', { failureR
app.get('/auth/tumblr', passport.authorize('tumblr'));
app.get('/auth/tumblr/callback', passport.authorize('tumblr', { failureRedirect: '/api' }), function(req, res) { res.redirect('/api/tumblr'); });

app.listen(app.get('port'), function() {
console.log('✔ Express server listening on port ' + app.get('port'));
/**
* Emit Pageviews on Socket.io
*/

io.configure('production', function(){
io.enable('browser client minification'); // send minified client
io.enable('browser client etag'); // apply etag caching logic based on version number
io.enable('browser client gzip'); // gzip the file
io.set('log level', 1); // reduce logging
io.set("polling duration", 10); // increase polling frequency
io.set('transports', [ // Manage transports
'websocket'
, 'htmlfile'
, 'xhr-polling'
, 'jsonp-polling'
]);
io.set('authorization', function (handshakeData, callback) {
if (handshakeData.xdomain) {
callback('Cross-domain connections are not allowed');
} else {
callback(null, true);
}
});
});

io.configure('development', function(){
io.set('log level', 1); // reduce logging
io.set('transports', [
'websocket' // Let's just use websockets for development
]);
io.set('authorization', function (handshakeData, callback) {
if (handshakeData.xdomain) {
callback('Cross-domain connections are not allowed');
} else {
callback(null, true);
}
});
});

io.sockets.on('connection', function (socket) {
socket.on('message', function (message) {
console.log("Got message: " + message);
var ip = socket.handshake.address.address;
var url = message;
io.sockets.emit('pageview', { 'connections': Object.keys(io.connected).length, 'ip': ip, 'url': url, 'xdomain': socket.handshake.xdomain, 'timestamp': new Date()});
});
socket.on('disconnect', function () {
console.log("Socket disconnected");
io.sockets.emit('pageview', { 'connections': Object.keys(io.connected).length});
});
});
10 changes: 10 additions & 0 deletions controllers/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* GET /
* Home page.
*/

exports.getDashboard = function(req, res) {
res.render('dashboard', {
title: 'Dashboard'
});
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"twit": "~1.1.12",
"underscore": "~1.5.2",
"paypal-rest-sdk": "~0.6.4",
"connect-mongo": "~0.4.0"
"connect-mongo": "~0.4.0",
"socket.io": "0.9.16"
}
}
21 changes: 21 additions & 0 deletions public/css/styles.less
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ body {
border-top: 1px solid @navbar-default-border;
}

// Dashboard
// -------------------------

#connections {
text-align: center;
p {
font-size: 96px;
line-height: 96px;
color: #ff6600;
text-shadow: 1px 1px 1px #222;
}
}

#visits thead tr td {
font-weight: bold;
}

#pageViews thead tr td {
font-weight: bold;
}

// Navbar
// -------------------------

Expand Down
49 changes: 49 additions & 0 deletions views/dashboard.jade
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
extends layout

block content

.row
.well.col-md-2#connections
h3 Right Now
p 0
h5 active visitors
.col-md-10
legend Real Time Activity
table#visits.table.table-bordered.table-striped.table-condensed
thead
tr
td URL
td IP
td Timestamp
tbody
legend Page Views
table#pageViews.table.table-bordered.table-striped.table-condensed
thead
tr
td URL
td Page Views
tbody

script.
var pages = {};
var lastPageId = 0;
socket.on('connect', function () {
console.log('Socket connected');
socket.on('pageview', function (msg) {
console.log('Connections: ' + msg.connections);
$('#connections > p').html(msg.connections - 1); // -1 since we don't count our own dashboard connection
if (msg.url) {
if ($('#visits tr').length > 10) {
$('#visits tr:last').remove();
}
$('#visits tbody').prepend('<tr><td>' + msg.url + '</td><td>' + msg.ip + '</td><td>' + msg.timestamp + '</td></tr>');
if (pages[msg.url]) {
pages[msg.url].views = pages[msg.url].views + 1;
$('#page' + pages[msg.url].pageId).html(pages[msg.url].views);
} else {
pages[msg.url] = {views: 1, pageId: ++lastPageId};
$('#pageViews tbody').append('<tr><td>' + msg.url + '</td><td id="page' + lastPageId + '">1</td></tr>');
}
}
});
});
10 changes: 10 additions & 0 deletions views/layout.jade
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ html
script(src='/js/lib/jquery.js?v=#{cacheBuster}')
script(src='/js/lib/bootstrap.js?v=#{cacheBuster}')
script(src='/js/main.js?v=#{cacheBuster}')
script(src='/socket.io/socket.io.js?v=#{cacheBuster}')
//- For real-time monitoring
script.
var socket = io.connect();
socket.on('connect', function () {
socket.send(window.location.href);
});
window.onhashchange = function () {
socket.send(window.location.href);
}
body
#wrap
include partials/navigation
Expand Down
2 changes: 2 additions & 0 deletions views/partials/navigation.jade
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
a(href='/api') API Browser
li(class=title=='Contact'?'active':undefined)
a(href='/contact') Contact
li(class=title=='Dashboard'?'active':undefined)
a(href='/dashboard') Dashboard
ul.nav.navbar-nav.navbar-right
if !user
li(class=title=='Login'?'active':undefined)
Expand Down