Description
In my app, I have both traditional http and websockets -- both are protected by JSON web token authentication. When a user logs in (i.e. post to http endpoint), a token is returned, and then the client will attempt to connect to the websocket endpoint with the token. The connection is rejected if the token isn't valid.
When a user logs out, the websocket is disconnected. I don't want to leave that channel open anymore b/c the user is no longer authenticated. Likewise, I don't want to re-use that same websocket if a new user logs in, b/c the authentication token will be different (and not valid for the new user).
What I'm left with is something like this:
angular.module('app.security')
.factory('Socket', ['socketFactory', '$rootScope', function (socketFactory, $rootScope) {
var socket, token = /* get token */
function connect(token) {
socket = io.connect('', { query: 'token=' + token, forceNew: true });
socket.on('connect', function () { /* etc. */ });
// other event handling
}
// connect if we have a token
if (token) { connect(token); }
$rootScope.on('login', function ( ) {
token = /* get token */
connect(token);
});
$rootScope.on('logout', function () { socket.disconnect(); })
return socketFactory({ ioSocket: socket });
}]);
..and this is an example of how it is in injected into a controller to be used...
angular.module('app.something')
.controller('FooCtrl', ['Socket', '$scope', function (Socket, $scope) {
Socket.forward('time:request', $scope);
$scope.$on('socket:time:response', function (evt, data) {
console.log('the current time is ', data);
});
Socket.emit('time:request');
}]);
On login, the websocket is connected. On logout it is disconnected, and at the end, it is returning the socketFactory
wrapper.
The problem here is that socketFactory.$get
is only ever called once in the provider, which means that the very first time Socket
is injected into a controller it is valid and connected. But if a user logs out and logs in again, angular re-injects the same instance into a controller, and the internal ioSocket
has since been disconnected and is no longer good. (note the use of socket.io forceNew
option which abandons the socket wholesale and initiates a brand new connection).
What is needed is something like the angular service recipe pattern which news up the object each time, so we don't re-use the same instance of the wrapper...either that or else an API exposed on socketFactory itself that allows one to replace the inner ioSocket
reference.
Any ideas on the best way to accomplish this?