btford / btford/angular-socket-io

Require a method to update inner ioSocket object for connect / disconnect

Open
#86 16 comments 0 reactions 0 assignees View on GitHub
Dominant language
JavaScript
Stars
1.5k
Forks
225
PR merge metrics
No merged PRs in 30d

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:

``` javascript
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...

``` javascript
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](https://docs.angularjs.org/guide/providers#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?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.