3. Usage — Django-tornado-websockets 0.2.1 documentation

# 3. Usage

- Run Tornado server
- Using WebSockets (server side)
  - Create a WebSocket application
  - Receive an event from a client
  - Send an event to a client
- Using WebSockets (client side)
  - Linking JS wrapper into your Django template
  - Create a WebSocket connection
  - Receive an event from the server
  - Send an event to the server

## 3.1. Run Tornado server

Django-tornado-websockets provides an easy solution to run your Tornado server. When you add `tornado_websockets` to your `INSTALLED_APPS`, you obtain a new management command called `runtornado`:

    $ python manage.py runtornado

## 3.2. Using WebSockets (server side)

It’s preferable to write your WebSocket applications in your `views.py` file, or import these in `views.py`.

### 3.2.1. Create a WebSocket application

You should use the `WebSocket` class to use... WebSockets 🤔. It takes only one parameter and it’s the `path`. This path should be unique because it’s automatically adding a new handler to Tornado handlers (`your_path <=> your_websocket`):

    from tornado_websockets.websocket import WebSocket

    # Make a new instance of WebSocket and automatically add handler '/ws/my_ws' to Tornado handlers
    my_ws = WebSocket('/my_ws')

Note

If you are using this decorator on a class method (a wild `self` parameter appears!), you need to define a context for the WebSocket instance because `@my_ws.on` decorator can not know by itself what value `self` should take (or maybe I am doing it wrong?):

    class MyClass(object):

        def __init__(self):
            my_ws.context = self

### 3.2.2. Receive an event from a client

To listen an incoming event, you should use the `@my_ws.on` decorator (where `my_ws` is an instance of `WebSocket`) on a function or a class method.

Functions and class methods should take two named parameters:

- `socket`: client who sent the event (instance of `WebSocketHandler`),
- `data`: data sent by the client (dictionary).

Usage example:

    # On a function
    @my_ws.on
    def my_event(socket, data):
        print('Catch "my_event" event from a client')
        print('But I know this client, it is the one using this websocket connection: %s' % socket)

    # On a class method
    class MyClass(object):

        def __init__(self):
            # Do not forget the context, otherwise the `self` value for all class methods decorated by `@my_ws.on`
            # decorator will be `None`
            my_ws.context = self

        @wy_ws.on
        def my_other_event(self, socket, data):
            # `self` value is a MyClass instance due to `my_ws.context = self` in `__init__()` method
            print('Catch "my_other_event" from a client')
            print('And same as before, I know that this client is using this websocket connection: %s' % socket)

### 3.2.3. Send an event to a client

Warning

You can only emit an event in a function or method decorated by `@my_ws.on` decorator.

There is three ways to emit an event:

1. For all clients connected to your WebSocket application, you should use `my_ws.emit` method,
2. For the client who just sent an event, you should use `socket.emit` method,
3. For a specific client, it’s not officially implemented but you can take a look at `my_ws.handlers`. It’s a `WebSocketHandler` list and represents all clients connected to your application, so you can use `my_ws.handlers[0].emit` method.

Usage example (echo server):

    from tornado_websockets.websocket import WebSocket

    ws_echo = WebSocket('/echo')

    @ws_echo.on
    def open(socket):
        # Notify all clients about a new connection
        ws_echo.emit('new_connection')

    @ws_echo.on
    def message(socket, data):
        # Reply to the client
        socket.emit('message', data)

        # Wow we got a spammer, let's inform the first client :^)
        if 'spam' in data.message:
            # wow
            ws_echo[0].emit('got_spam', {
                'message': data.get('message'),
                'socket': socket
            })

For more examples, you can read testapp/views.py file.

## 3.3. Using WebSockets (client side)

Django-tornado-websockets uses its own wrapper for using JavaScript WebSocket in client-side: django-tornado-websockets-client. By using this wrapper, you will be able to write:

    var ws = new TornadoWebSocket(...);

    ws.on('open', () => {
        ws.emit('my_event', { foo: 'bar' });
    });

    // instead of
    var ws = new WebSocket(...);

    ws.onopen = () => {
        ws.send({ event: 'my_event', data: { foo: 'bar' }});
    };

But you can simply ignore this wrapper and use raw WebSocket if you want. Just remember that data passed by Django-tornado-websockets are in JSON: `{event: 'evt', data: {}}`.

### 3.3.1. Linking JS wrapper into your Django template

Link `django-tornado-websockets-client.js` (symbolic link to main.min.js) file in your Django template:

    {% load static %}
    <script src="{% static 'tornado_websockets/client.js' %}"></script>

### 3.3.2. Create a WebSocket connection

There is three ways to create a WebSocket connection:

    var ws = new TornadoWebSocket(path, options);
    var ws = TornadoWebSocket(path, options); // shortcut to new TornadoWebSocket(path, options)
    var ws = tws(path, options);  // shortcut to new TornadoWebSocket(path, options)

class `TornadoWebSocket`(String path, Object options)

  Initialize a new WebSocket object with given options.

  Parameters:

  - `path`: same value than `path` parameter from `WebSocket`, see create websocket application,
  - `options.host`: host used for connection (default: `'localhost'`, but soon `window.location`)
  - `options.port`: port used for connection (default: `8000`)
  - `options.secure`: `true` for using a secure connection (default: `false`)

### 3.3.3. Receive an event from the server

You can listen to WebSocket’s events `onopen`, `onclose` and `onerror` (`onmessage` too but you will rewrite a core part). You can also listen to your own events like `my_event`, `user_joined`, etc...

`TornadoWebSocket.` `on`(String event, Function callback)

  Bind a function to an event.

  Parameters:

  - `event`: Event name
  - `callback`: Function to execute when event `event` is received

    // Bind to WebSocket.onopen
    ws.on('open', event => {
        console.log('Connection: OPEN', event);

        // Add an event/callback combination into TornadoWebSocket.events private object.
        // Will be called when we receive a JSON like that: {event: 'my_event', data: {...}}
        ws.on('my_event', data => {
            console.log('Got data from « my_event »', data);
        });
    });

    // Bind to WebSocket.onclose
    ws.on('close', event => {
        console.log('Connection: ERROR', event);
    });

    // Bind to WebSocket.onerror
    ws.on('error', event => {
        console.log('Connection: CLOSED', event);
    });

### 3.3.4. Send an event to the server

`TornadoWebSocket.` `emit`(String event, Object|* data)

  Send a pair event/data to the server.

  Parameters:

  - `event`: Event name
  - `data`: Data to send, can be an `Object`, not an `Object` (will be replaced by `{ data: { message: data }}`, or `undefined` (will be replaced by `{}`)

    ws.on('open', event => {
        ws.emit('my_event'); // will send {}

        ws.emit('my_event', 'My message'); // will send {message: 'My message'}

        ws.emit('my_event', {my: 'data'}); // will send {my: 'data}
    });