Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton Websockets object with different callback handlers

I have a JavaScript Websockets implementation where I would like to use a singleton model that uses one Websocket connection for multiple calls to the server but with different callback event handlers. I have the implementation working just fine but have noticed some strange behaviors with messages being directed to the wrong callback handler. Here is some code:

Connection.js file

var connection = function(){
    var _socket = null;
    return {
        socket : function(){
            if (_socket == null){
                _socket = new WebSocket("ws://localhost:8081/index.ashx");
                _socket.onclose = function(evt){alert('Closed');}
                _socket.extraParameter = null;
            }
            return _socket;
        },
        send : function(data, callback){
            var localSocket = connection.socket();
            localSocket.extraParameter = new Date().toString();
            localSocket.onmessage = callback;
            localSocket.originalDataSent = data;
            localSocket.send(data);
        }
    }
}();

App.js file

var App = function(){
    return {
        cpuUtilization : function(evt){
            var localSocket = this;
            var dateTimeOfRequest = localSocket.extraParameter;
            var originalDataSent = localSocket.originalDataSent
            var jsonData = $.parseJSON(evt.data);
            if ($.parseJSON(originalDataSent).type == "cpu"){
                $("#dateTimeContainer").html();
                $("#cpuContainer").html(jsonData.value);
            }
        }
    }
}();

Third Party Signal.js file

var Signal = function(){
    return {
        handlerProcess : function(evt){
            //  Does some third party stuff...
        }
    }
}();

usage

connection.send("{type:'process'}", Signal.handlerProcess);
connection.send("{type:'cpu'}", App.cpuUtilization);
connection.send("{type:'memory'}", Signal.handlerMemory);
connection.send("{type:'harddrive'}", Signal.handlerHardDrive);

Now where I think I am see the problem is when multiple request are made through the same websocket and the message returns. Since this is asynchronous, I have no way of tieing the request to the event callback. My solution uses the options in the handler for reference, but depending on the time it takes for the websocket request to run, the wrong callback handler is being called and process fails. I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.

Is there a way to pass a reference or additional parameters along with the evt parameter? Maybe wrapping this somehow?

like image 200
WalkSolutions Avatar asked Jun 20 '12 20:06

WalkSolutions


1 Answers

I think it is failing because I am accessing properties from the websocket instance that may be changing between calls.

Yes.

Since this is asynchronous, I have no way of tieing the request to the event callback.

No. You can create a closure for the callback function instead of calling using callback directly:

... send: function(data, callback){
    var localSocket = connection.socket();
    var extraParameter = new Date().toString();
    localSocket.onmessage = function(evt) {
        callback(evt.data, /* original- */ data, extraParameter);
    };
    localSocket.send(data);
}

But still, you have a changing onmessage callback handler. That means, an event may be sent to a handler that does not deserve it. Having an asynchronous system, you will need to add a piece of information to the server resonse that indicates which process the data belongs to. The one universal message handler then could resolve that and call the right callback.

like image 69
Bergi Avatar answered Sep 29 '22 11:09

Bergi