tornado-sse use tornado and brukva for multichannel Server-Sent Event server. Additional it provides such thins like: eventsource polyfill, we prefer jQuery.eventsource; javascript handler for delegate SSE to jQuery events; Django management command and special Django handler.
pip install git+git://github.com/truetug/tornado-sse.git
Start server:
$ tornado_sse [--address=127.0.0.1] [--port=8888] [--debug]
Then place static files to serve directory, or just map Nginx location to tornado_sse/static directory.
To subscribe to some channels just place them to get parameter "channels" in "sse-data" attribute of body:
<head> <script type="text/javascript" src="/media/tornado_sse/jquery.eventsource.js"></script> <script type="text/javascript" src="/media/tornado_sse/sse.js"></script> </head> <body sse-data="/sse/?channels=all,foo"> ... </body>
Unfortunately, many browsers catch only "onopen" and "onmessage" event, so for now I decide to make my own format of JSON for different kinds of messages:
// for redis 127.0.0.1:6379> PUBLISH all '["message", "{\"type\": \"message\", \"your-structure\": \"Blowjob is better than no job 1\", \"user\": \"tug\"}"]' $('body').on('sse.message', function(el, msg){ console.log(msg); }); // for redis 127.0.0.1:6379> PUBLISH all '["message", "{\"type\": \"foo\", \"other-structure\": \"Blowjob is better than no job 1\", \"user\": \"bar\"}"]' $('body').on('sse.foo', function(el, msg){ console.log(msg); });
Install redis and django_sse. It is no requirements of tornado_sse.
Add "redis", "django_sse" and "tornado_sse" to INSTALLED_APPS:
### SSE ### INSTALLED_APPS += ( 'redis', 'django_sse', 'tornado_sse', ) REDIS_SSEQUEUE_CONNECTION_SETTINGS = { 'location': 'localhost:6379', 'db': 0, } ### SSE ###
tornado_sse use same settings for connection to redis as django_sse.
Handler for Django differs from usual handler. It subscribes to channels: "%username%" and "all".
To send message you may use send_event function from django_sse.redisqueue.
I prefer to use signals for such things. So for user with login "admin" it would look something like this:
# encoding: utf-8 from django.utils import simplejson as json from django.dispatch.dispatcher import receiver from django.db.models.signals import post_save from django_sse.redisqueue import send_event from myapp.models import MyModel @receiver(post_save, sender=MyModel) def mymodel_post_save_notify(sender, **kwargs): instance = kwargs.get('instance') message = json.dumps({ 'type': 'foo', 'html': instance.as_html(), }) send_event('message', message, 'admin') # named channel return True
Start server:
(env) ...$ python manage.py runsseserver
In HTML no need to register channels in "sse-data" because handler determines their names on the session:
<head> <script type="text/javascript" src="{{ STATIC_URL }}tornado_sse/jquery.eventsource.js"></script> <script type="text/javascript" src="{{ STATIC_URL }}tornado_sse/sse.js"></script> </head> <body sse-data="/sse/"> ... </body>
Use code from Standalone section.
If your main server in behind Nginx you may proxy SSE like this:
location /sse/ { rewrite ^(.*)$ / break; # to root of our tornado proxy_buffering off; # to push immediately proxy_pass http://127.0.0.1:8888; }