Skip to content
This repository
Newer
Older
100644 510 lines (359 sloc) 17.74 kb
77f4e96a »
2010-01-28 updated docs
1 =======
c297fa0f »
2012-02-10 updated docs, and version
2 cyclone
77f4e96a »
2010-01-28 updated docs
3 =======
4 :Info: See `github <http://github.com/fiorix/cyclone>`_ for the latest source.
5 :Author: Alexandre Fiori <fiorix@gmail.com>
6
eb665671 »
2010-01-24 docs
7 About
8 =====
9
83ae4e29 »
2012-06-08 partially updated docs
10 cyclone is a clone of facebook's `Tornado <http://tornadoweb.org>`_, on top of
11 `Twisted <http://twistedmatrix.com>`_.
12
13 The web framework is very similar, but cyclone leverages all enterprise class
14 features of Twisted, and more.
15
16 It is extremely stable, and ready for production.
17
18
19 Features
20 --------
21
96b904d1 »
2012-06-08 partially updated docs
22 **cyclone is a Twisted protocol**. Thus, it may be used in conjunction with
f4323256 »
2012-06-08 partially updated docs
23 any other protocol implemented in Twisted. The same server can deliver HTTP
24 content on one port, SSH on another, and it can keep a pool of persistent,
25 non-blocking connections to several databases. All in a single process.
83ae4e29 »
2012-06-08 partially updated docs
26
f4323256 »
2012-06-08 partially updated docs
27 Web apps built with cyclone are **fully translatable**. The localisation system
83ae4e29 »
2012-06-08 partially updated docs
28 is based on `Gettext <http://www.gnu.org/software/gettext/>`_. It's possible
29 to translate strings in the server code, as well as text and HTML templates.
30
f4323256 »
2012-06-08 partially updated docs
31 **Secure**. It can deliver HTTP and **HTTPS (SSL)** on the same server, with
83ae4e29 »
2012-06-08 partially updated docs
32 individual request routing mechanism. Also, cyclone supports the standard HTTP
33 Authentication, which can be used to implement HTTP Basic, Digest, or any
34 other hand crafted authentication system, like `Amazon's S3
35 <http://docs.amazonwebservices.com/AmazonS3/latest/dev/RESTAuthentication.html>`_.
36
f4323256 »
2012-06-08 partially updated docs
37 **API friendly**. cyclone is very useful for writing web APIs, RESTful or not.
83ae4e29 »
2012-06-08 partially updated docs
38 Features like HTTP Keep-Alive and XSRF can be enabled or disabled per request,
39 which means the server can have different behaviour when communicating with
40 browsers, or other custom HTTP clients.
41
f4323256 »
2012-06-08 partially updated docs
42 Ships with a full featured, **non-blocking HTTP client**, using
83ae4e29 »
2012-06-08 partially updated docs
43 `TwistedWeb <http://twistedmatrix.com/trac/wiki/TwistedWeb>`_.
44
f4323256 »
2012-06-08 partially updated docs
45 **E-mail, the easy way**. With cyclone, the web server can connect to multiple
83ae4e29 »
2012-06-08 partially updated docs
46 SMTP servers, on demand. The e-mail API is simple, support client connections
47 with SSL and TLS, and provide you with an easy way to customize messages,
48 and attachments.
49
f4323256 »
2012-06-08 partially updated docs
50 Supports **multiple protocols**: built-in support for XML-RPC, JSON-RPC,
83ae4e29 »
2012-06-08 partially updated docs
51 WebSocket and SSE. And, many other protocols can be used in cyclone-based web
52 servers, like the `Event Socket <http://wiki.freeswitch.org/wiki/Event_Socket>`_
53 protocol of `Freeswitch <http://freeswitch.org/>`_, a highly scalable soft
54 switch, telephony platform.
55
f4323256 »
2012-06-08 partially updated docs
56 **Storage engines**: cyclone ships with built-in support for inline SQLite,
83ae4e29 »
2012-06-08 partially updated docs
57 and `Redis <http://redis.io/>`_. MongoDB and many other NoSQL are supported
58 with 3rd party libraries. All other RDBMs supported by Python are available as
59 well, like MySQL and PostgreSQL, via `twisted.enterprise.adbapi
60 <http://twistedmatrix.com/documents/current/core/howto/rdbms.html>`_.
61 Connection pools can persist, and be efficiently used by all requests. It can
62 also auto-reconnect automatically, making it totally fault-tolerant on database
63 errors and disconnections.
64
f4323256 »
2012-06-08 partially updated docs
65 **For the simple, and the complex**: cyclone-based web apps can be written as
83ae4e29 »
2012-06-08 partially updated docs
66 `Bottle <http://bottlepy.org/>`_, or Tornado. A 10-line script can handle
67 thousands of connections per second, with very low CPU and memory footprint.
68 For more complex applications, cyclone offers an app template out of the box,
69 with a configuration file, database support, translation, and deployment
70 scheme, fully integrated with Debian GNU/Linux. Via ``twistd``, cyclone-based
71 apps can be easily deployed in any operating system, with customized log and
72 pid files, reactor, permissions, and many other settings.
73
eb665671 »
2010-01-24 docs
74
fde01019 »
2010-01-26 updated docs
75 Benchmarks
76 ----------
77
78 Check out the `benchmarks <http://wiki.github.com/fiorix/cyclone/benchmarks>`_ page.
eb665671 »
2010-01-24 docs
79
976ad3f5 »
2012-02-15 new docs, skel and version
80
81 Development and Deployment
82 ==========================
83
84 Twisted Plugin is the recommended way to go for production. Create new projects
85 right away off of the generic application skeleton shipped with cyclone::
86
87 $ python -m cyclone.app --help
88
89 use: cyclone/app.py [options]
90 Options:
91 -h --help Show this help.
92 -g --git Use git's name and email settings, and create a git repo on target
93 -p --project=NAME Create new cyclone project.
94 -m --modname=NAME Use another name for the module [default: project_name]
95 -v --version=VERSION Set project version [default: 0.1]
96 -s --set-pkg-version Set version on package name [default: False]
97 -t --target=PATH Set path where project is created [default: ./]
98
99 Example::
100
101 python -m cyclone.app -p foobar
102 cd foobar
103 twistd -n foobar
104
105 Check out the README.rst in the new project's directory for detailed information.
106 It ships with debian init scripts for single or multiple instances (one per cpu core)
107 to help make deployment as simple as possible.
108
109
eb665671 »
2010-01-24 docs
110 Tips and Tricks
111 ===============
112
c297fa0f »
2012-02-10 updated docs, and version
113 As a clone, the API implemented in cyclone is almost the same of Tornado. Therefore you may use the `Tornado Documentation <http://www.tornadoweb.org/documentation>`_ for stuff like templates and so on.
eb665671 »
2010-01-24 docs
114
115 The snippets below will show some tips and tricks regarding the few differences between the two.
116
117 Hello World
118 -----------
119
120 ::
121
122 #!/usr/bin/env python
123 # coding: utf-8
124
125 import cyclone.web
c297fa0f »
2012-02-10 updated docs, and version
126 import sys
eb665671 »
2010-01-24 docs
127 from twisted.internet import reactor
c297fa0f »
2012-02-10 updated docs, and version
128 from twisted.python import log
eb665671 »
2010-01-24 docs
129
c297fa0f »
2012-02-10 updated docs, and version
130 class MainHandler(cyclone.web.RequestHandler):
eb665671 »
2010-01-24 docs
131 def get(self):
c297fa0f »
2012-02-10 updated docs, and version
132 self.write("Hello, world")
eb665671 »
2010-01-24 docs
133
c297fa0f »
2012-02-10 updated docs, and version
134 def main():
135 log.startLogging(sys.stdout)
136 application = cyclone.web.Application([
137 (r"/", MainHandler)
138 ])
eb665671 »
2010-01-24 docs
139
c297fa0f »
2012-02-10 updated docs, and version
140 reactor.listenTCP(8888, application, interface="127.0.0.1")
141 reactor.run()
eb665671 »
2010-01-24 docs
142
143 if __name__ == "__main__":
c297fa0f »
2012-02-10 updated docs, and version
144 main()
eb665671 »
2010-01-24 docs
145
c297fa0f »
2012-02-10 updated docs, and version
146
147 Twisted Application and Plugin
148 ------------------------------
eb665671 »
2010-01-24 docs
149
150 The advantage of being a Twisted Application is that you don't need to care about basic daemon features like forking, creating pid files, changing application's user and group permissions, and selecting the proper reactor within the code.
151
152 Instead, the application may be run by ``twistd``, as follows::
153
154 for testing:
155 /usr/bin/twistd --nodaemon --python=foobar.tac
156
157 for production:
158 /usr/bin/twistd --pidfile=/var/run/foobar.pid \
159 --logfile=/var/log/foobar.log \
160 --uid=nobody --gid=nobody \
161 --reactor=epoll \
162 --python=foobar.tac
163
164 Following is the *Hello World* as a twisted application::
165
166 # coding: utf-8
167 # twisted application: foobar.tac
168
169 import cyclone.web
170 from twisted.application import service, internet
171
172 class IndexHandler(cyclone.web.RequestHandler):
173 def get(self):
174 self.write("hello world")
175
176 foobar = cyclone.web.Application([(r"/", IndexHandler)])
177
178 application = service.Application("foobar")
179 internet.TCPServer(8888, foobar(),
180 interface="127.0.0.1").setServiceParent(application)
181
c297fa0f »
2012-02-10 updated docs, and version
182
976ad3f5 »
2012-02-15 new docs, skel and version
183 Authenticated and Asynchronous decorators
184 -----------------------------------------
185
186 Tornado provides decorator functions for asynchronous and authenticated
187 methods. Obviously, they're also implemented in cyclone, and yet more
188 powerful when combined with a famous Twisted decorator: ``defer.inlineCallbacks``.
189
190 The ``cyclone.web.authenticated`` decorator may be combined with ``defer.inlineCallbacks``,
191 however, there's a basic rule to use them together. Considering that the authenticated
192 decorator will check user credentials, and, depending on the result, it will
193 continue processing the request OR redirect the request to the login page,
194 it has to be used *before* the ``defer.inlineCallbacks`` to function properly::
195
196 class IndexHandler(cyclone.web.RequestHandler):
197 @cyclone.web.authenticated
198 @defer.inlineCallbacks
199 def get(self):
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
200 result = yield self.do_download()
976ad3f5 »
2012-02-15 new docs, skel and version
201 self.write(result)
202
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
203 The ``cyclone.web.asynchronous`` decorator should be used with
204 asynchronous handers that don't use ``defer.inlineCallbacks``. This
205 decorator will keep the request open until you explicitly call
206 ``self.finish()`` later on, which is necessary if your handler needs
207 to continue writing to the request::
976ad3f5 »
2012-02-15 new docs, skel and version
208
209 class Indexhandler(cyclone.web.RequestHandler):
210 @cyclone.web.asynchronous
211 def get(self):
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
212 download_deferred = self.do_download()
8a54d848 »
2012-05-05 fixed README - exec callback instead of just passing on Auth/Async de…
213 download_deferred.addCallback(self.process_download)
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
214 return d
976ad3f5 »
2012-02-15 new docs, skel and version
215
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
216 def process_download(self, result):
217 self.finish(result)
976ad3f5 »
2012-02-15 new docs, skel and version
218
6f8b06e5 »
2012-04-27 clarify authenticated/asynchronous decorators
219 If you're looking for the Cyclone equivalent of the ``tornado.gen.engine``
220 decorator, this is Tornado's version of ``defer.inlineCallbacks``.
c297fa0f »
2012-02-10 updated docs, and version
221
eb665671 »
2010-01-24 docs
222 Localization
223 ------------
224
c297fa0f »
2012-02-10 updated docs, and version
225 The ``cyclone.locale`` provides an API based on the Python ``gettext`` module.
eb665671 »
2010-01-24 docs
226
c297fa0f »
2012-02-10 updated docs, and version
227 Because of that, there is *one* extra option that may be passed to ``cyclone.locale.load_gettext_translations(path, domain="cyclone")``, which the is the gettext's domain. The default domain is *cyclone*.
eb665671 »
2010-01-24 docs
228
c297fa0f »
2012-02-10 updated docs, and version
229 Following is a step-by-step guide to implement localization in any cyclone application:
eb665671 »
2010-01-24 docs
230
231 1. Create a python script or twisted application with translatable strings::
232
233 # coding: utf-8
234 # twisted application: foobar.tac
235
236 import cyclone.web
237 import cyclone.locale
238 from twisted.application import service, internet
239
240 class BaseHandler(cyclone.web.RequestHandler):
241 def get_user_locale(self):
242 lang = self.get_cookie("lang")
243 return cyclone.locale.get(lang)
244
245 class IndexHandler(BaseHandler):
246 def get(self):
247 self.render("index.html")
248
249 def post(self):
b0cfeb84 »
2010-01-24 updated docs
250 _ = self.locale.translate
eb665671 »
2010-01-24 docs
251 name = self.get_argument("name")
252 self.write(_("the name is: %s" % name))
253
254 class LangHandler(cyclone.web.RequestHandler):
255 def get(self, lang):
256 if lang in cyclone.locale.get_supported_locales():
257 self.set_cookie("lang", lang)
258 self.redirect("/")
259
260 class Application(cyclone.web.Application):
261 def __init__(self):
262 handlers = [
263 (r"/", IndexHandler),
264 (r"/lang/(.+)", LangHandler),
265 ]
266
267 settings = {
268 "static_path": "./static",
269 "template_path": "./template",
270 }
271
fcfba71c »
2012-02-10 updated doc
272 cyclone.locale.load_gettext_translations("./locale", "foobar")
eb665671 »
2010-01-24 docs
273 cyclone.web.Application.__init__(self, handlers, **settings)
274
275 application = service.Application("foobar")
276 internet.TCPServer(8888, Application(),
277 interface="127.0.0.1").setServiceParent(application)
278
279 2. Create a file in ``./template/index.html`` with translatable strings::
280
281 <html>
282 <body>
283 <form action="/" method="post">
284 <p>{{ _("write someone's name:") }}</p>
79218b51 »
2010-01-24 updated docs
285 <input type="text" name="name">
eb665671 »
2010-01-24 docs
286 <input type="submit" value="{{ _('send') }}">
287 </form>
288
289 <br>
290 <p>{{ _("change language:") }}</p>
291 <p><a href="/lang/en_US">English (US)</a></p>
292 <p><a href="/lang/pt_BR">Portuguese (BR)</a></p>
293 </body>
294 </html>
295
296 3. Generate PO translatable file from the source code, using ``xgettext``:
297
298 You will notice that ``xgettext`` cannot parse HTML properly. It was
299 first designed to parse C files, and now it supports many other
300 languages including Python.
301
302 In order to parse lines like ``<input type="submit" value="{{ _('send') }}">``,
303 you'll need an extra script to pre-process the files.
304
305 Here's what you can use as ``fix.py``::
e4eb964e »
2011-02-24 minor update on locale code
306
eb665671 »
2010-01-24 docs
307 #!/usr/bin/env python
308 # coding: utf-8
309 # fix.py
310
311 import re, sys
312
313 if __name__ == "__main__":
314 try:
315 filename = sys.argv[1]
316 assert filename != "-"
317 fd = open(filename)
318 except:
319 fd = sys.stdin
320
321 line_re = re.compile(r"""['"]{{|}}['"] """)
322 for line in fd:
323 line = line_re.sub(r"", line)
324 sys.stdout.write(line)
325 fd.close()
326
327 Then, call ``xgettext`` to generate the PO translatable file::
328
329 cat foobar.tac template/index.html | python fix.py | \
e4eb964e »
2011-02-24 minor update on locale code
330 xgettext --language=Python --from-code=utf-8 --keyword=_:1,2 -d foobar
eb665671 »
2010-01-24 docs
331
332 This will create a file named ``foobar.po``, which needs to be
333 translated, then compiled into an MO file::
334
335 vi foobar.po
336 (translate everything, :wq)
337
338 mkdir -p ./locale/pt_BR/LC_MESSAGES/
339 msgfmt foobar.po -o ./locale/pt_BR/LC_MESSAGES/foobar.mo
340
341 4. Finally, test the internationalized application::
342
343 twistd -ny foobar.tac
344
4edc9c15 »
2010-01-24 updated docs
345 There is also a complete example with pluralization in `demos/locale <http://github.com/fiorix/cyclone/tree/master/demos/locale>`_.
eb665671 »
2010-01-24 docs
346
004c2b15 »
2010-01-25 more options and tricks
347 More options and tricks
348 -----------------------
349
350 - Keep-Alive
351
352 Because of the HTTP 1.1 support, sockets aren't always closed when you call
c297fa0f »
2012-02-10 updated docs, and version
353 ``self.finish()`` in a RequestHandler. cyclone lets you enforce that by setting
004c2b15 »
2010-01-25 more options and tricks
354 the ``no_keep_alive`` attribute attribute in some of your RequestHandlers::
355
356 class IndexHandler(cyclone.web.RequestHandler):
357 no_keep_alive = True
358 def get(self):
359 ...
360
361 - Socket closed notification
362
363 One of the great features of TwistedWeb is the ``request.notifyFinish()``,
c297fa0f »
2012-02-10 updated docs, and version
364 which is also available in cyclone.
004c2b15 »
2010-01-25 more options and tricks
365 This method returns a deferred which is fired when the request socket
366 is closed, by either ``self.finish()``, someone closing their browser
367 while receiving data, or closing the connection of a Comet request::
368
369 class IndexHandler(cyclone.web.RequestHandler):
370 def get(self):
371 ...
372 d = self.notifyFinish()
373 d.addCallback(remove_from_comet_handlers_list)
374
375 - HTTP X-Headers
376
976ad3f5 »
2012-02-15 new docs, skel and version
377 When running a cyclone-based application behind `Nginx <http://nginx.org/en/>`_,
004c2b15 »
2010-01-25 more options and tricks
378 it's very important to make it automatically use X-Real-Ip and X-Scheme HTTP
c297fa0f »
2012-02-10 updated docs, and version
379 headers. In order to make cyclone recognize those headers, the option ``xheaders=True``
004c2b15 »
2010-01-25 more options and tricks
380 must be set in the Application settings::
381
382 class Application(cyclone.web.Application):
383 def __init__(self):
384 handlers = [
385 (r"/", IndexHandler),
386 ]
387
388 settings = {
389 "xheaders": True
390 "static_path": "./static",
391 }
392
393 cyclone.web.Application.__init__(self, handlers, **settings)
394
3040a16c »
2010-04-23 added cookie-secret key generation example
395 - Cookie-Secret generation
396
397 What I use to generate the "cookie_secrect" key used in cyclone.web.Application's
398 settings is something pretty simple, like this::
399
828dda5d »
2010-09-09 added FAQ
400 >>> import uuid, base64
401 >>> base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
402 'FoQv5hgLTYCb9aKiBagpJJYtLJInWUcXilg3/vPkUnI='
3040a16c »
2010-04-23 added cookie-secret key generation example
403
f1d9df4d »
2010-01-24 updated docs
404
edc57fa7 »
2010-09-09 added FAQ
405 FAQ
406 ---
407
408 - Where are the request headers?
409
828dda5d »
2010-09-09 added FAQ
410 They are part of the request, dude::
edc57fa7 »
2010-09-09 added FAQ
411
4f8b2ea7 »
2010-09-09 added FAQ
412 class MyHandler(cyclone.web.RequestHandler):
413 def get(self):
414 # self.request.headers is a dict
415 user_agent = self.request.headers.get("User-Agent")
edc57fa7 »
2010-09-09 added FAQ
416
417 - How do I access raw POST data?
418
419 Both raw POST data and GET/DELETE un-parsed query string are available::
420
4f8b2ea7 »
2010-09-09 added FAQ
421 class MyHandler(cyclone.web.RequestHandler):
422 def get(self):
423 raw = self.request.query
edc57fa7 »
2010-09-09 added FAQ
424
4f8b2ea7 »
2010-09-09 added FAQ
425 def post(self):
426 raw = self.request.body
edc57fa7 »
2010-09-09 added FAQ
427
428 - Where is the request information, like remote IP address, HTTP method, URI and version?
429
430 Everything is available as request attributes::
431
4f8b2ea7 »
2010-09-09 added FAQ
432 class MyHandler(cyclone.web.RequestHandler):
433 def get(self):
434 remote_ip = self.request.remote_ip
435 method = self.request.method
436 uri = self.request.uri
437 version = self.request.version
edc57fa7 »
2010-09-09 added FAQ
438
439 - How do I set my own headers for the reply?
440
441 Guess what, use self.set_header(name, value)::
442
4f8b2ea7 »
2010-09-09 added FAQ
443 class MyHandler(cyclone.web.RequestHandler):
444 def get(self):
445 self.set_header("Content-Type", "application/json")
446 self.finish(cyclone.escape.json_encode({"success":True}))
edc57fa7 »
2010-09-09 added FAQ
447
448 - What HTTP methods are supported in RequestHandler?
449
c297fa0f »
2012-02-10 updated docs, and version
450 Well, almost all of them. HEAD, GET, POST, DELETE, PUT and OPTIONS are supported.
edc57fa7 »
2010-09-09 added FAQ
451 TRACE is disabled by default, because it may get you in trouble. CONNECT has nothing
452 to do with web servers, it's for proxies.
453
454 For more information on HTTP 1.1 methods, please refer to the `RFC 2612 Fielding, et al. <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html>`_.
455 For information regarding TRACE vulnerabilities, please check the following links:
c297fa0f »
2012-02-10 updated docs, and version
456 `What is HTTP TRACE? <http://www.cgisecurity.com/questions/httptrace.shtml>`_ and
edc57fa7 »
2010-09-09 added FAQ
457 `Apache Week, security issues <http://www.apacheweek.com/issues/03-01-24#news>`_.
458
4f8b2ea7 »
2010-09-09 added FAQ
459 Supporting different HTTP methods in the same RequestHandler is easy::
edc57fa7 »
2010-09-09 added FAQ
460
4f8b2ea7 »
2010-09-09 added FAQ
461 class MyHandler(cyclone.web.RequestHandler):
462 def get(self):
463 pass
edc57fa7 »
2010-09-09 added FAQ
464
4f8b2ea7 »
2010-09-09 added FAQ
465 def head(self):
466 pass
edc57fa7 »
2010-09-09 added FAQ
467
4f8b2ea7 »
2010-09-09 added FAQ
468 ...
edc57fa7 »
2010-09-09 added FAQ
469
470
a27e93b4 »
2010-03-01 added Credits
471 Credits
472 =======
473 Thanks to (in no particular order):
474
ffdf2f3a »
2010-04-04 added credits
475 - Nuswit Telephony API
476
5b575bfb »
2010-04-04 updated docs
477 - Granting permission for this code to be published and sponsoring
ffdf2f3a »
2010-04-04 added credits
478
a27e93b4 »
2010-03-01 added Credits
479 - Gleicon Moraes
c297fa0f »
2012-02-10 updated docs, and version
480
a27e93b4 »
2010-03-01 added Credits
481 - Testing and using it in the `RestMQ <http://github.com/gleicon/restmq>`_ web service
482
483 - Vanderson Mota
484
485 - Patching setup.py and PyPi maintenance
aa8e903d »
2010-06-11 added credits
486
487 - Andrew Badr
488
489 - Fixing auth bugs and adding current Tornado's features
536393ec »
2010-12-07 credits to jonoberheide
490
491 - Jon Oberheide
492
493 - Syncing code with Tornado and security features/fixes
1ad0f234 »
2011-01-27 Add name to credits and fix typo
494
495 - `Silas Sewell <https://github.com/silas>`_
496
497 - Syncing code and minor mail fix
c297fa0f »
2012-02-10 updated docs, and version
498
499 - `Twitter Bootstrap <https://github.com/twitter/bootstrap>`_
500
501 - For making our demo applications look good
dfb54115 »
2012-02-15 websocket keep-alive for draft 17
502
503 - `Dan Griffin <https://github.com/dgriff1>`_
504
505 - WebSocket Keep-Alive for OpDemand
641a8b4e »
2012-02-16 Update README.rst
506
507 - `Toby Padilla <https://github.com/tobypadilla>`_
508
a0ee0097 »
2012-02-19 xsrf control per RequestHandler
509 - WebSocket server
Something went wrong with that request. Please try again.