3. Usage¶
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 ofWebSocketHandler
),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:
- For all clients connected to your WebSocket application, you should use
my_ws.emit
method, - For the client who just sent an event, you should use
socket.emit
method, - For a specific client, it’s not officially implemented but you can take a look at
my_ws.handlers
. It’s aWebSocketHandler
list and represents all clients connected to your application, so you can usemy_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 thanpath
parameter fromWebSocket
, see create websocket application,options.host
: host used for connection (default:'localhost'
, but soonwindow.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 namecallback
: Function to execute when eventevent
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 namedata
: Data to send, can be anObject
, not anObject
(will be replaced by{ data: { message: data }}
, orundefined
(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}
});