Last active
August 29, 2015 14:02
-
-
Save ben-bradley/651de8ca850c2ec4506c to your computer and use it in GitHub Desktop.
Making Express, Socket.IO, and Angular play nicely together
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// File: client/scripts/controllers/main.js | |
// With this, you can use 'socket' very nicely (IMHO) | |
'use strict'; | |
angular.module('theApp') | |
.controller('MainCtrl', function ($scope, socket) { | |
$scope.now = 'loading...'; | |
var ioTime = socket.connect('/io/time'); | |
ioTime.on('time', function(now) { | |
$scope.now = now; | |
}); | |
var ioPing = socket.connect('/io/ping'); | |
ioPing.on('pong', function(data) { | |
console.log(data); | |
}); | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// File: server/server.js | |
// This is the Node file to fire up an Socket.IO enabled Express server | |
// Code your io stuff as normal | |
var express = require('express'), | |
session = require('express-session'), | |
bodyParser = require('body-parser'), | |
cookieParser = require('cookie-parser'), | |
http = require('http'), | |
socketio = require('socket.io'); | |
var app = express(); | |
var server = http.createServer(app); | |
var io = socketio.listen(server); | |
var sessionStore = new session.MemoryStore(); | |
app.use(express.static(__dirname+'/../client')); // serve the client | |
app.use(bodyParser()); | |
app.use(cookieParser()); | |
app.use(session({ | |
store: sessionStore, | |
secret: ''+new Date().getTime() | |
})); | |
// this is the authentication middleware that links the | |
// Express session with the socket. You need to manage | |
// the session within the authentication stack of the | |
// Express app: | |
/* | |
app.get('/signout', function(req, res) { | |
... | |
req.session.destroy(); | |
... | |
}) | |
*/ | |
io.use(function(socket, next) { | |
var cookie = socket.handshake.headers.cookie, | |
sid = cookie.match(/connect.sid=s%3A([^\.]+)\.*/); | |
if (sid) | |
sid = sid[1]; | |
else | |
return next('no session', false); | |
sessionStore.get(sid, function(err, session) { | |
if (!session) | |
return next('no session', false); | |
// check every 5 seconds to see if the express session is active | |
var checkSession = setInterval(function() { | |
sessionStore.get(sid, function(err, session) { | |
if (!session) { | |
socket.disconnect(true); | |
clearInterval(checkSession); | |
} | |
}); | |
}, 5000); | |
next(); | |
}); | |
}); | |
io.of('/io/ping').on('connection', function(socket) { | |
setInterval(function() { // emit a pong every 1 sec | |
socket.emit('pong', { pong: new Date() }); | |
}, 1000); | |
}); | |
io.of('/io/time').on('connection', function(socket) { | |
setInterval(function() { // emit a new Date() every .5 sec | |
socket.emit('time', new Date()); | |
}, 500); | |
}); | |
server.listen(8000); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// File: client/scripts/services/socket.js | |
// Here's the good stuff! =) | |
// Heavily inspired by another developer's work whom I've lost track of | |
'use strict'; | |
angular.module('theApp') | |
.service('socket', function($rootScope) { | |
this.connect = function(namespace) { | |
console.log('connecting: ', namespace) | |
var _socket = io.connect(namespace); | |
_socket._on = _socket.on; | |
_socket._emit = _socket.emit; | |
_socket.on = function(eventName, callback) { | |
_socket._on(eventName, function() { | |
var args = arguments; | |
$rootScope.$apply(function() { | |
callback.apply(_socket, args); | |
}); | |
}); | |
}; | |
_socket.emit = function(eventName, data, callback) { | |
_socket._emit(eventName, data, function() { | |
var args = arguments; | |
$rootScope.$apply(function() { | |
if (callback) { | |
callback.apply(_socket, args); | |
} | |
}); | |
}); | |
}; | |
return _socket; | |
}; | |
}) |
I'm struggling with authentication on the socket, if anyone has any ideas for nice, clean solutions, please let me know.
I think I've sorted out the authentication sync between Express & Socket.IO in server.js
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is an example of how I've been able to get Socket.IO and Angular to play nicely with each other. I struggled with getting the $scope to update cleanly and found some example code (but lost the URL for credit, sorry!) that got me pointed in the right direction. I hacked it up to allow for connecting to specific namespaces and this is the result.
My expertise with Angular is limited so it's entirely possible that I've inadvertently created some unintended consequences. If you can identify any, please let me know.