Search code examples
javascriptwebsocketpromiseautobahn

Handling multiple websocket subscriptions, but only one connection object, in a single Javascript function


Note: I'm using Autobahn.js for the client-side WAMP implementation, and when.js for promises.

I'm trying to create re-usable code so that only one websocket 'session', or connection exists, and whenever a dev wants to subscribe to a topic using autobahn, they can just use the current connection object to do so if it already exists; else a new one is created.

My issue is that, if the connection already exists, I have to use a setTimeout() to wait for a second to make sure it's actually connected, and then duplicate all the subscription code - I don't like this at all.

Here's my current code:

(function() {
    var connection = null;

    subscribeTo('subject', __userId, __token, function(onconnect) {
        console.log('Yay, connected');
    });

    function subscribeTo(subject, userId, token, onConnect, onDisconnect) { 
        if (connection === null)
        {   
            connection = new ab.Session('ws://localhost:8080', function(onopen) {

                connection.subscribe(JSON.stringify({subject: subject, userId: userId, token: token}), function(subscription, data) {
                    data = $.parseJSON(data);

                    // Do something with the data ...
                });

                if (typeof onConnect === 'function') { 
                    onConnect(); 
                }

            }, function(onclose) {
                if (typeof onDisconnect === 'function') { 
                    onDisconnect(); 
                }
            }, { 'skipSubprotocolCheck': true });
        }
    }
})();

Great. Now the issue is, what if I have another subscribeTo() straight after the previous one? Connection won't be null any more, but it also won't be connected. So the following is what I have to do:

// subscribeTo() multiple times at the top ...

subscribeTo('subject', __userId, __token, function(onconnect) {
    console.log('Yay, connected');
});

subscribeTo('anothersubject', __userId, __token, function(onconnect) {
    console.log('Yay, connected');
});

// The first one works, the second one requires a setTimeout() for the connection

// if connection is NOT null...
} else {
    setTimeout(function() {
        connection.subscribe(topic... etc...) // Really!?
    }, 1000);
}

Remove the setTimeout() and you'll get an error saying that "Autbahn is not connected".

Is there a better way to have a single, re-usable connection, without code-duplication, or am I doomed to create a new connection for each subscription because of the promises (perhaps I can use promises to my advantage here, although I haven't used them before this)?


Solution

  • This is all way too complex, unneeded and wrong. You want to do your subscribes in response to a session being created:

    var session = null;
    
    function start() {
       // turn on WAMP debug output
       //ab.debug(true, false, false);
    
       // use jQuery deferreds instead of bundle whenjs
       //ab.Deferred = $.Deferred;
    
       // Connect to WAMP server ..
       //
       ab.launch(
          // WAMP app configuration
          {
             // WAMP URL
             wsuri: "ws://localhost:9000/ws",
             // authentication info
             appkey: null, // authenticate as anonymous
             appsecret: null,
             appextra: null,
             // additional session configuration
             sessionConfig: {maxRetries: 10, sessionIdent: "My App"}
          },
          // session open handler
          function (newSession) {
             session = newSession;
             main();
          },
          // session close handler
          function (code, reason, detail) {
             session = null;
          }
       );
    }
    
    function main() {
       session.subscribe("http://myapp.com/mytopic1", function(topic, event) {});
       session.subscribe("http://myapp.com/mytopic2", function(topic, event) {});
       session.subscribe("http://myapp.com/mytopic3", function(topic, event) {});
    }
    
    start();
    

    The ab.launch helper will manage automatic reconnects for you (and also do WAMP-CRA authentication if required). init() is then automatically called again when a reconnect happens. Using raw Session object is not recommended (unless you know what you are doing).

    Also: topics must be URIs from the http or https scheme. Using serialized objects (JSON) is not allowed.