Split off the Tornado code into a separate process

(imported from commit 95dbd0f438cdba06d6e6c6c539a2a3d49c577cfd)
This commit is contained in:
Keegan McAllister
2012-10-09 16:21:03 -04:00
parent f0d4cc3d42
commit 5e70b5a291
5 changed files with 39 additions and 6 deletions

View File

@@ -84,6 +84,13 @@ if deployed:
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# A shared secret, used to authenticate different parts of the app to each other.
# FIXME: store this password more securely
SHARED_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# URL where Django code posts to the Tornado code to notify of new messages
NOTIFY_WAITING_CLIENTS_URL = 'http://localhost:9993/notify_waiting_clients'
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',

View File

@@ -40,6 +40,9 @@ urlpatterns = patterns('',
url(r'^static/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': os.path.join(settings.SITE_ROOT, '../zephyr/static-access-control')}),
# Used internally for communication between Django and Tornado processes
url(r'^notify_waiting_clients$', 'zephyr.views.notify_waiting_clients', name='notify_waiting_clients'),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

View File

@@ -84,14 +84,11 @@ class Command(BaseCommand):
print "Tornado server is running at http://%s:%s/" % (addr, port)
print "Quit the server with %s." % quit_command
from tornado.web import FallbackHandler
django_app = wsgi.WSGIContainer(WSGIHandler())
try:
# Application is an instance of Django's standard wsgi handler.
application = web.Application([(r"/json/get_updates", AsyncDjangoHandler),
(r"/api/v1/get_messages", AsyncDjangoHandler),
(r".*", FallbackHandler, dict(fallback=django_app)),
(r"/notify_waiting_clients", AsyncDjangoHandler),
], debug=django.conf.settings.DEBUG)
# start tornado web server in single-threaded mode

View File

@@ -11,6 +11,7 @@ import simplejson
from django.db import transaction
from zephyr.lib import bugdown
from zephyr.lib.avatar import gravatar_hash
import requests
@cache_with_key(lambda self: 'display_recipient_dict:%d' % (self.id))
def get_display_recipient(recipient):
@@ -81,6 +82,7 @@ class UserProfile(models.Model):
api_key = models.CharField(max_length=32)
# The user receives this message
# Called in the Tornado process
def receive(self, message):
global callback_table
@@ -292,8 +294,10 @@ def do_send_message(message, synced_from_mit=False, no_log=False):
for user_profile in recipients:
UserMessage(user_profile=user_profile, message=message).save()
for recipient in recipients:
recipient.receive(message)
requests.post(settings.NOTIFY_WAITING_CLIENTS_URL, data=[
('secret', settings.SHARED_SECRET),
('message', message.id)]
+ [('user', user.id) for user in recipients])
class Subscription(models.Model):
userprofile = models.ForeignKey(UserProfile)

View File

@@ -446,6 +446,28 @@ def send_message_backend(request, user_profile, sender):
return json_success()
@asynchronous
@csrf_exempt
@require_post
def notify_waiting_clients(request, handler):
# Check the shared secret.
# Also check the originating IP, at least for now.
if ((request.META['REMOTE_ADDR'] != '127.0.0.1')
or (request.POST.get('secret') != settings.SHARED_SECRET)):
handler.set_status(403)
handler.finish('Access denied')
return
# FIXME: better query
users = [UserProfile.objects.get(id=user) for user in request.POST.getlist('user')]
message = Message.objects.get(id=request.POST['message'])
for user in users:
user.receive(message)
handler.finish()
@login_required_api_view
def api_get_public_streams(request, user_profile):
streams = sorted([stream.name for stream in