Socket.io 1.4 to 1.7.2 temporary fix for #2405: Server socket id doesn’t match client’s socket id

If you’re affected by the major change outlined by this reported issue here’s a temporary fix you may want to try to get things working again without having to change all of your own code:

find . -name "socket.io.js" -exec sed -i -e 's/socket\.id \= self\.engine\.id;/socket\.id \= socket\.nsp \+ "\#" \+ self\.engine\.id;/' {} \;
find . -name "socket.io.js" -exec sed -i -e 's/this\.nsps\[nsp\]\.id \= this\.engine\.id;/this\.nsps\[nsp\]\.id \= nsp \+ "\#" \+ this\.engine\.id;/' {} \;
find . -name "socket.io.js.map" -exec sed -i -e 's/socket\.id \= self\.engine\.id;/socket\.id \= socket\.nsp \+ "\#" \+ self\.engine\.id;/' {} \;
find . -name "socket.io.js.map" -exec sed -i -e 's/this\.nsps\[nsp\]\.id \= this\.engine\.id;/this\.nsps\[nsp\]\.id \= nsp \+ "\#" \+ this\.engine\.id;/' {} \;
find . -name "socket.io.slim.js.map" -exec sed -i -e 's/socket\.id \= self\.engine\.id;/socket\.id \= socket\.nsp \+ "\#" \+ self\.engine\.id;/' {} \;
find . -name "socket.io.slim.js.map" -exec sed -i -e 's/this\.nsps\[nsp\]\.id \= this\.engine\.id;/this\.nsps\[nsp\]\.id \= nsp \+ "\#" \+ this\.engine\.id;/' {} \;
find . -name "socket.io.min.js" -exec sed -i -e 's/n\.id\=o\.engine\.id/n\.id\=n\.nsp\+"\#"\+o\.engine\.id/' {} \;
find . -name "socket.io.min.js" -exec sed -i -e 's/this\.nsps\[t\]\.id\=this\.engine\.id/this\.nsps\[t\]\.id\=t\+"\#"\+this\.engine\.id/' {} \;
find . -name "socket.io.slim.min.js" -exec sed -i -e 's/n\.id\=o\.engine\.id/n\.id\=n\.nsp\+"\#"\+o\.engine\.id/' {} \;
find . -name "socket.io.slim.min.js" -exec sed -i -e 's/this\.nsps\[t\]\.id\=this\.engine\.id/this\.nsps\[t\]\.id\=t\+"\#"\+this\.engine\.id/' {} \;
find . -name "manager.js" -exec sed -i -e 's/socket\.id \= self\.engine\.id;/socket\.id \= socket\.nsp \+ "\#" \+ self\.engine\.id;/' {} \;

Running this as a bash script in the root folder of your projects that depend on socket.io-client will replace all instances in the socket.io-client code to use the naming convention prior to v1.4 (and thus maintain consistency across client and server): the namespace followed by # and then the engine id.

If you run the bash script and want to undo the above changes, you’ll have to reverse the sed regular expressions and rerun the script.

*     *     *

You may enjoy playing a game at GameSlush.com because it also uses socket.io.

Socket.io 1.3.2: client events received in browsers prior to all JS being loaded

FireFox experiences a race condition between the loading of code in scripts and receiving socket.io events if a socket establishes a connection concurrently with the loading of scripts.  If a socket.io client in FireFox connects to the socket.io server in a script, but there are socket event handlers yet to be loaded (or general JS yet to be loaded), events from the socket.io server may be received and unhandled properly on the client side due to “missing” code.  IE and Chrome tend to finish loading all JavaScript prior to handling the first socket.io event from the server, so the issue is not evident outside of FireFox.

Not documented on socket.io’s page or its GitHub page, socket.io has an “autoConnect” option on the client side initialization that helps solve this problem.  Here’s an effective connection paradigm to follow when using socket.io clients on browsers:

First, create the io Manager and initialize the socket with autoConnect = false, that way we don’t connect to the socket.io server until we set up all of our event handlers.

var socket = io('http://server_host', { autoConnect: false });</pre>
Second, set up our event handlers.
<pre class="js">socket.on('foo', function() {
  console.log('bar');
}

Finally, after all of our JS, images, frames, etc. are loaded and we are completely ready to handle all incoming socket events, follow through with connecting to the server.

window.onload = function() {
  socket.connect();
}

Socket.io 1.2.0: Handling global authorization events when client connects to a custom namespace

The documentation on socket.io’s page and its GitHub page are inconsistent (namely due to the latter being out of date, but contains information not covered by the former). A problem arises when using global authorization middleware on the server, having a client trying to connect to a custom namespace, and having the server deny access to the connecting client by passing an error to next() in the middleware.

Sample server authorization middleware code that denies access globally to all incoming connections:

io.use(function(socket, next) {
  next(new Error('not authorized'));
});

Sample client connecting code with error handler:

var socket = require('socket.io-client')('http://localhost/customnamespace');

socket.on('error', function(err) {
  console.log(err); // 'not authorized' not output, 
                    // since this is a '/customnamespace' event handler
});

The client needs to handle both the events coming from the global namespace and the custom namespace, otherwise the socket connection seemingly hangs on the client side as it receives no feedback from the custom namespace event handlers. None of the socket.io documentation seems to cover this shortcoming.

You can simply get any namespace socket from the socket Manager by calling Manager.socket([namespace]). To get the socket Manager from any socket, simply reference the ‘io’ property of the socket object. From there we would use ‘/’ to get the global namespace socket.

Here’s the proposed workaround that continues the sample client code above:

var socket = require('socket.io-client')('http://localhost/customnamespace');
var manager = socket.io;
var socketGlobalNs = manager.socket('/');

socket.on('error', function(err) {
  console.log(err); // 'not authorized' not output, 
});

socketGlobalNs.on('error', function(err) {
  console.log(err); // This will output 'not authorized'
});