Professional Documents
Culture Documents
TORNADO
Gavin M. Roy
CTO
myYearbook.com
pyCon 2011
Atlanta, GA
TORNADO AT
MYYEARBOOK.COM
• Currency Connect
• Redirect Engine
• Nerve
• Staplr 2
application = web.Application([
(r"/", MainPageHandler),
])
http_server = httpserver.HTTPServer(application)
http_server.listen(8080)
ioloop.IOLoop.instance().start()
application = web.Application([
(r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}),
])
• Based on Twisted
• Includes decorators
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler),
])
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(8888)
tornado.ioloop.IOLoop.instance().start()
REQUEST HANDLERS
• tornado.web.RequestHandler
• Session Handling
• Localization
class MyRequestHandler(tornado.web.RequestHandler):
def initialize(self):
host = self.application.settings['Redis']['host']
port = self.application.settings['Redis']['port']
class Homepage(MyRequestHandler):
@tornado.web.asynchronous
def get(self):
content = self.redis.get('homepage')
self.write(content)
self.finish()
TORNADO.TEMPLATE
• Not required
• Fast, extensible
class Home(RequestHandler):
def get(self):
<html>
<body>
Hi {{username}}, welcome to our site.
</body>
</html>
BASE TEMPLATE
<html>
<head>
<title>My Site :: {% block title %}Unextended Template{% end %}</title>
<link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" />
<script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script>
{% if not current_user %}
<script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js">
</script>
{% end %}
</head>
<body{% if current_user %} class="authenticated"{% end %}>
{% include "header.html" %}
{% if request.uri not in ['/', ''] and current_user %}
{{ modules.MemberBar() }}
{% end %}
<div id="content">
{% block content %}
No Content Specified
{% end %}
</div>
<ul id="footer">
<li><a href="/terms">{{_("Terms and Conditions")}}</a></li>
<li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li>
<li class="right">{{_("Copyright")}} © {{ datetime.date.today().year }}</li>
</ul>
</body>
</html>
CONTENT TEMPLATE
{% extends "base.html" %}
{% block title %}{{_("Error Title")}}{% end %}
{% block content %}
<h1>{{_("Error Title")}}</h1>
<img src="/static/images/sad_robot.png" class="error_robot" />
<p class="error_message">{{_("Error Message")}}</p>
<h2 class="error">{{status_code}} - {{exception}}</h2>
{% end %}
TEMPLATE XSRF EXAMPLE
• Similar
to RequestHandler in
behavior
UIMODULE EXAMPLE
Embed
UIMODULE EXAMPLE
<div>{{ modules.HTTPSCheck() }}</div>
class HTTPSCheck(tornado.web.UIModule):
def render(self):
UIModule Class
return self.render_string("modules/ssl.html")
return ''
<div class="information">
Template
<a href="https://{{request.host}}{{request.uri}}">
{{_("Click here to use a secure connection")}}
</a>
</div>
TORNADO.LOCALE
• In a csv format
• tornado.locale.load_translations
(path)
class RequestHandler(tornado.web.RequestHandler):
def get_user_locale(self):
<html>
<body>
{{_("Welcome to our site.")}}
</body>
</html>
LOCALE FILE EXAMPLE: DE_DE
"New","Neu"
"Donate","Spenden"
"New Paste","Neuer Paste"
"Secure, Private Pasting","Sicheres Pasten"
"Unclaimed Hostname","Sie benutzen einen offenen Hostnamen.
Klicken Sie heir für weitere Informationen."
"Paste Options","Paste Optionen"
"Formatting","Formatierung"
"No Formatting","Keine Formatierung"
"Line Numbers","Zeilennummern"
"On","An"
"Off","Aus"
"Minutes","Minuten"
"Hour","Stunde"
"Day","Tag"
"Week","Woche"
"Year","Jahr"
"Expire Paste","Wann soll der Paste gelöscht werden?"
"Encryption","Verschlüsselung"
"Encryption Key","Passwort-Verschlüsselung"
"Encryption Algorithm","Algorithm-Verschlüsselung"
"Save Paste","Paste speichern"
"All Rights Reserved","Alle Rechte vorbehalten"
TEMPLATE EXAMPLE AGAIN
<html>
<head>
<title>My Site :: {% block title %}Unextended Template{% end %}</title>
<link rel="stylesheet" type="text/css" href="{{ static_url('css/site.css') }}" />
<script type="text/javascript" src="{{ static_url('javascript/site.js') }}"></script>
{% if not current_user %}
<script type="text/javascript" src="http://api.recaptcha.net/js/recaptcha_ajax.js">
</script>
{% end %}
</head>
<body{% if current_user %} class="authenticated"{% end %}>
{% include "header.html" %}
{% if request.uri not in ['/', ''] and current_user %}
{{ modules.MemberBar() }}
{% end %}
<div id="content">
{% block content %}
No Content Specified
{% end %}
</div>
<ul id="footer">
<li><a href="/terms">{{_("Terms and Conditions")}}</a></li>
<li class="center">{{_("Version")}}: {{ handler.application.settings['version'] }}</li>
<li class="right">{{_("Copyright")}} © {{ datetime.date.today().year }}</li>
</ul>
</body>
</html>
TORNADO.AUTH
• Is asynchronous
@tornado.web.asynchronous
def get(self):
if self.get_argument("oauth_token", None):
self.get_authenticated_user(self.async_callback(self._on_auth))
return
self.authorize_redirect()
username = ffuser['username']
TORNADO.IOLOOP
• Protocol independent
• tornado.ioloop.add_timeout
• tornado.ioloop.PeriodicCallback
TORNADO.IOLOOP EXAMPLE
class MyClient(object):
self.io_loop.add_handler(self.sock.fileno(),
self._handle_events, events)
https://github.com/pika/pika/blob/master/pika/adapters/tornado_connection.py
OTHER MODULES OF NOTE
• tornado.database • tornado.options
• tornado.escape • tornado.testing
• tornado.httpclient • tornado.websocket
• tornado.iostream
• Memcache
• MongoDB
• PostgreSQL
• RabbitMQ
• Redis
FIN
• Blog: http://gavinroy.com
• Pika: http://github.com/pika