How do I use Twisted (or Autobahn) to connect to a socket.io server?
Question: I am trying to figure out a way to connect to a socket.io (node.js) server
with a Python Twisted client. The server is a chat server which I didn't
write, so I have no control over it. I tried a few things, mainly TCP
connections, but I figured that I'll need to use the Websockets interface to
communicate successfully.

Just to test out, I used the code from socket.io tutorial,
<http://socket.io/#how-to-use> for the server.

    
    
    var app = require('http').createServer(handler)
      , io = require('socket.io').listen(app)
      , fs = require('fs')
    
    app.listen(8080);
    
    function handler (req, res) {
      fs.readFile(__dirname + '/index.html',
      function (err, data) {
        if (err) {
          res.writeHead(500);
          return res.end('Error loading index.html');
        }
    
        res.writeHead(200);
        res.end(data);
      });
    }
    
    io.sockets.on('connection', function (socket) {
      socket.emit('news', { hello: 'world' });
      socket.on('my other event', function (data) {
        console.log(data);
      });
    });
    

For the client, I used the example code from this tutorial
<http://autobahn.ws/python/tutorials/echo/>: (I know the callbacks don't
match, but I just want to see if it will connect first, which it doesn't).

    
    
    from twisted.internet import reactor
    from autobahn.websocket import WebSocketClientFactory, \
                                   WebSocketClientProtocol, \
                                   connectWS
    
    
    class EchoClientProtocol(WebSocketClientProtocol):
    
       def sendHello(self):
          self.sendMessage("Hello, world!")
    
       def onOpen(self):
          self.sendHello()
    
       def onMessage(self, msg, binary):
          print "Got echo: " + msg
          reactor.callLater(1, self.sendHello)
    
    
    if __name__ == '__main__':
    
       factory = WebSocketClientFactory("ws://localhost:8080", debug = False)
       factory.protocol = EchoClientProtocol
       connectWS(factory)
       reactor.run()
    

This is just to see if it will connect. The problem is, the socket.io server
says: `destroying non-socket.io upgrade`, so I'm guessing the client isn't
sending a proper UPGRADE header, but I'm not sure.

Am I missing something, or are Websocket implementations different across
libraries, and that I'll need to do some digging in order for them to
communicate? I had a feeling it was supposed to be quite easy. My question is,
what do I change on the client so it will connect (complete handshake
successfully and start accepting/sending frames)?

Finally, I would like to use Twisted, but I'm open to other suggestions. I
understand the most straight forward will be making a socket.io client, but I
only know Python.

EDIT:

    
    
    After turning on logging, it shows this:
    2013-11-14 22:11:29-0800 [-] Starting factory <autobahn.websocket.WebSocketClientFactory instance at 0xb6812080>
    2013-11-14 22:11:30-0800 [Uninitialized]
            [('debug', True, 'WebSocketClientFactory'),
             ('debugCodePaths', False, 'WebSocketClientFactory'),
             ('logOctets', True, 'WebSocketClientFactory'),
             ('logFrames', True, 'WebSocketClientFactory'),
             ('trackTimings', False, 'WebSocketClientFactory'),
             ('allowHixie76', False, 'WebSocketClientFactory'),
             ('utf8validateIncoming', True, 'WebSocketClientFactory'),
             ('applyMask', True, 'WebSocketClientFactory'),
             ('maxFramePayloadSize', 0, 'WebSocketClientFactory'),
             ('maxMessagePayloadSize', 0, 'WebSocketClientFactory'),
             ('autoFragmentSize', 0, 'WebSocketClientFactory'),
             ('failByDrop', True, 'WebSocketClientFactory'),
             ('echoCloseCodeReason', False, 'WebSocketClientFactory'),
             ('openHandshakeTimeout', 5, 'WebSocketClientFactory'),
             ('closeHandshakeTimeout', 1, 'WebSocketClientFactory'),
             ('tcpNoDelay', True, 'WebSocketClientFactory'),
             ('version', 18, 'WebSocketClientFactory'),
             ('acceptMaskedServerFrames', False, 'WebSocketClientFactory'),
             ('maskClientFrames', True, 'WebSocketClientFactory'),
             ('serverConnectionDropTimeout', 1, 'WebSocketClientFactory'),
             ('perMessageCompressionOffers', [], 'WebSocketClientFactory'),
             ('perMessageCompressionAccept',
              <function <lambda> at 0x177ba30>,
              'WebSocketClientFactory')]
    2013-11-14 22:11:30-0800 [Uninitialized] connection to 127.0.0.1:8080 established
    2013-11-14 22:11:30-0800 [Uninitialized] GET / HTTP/1.1
            User-Agent: AutobahnPython/0.6.4
            Host: localhost:8080
            Upgrade: WebSocket
            Connection: Upgrade
            Pragma: no-cache
            Cache-Control: no-cache
            Sec-WebSocket-Key: TOy2OL5T6VwzaiX93cesPw==
            Sec-WebSocket-Version: 13
    
    2013-11-14 22:11:30-0800 [Uninitialized] TX Octets to 127.0.0.1:8080 : sync = False, octets = 474554202f20485454502f312e310d0a557365722d4167656e743a204175746f6261686e5079
    74686f6e2f302e362e340d0a486f73743a206c6f63616c686f73743a383038300d0a557067726164653a20576562536f636b65740d0a436f6e6e656374696f6e3a20557067726164650d0a507261676d613a206e6f
    2d63616368650d0a43616368652d436f6e74726f6c3a206e6f2d63616368650d0a5365632d576562536f636b65742d4b65793a20544f79324f4c35543656777a616958393363657350773d3d0d0a5365632d576562
    536f636b65742d56657273696f6e3a2031330d0a0d0a
    2013-11-14 22:11:30-0800 [EchoClientProtocol,client] connection to 127.0.0.1:8080 lost
    2013-11-14 22:11:30-0800 [EchoClientProtocol,client] Stopping factory <autobahn.websocket.WebSocketClientFactory instance at 0xb6812080>
    

I take this as socket.io not wanting let non-socket.io connections connect,
which is kind of odd. If anyone knows a workaround or any ideas please share
them.


Answer: Websocket is just one protocol used by socket.io. As per socket.io
specifications <https://github.com/LearnBoost/socket.io-spec>, I need to make
a POST request to the server, which will return a session ID. Then, I can use
that to make an url to make a Websocket connection to the server with
Autobahn.

Do a POST to:  
`'http://localhost:8080/socket.io/1/'` The response body will include a unique
session ID.

`url = 'ws://socket.io/1/websocket/' + sid + '/'`  
Use above to connect to the server with Autobahn.

