Search code examples
javascriptdjangopython-3.xwebsocketautobahn

Cannot communicate with websocket. Autobahn: received HELLO message, and session is not yet established


I am trying to build a WebSocket session using Python 3.4, Django, Autobahn and JS. I have successfully run the websocket server on the python side, but i cannot subscribe or receive any data published by the server

My code is fairly simple:

class TestAppWS(ApplicationSession):
    """
    An application component that publishes an event every second.
    """
    def onConnect(self):
        self.join(u"realm1")

    @asyncio.coroutine
    def onJoin(self, details):
        counter = 0
        while True:
            self.publish('com.myapp.topic1', counter)
            counter += 1
            yield from asyncio.sleep(1)


def start_ws():
    print("Running")
    session_factory = ApplicationSessionFactory()
    session_factory.session = TestAppWS
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)

    # factory = WebSocketServerFactory("ws://localhost:8090", debug=False)
    # factory.protocol = MyServerProtocol

    server = None
    try:
        transport_factory = WampWebSocketServerFactory(session_factory, debug_wamp=True)
        loop = asyncio.get_event_loop()
        coro = loop.create_server(transport_factory, 'localhost', 8090)
        server = loop.run_until_complete(coro)
        loop.run_forever()
    except OSError:
        print("WS server already running")
    except KeyboardInterrupt:
        pass
    finally:
        if server:
            server.close()
        loop.close()

start_ws() is run inside a separate Thread object. If I access localhost:8090 on my browser I can see the Autobahn welcome message.

On the frontend I have

var connection = new autobahn.Connection({
   url: 'ws://localhost:8090/',
   realm: 'realm1'}
);
connection.onopen = function (session) {    
   var received = 0;

   function onevent1(args) {
      console.log("Got event:", args[0]);
      received += 1;
      if (received > 5) {
         console.log("Closing ..");
         connection.close();
      }
   }

   session.subscribe('com.myapp.topic1', onevent1);
};

connection.open();

It does not seem to work, when I try to connect the frontend I get the following error on the backend side:

Failing WAMP-over-WebSocket transport: code = 1002, reason = 'WAMP Protocol Error (Received <class 'autobahn.wamp.message.Hello'> message, and session is not yet established)'
WAMP-over-WebSocket transport lost: wasClean = False, code = 1006, reason = 'connection was closed uncleanly (I failed the WebSocket connection by dropping the TCP connection)'
TX WAMP HELLO Message (realm = realm1, roles = [<autobahn.wamp.role.RolePublisherFeatures object at 0x04710270>, <autobahn.wamp.role.RoleSubscriberFeatures object at 0x047102B0>, <autobahn.wamp.role.RoleCallerFeatures object at 0x047102D0>, <autobahn.wamp.role.RoleCalleeFeatures object at 0x047102F0>], authmethods = None, authid = None)
RX WAMP HELLO Message (realm = realm1, roles = [<autobahn.wamp.role.RoleSubscriberFeatures object at 0x04710350>, <autobahn.wamp.role.RoleCallerFeatures object at 0x04710330>, <autobahn.wamp.role.RoleCalleeFeatures object at 0x04710390>, <autobahn.wamp.role.RolePublisherFeatures object at 0x04710370>], authmethods = None, authid = None)
Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\autobahn\wamp\websocket.py", line 91, in onMessage
    self._session.onMessage(msg)
  File "C:\Python34\lib\site-packages\autobahn\wamp\protocol.py", line 429, in onMessage
    raise ProtocolError("Received {0} message, and session is not yet established".format(msg.__class__))
autobahn.wamp.exception.ProtocolError: Received <class 'autobahn.wamp.message.Hello'> message, and session is not yet established

on the javascript console I see:

Uncaught InvalidAccessError: Failed to execute 'close' on 'WebSocket': The code must be either 1000, or between 3000 and 4999. 1002 is neither.

Any idea? It looks like the session is not started, honestly it is not clear how this session work. Should not the session be initialized once a connection from the client is made?


Solution

  • Your TestAppWs and your browser code are both WAMP application components. Both of these need to connect to a WAMP router. Then they can talk freely to each other (as if there were no router in between .. transparently).

    Here is how to run.

    Run a WAMP Router.

    Using Crossbar.io (but you can use other WAMP routers as well), that's trivial. First install Crossbar.io:

    pip install crossbar
    

    Crossbar.io (currently) runs on Python 2, but that's irrelevant as your app components can run on Python 3 or any other WAMP supported language/run-time. Think of Crossbar.io like a black-box, an external infrastructure, like a database system.

    Then create and start a Crossbar.io default router:

    cd $HOME
    mkdir mynode
    cd mynode
    crossbar init
    crossbar start
    

    Run your Python 3 / asyncio component

    import asyncio
    from autobahn.asyncio.wamp import ApplicationSession
    
    
    class MyComponent(ApplicationSession):
    
       @asyncio.coroutine
       def onJoin(self, details):
          print("session ready")
    
          counter = 0
          while True:
             self.publish('com.myapp.topic1', counter)
             counter += 1
             yield from asyncio.sleep(1)
    
    
    if __name__ == '__main__':
       from autobahn.asyncio.wamp import ApplicationRunner
    
       runner = ApplicationRunner(url = "ws://localhost:8080/ws", realm = "realm1")
       runner.run(MyComponent)
    

    Run your browser component

    var connection = new autobahn.Connection({
       url: 'ws://localhost:8080/ws',
       realm: 'realm1'}
    );
    
    connection.onopen = function (session) {    
       var received = 0;
    
       function onevent1(args) {
          console.log("Got event:", args[0]);
          received += 1;
          if (received > 5) {
             console.log("Closing ..");
             connection.close();
          }
       }
    
       session.subscribe('com.myapp.topic1', onevent1);
    };
    
    connection.open();