From f81b15b5f7d787ad9e0533c5cdf1af2fefa4db2d Mon Sep 17 00:00:00 2001 From: Alexandre Fiori Date: Tue, 15 Nov 2011 15:12:53 -0500 Subject: [PATCH] updated bottle support and demo --- cyclone/bottle.py | 23 ++++-- demos/bottle/bottle.py | 32 +------- demos/bottle/complete.py | 136 ++++++++++++++++++++++++++++++++++ demos/bottle/xmlrpc_client.py | 22 ++++++ 4 files changed, 176 insertions(+), 37 deletions(-) create mode 100755 demos/bottle/complete.py create mode 100644 demos/bottle/xmlrpc_client.py diff --git a/cyclone/bottle.py b/cyclone/bottle.py index 7e5e0608e2..ca2621b050 100644 --- a/cyclone/bottle.py +++ b/cyclone/bottle.py @@ -22,7 +22,8 @@ from twisted.python import log from twisted.internet import reactor -__handlers = [] +_handlers = [] +_BaseHandler = None class Router: def __init__(self): @@ -32,7 +33,7 @@ def add(self, method, callback): self.items.append((method, callback)) def __call__(self, *args, **kwargs): - obj = cyclone.web.RequestHandler(*args, **kwargs) + obj = _BaseHandler(*args, **kwargs) for (method, callback) in self.items: callback = functools.partial(callback, obj) setattr(obj, method.lower(), callback) @@ -43,22 +44,28 @@ def route(path=None, method="GET", callback=None, **kwargs): path, callback = None, path def decorator(callback): - __handlers.append((path, method, callback, kwargs)) + _handlers.append((path, method, callback, kwargs)) return callback return decorator def run(**settings): + global _handlers, _BaseHandler + port = settings.get("port", 8888) + interface = settings.get("host", "127.0.0.1") + log.startLogging(settings.pop("log", sys.stdout)) + _BaseHandler = settings.pop("base_handler", cyclone.web.RequestHandler) + handlers = {} - for (path, method, callback, kwargs) in __handlers: + for (path, method, callback, kwargs) in _handlers: if path not in handlers: handlers[path] = Router() handlers[path].add(method, callback) - log.startLogging(settings.get("log", sys.stdout)) - application = cyclone.web.Application(handlers.items(), **settings) - port = settings.get("port", 8888) - interface = settings.get("host", "127.0.0.1") + _handlers = None + + handlers = handlers.items() + settings.pop("more_handlers", []) + application = cyclone.web.Application(handlers, **settings) reactor.listenTCP(port, application, interface=interface) reactor.run() diff --git a/demos/bottle/bottle.py b/demos/bottle/bottle.py index 5c121a803b..2be55ce385 100755 --- a/demos/bottle/bottle.py +++ b/demos/bottle/bottle.py @@ -16,47 +16,21 @@ # License for the specific language governing permissions and limitations # under the License. - import sys -import cyclone.redis import cyclone.sqlite from cyclone.bottle import run, route -from twisted.internet import defer @route("/") def index(web): - web.write("try /sqlite or /redis\r\n") - + web.write("try /sqlite\r\n") @route("/sqlite") def sqlite_get(web): v = web.settings.sqlite.runQuery("select strftime('%Y-%m-%d')") web.write("today is " + repr(v) + "\r\n") - -@route("/redis") -@defer.inlineCallbacks -def redis_get(web): - try: - v = yield web.settings.redis.get("foo") - web.write("foo = " + repr(v) + "\r\n") - except: - raise cyclone.web.HTTPError(503) - -@route("/redis", method="POST") -@defer.inlineCallbacks -def redis_set(web): - try: - foo = web.get_argument("foo", "null") - yield web.settings.redis.set("foo", foo) - web.write("OK\r\n") - except: - raise cyclone.web.HTTPError(503) - - -run(host="localhost", port=8080, +run(host="127.0.0.1", port=8080, log=sys.stdout, # or any file descriptor static_path="static", template_path="template", - sqlite=cyclone.sqlite.InlineSQLite(":memory:"), - redis=cyclone.redis.lazyRedisConnectionPool()) + sqlite=cyclone.sqlite.InlineSQLite(":memory:")) diff --git a/demos/bottle/complete.py b/demos/bottle/complete.py new file mode 100755 index 0000000000..13f9c64d14 --- /dev/null +++ b/demos/bottle/complete.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# coding: utf-8 +# +# Copyright 2011 Alexandre Fiori +# based on the original Tornado by Facebook +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import cyclone.escape +import cyclone.redis +import cyclone.sqlite +import cyclone.web +from cyclone.bottle import run, route +from twisted.internet import defer + +class BaseHandler(cyclone.web.RequestHandler): + def get_current_user(self): + print "Getting user cookie" + return self.get_secure_cookie("user") + + +@route("/") +def index(req): + req.write("""try /sqlite, /redis or sign in""") + + +@route("/auth/login") +def auth_login_page(req): + req.write(""" +
+ username:
+ password:
+ +
+ """) + +@route("/auth/login", method="POST") +def auth_login(req): + user = req.get_argument("user") + passwd = req.get_argument("passwd") + next = req.get_argument("next", "/private") + # assert user=="foo" and passwd=="bar" + req.set_secure_cookie("user", user) + req.redirect(next) + +@route("/auth/logout") +@cyclone.web.authenticated +def auth_logout(req): + req.clear_cookie("user") + req.redirect("/") + +@route("/private") +@cyclone.web.authenticated +def private(req): + req.write("current user is: %s
" % repr(req.current_user)) + req.write("""logout""") + + +@route("/sqlite") +def sqlite_get(req): + v = req.settings.sqlite.runQuery("select strftime('%Y-%m-%d')") + req.write("today is " + repr(v) + "\r\n") + + +@route("/redis") +@defer.inlineCallbacks +def redis_get(req): + try: + v = yield req.settings.redis.get("foo") + req.write("foo = " + repr(v) + "\r\n") + except: + raise cyclone.web.HTTPError(503) + +@route("/redis", method="POST") +@defer.inlineCallbacks +def redis_set(req): + try: + foo = req.get_argument("foo", "null") + yield req.settings.redis.set("foo", foo) + req.write("OK\r\n") + except: + raise cyclone.web.HTTPError(503) + + +class WebSocketHandler(cyclone.web.WebSocketHandler): + def connectionMade(self, *args, **kwargs): + print "connection made:", args, kwargs + + def messageReceived(self, message): + self.sendMessage("echo: %s" % message) + + def connectionLost(self, why): + print "connection lost:", why + + +class XmlrpcHandler(cyclone.web.XmlrpcRequestHandler): + allowNone = True + + def xmlrpc_echo(self, text): + return text + + +try: + raise COMMENT_THIS_LINE_AND_LOG_TO_DAILY_FILE + from twisted.python.logfile import DailyLogFile + logFile = DailyLogFile.fromFullPath("server.log") + print("Logging to daily log file: server.log") +except Exception, e: + import sys + logFile = sys.stdout + +run(host="127.0.0.1", port=8080, + log=logFile, + static_path="static", + template_path="template", + locale_path="locale", + sqlite=cyclone.sqlite.InlineSQLite(":memory:"), + redis=cyclone.redis.lazyRedisConnectionPool(), + base_handler=BaseHandler, + cookie_secret="32oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=", + login_url="/auth/login", + more_handlers=[ + (r"/websocket", WebSocketHandler), + (r"/xmlrpc", XmlrpcHandler), + ]) + diff --git a/demos/bottle/xmlrpc_client.py b/demos/bottle/xmlrpc_client.py new file mode 100644 index 0000000000..7e74bc447a --- /dev/null +++ b/demos/bottle/xmlrpc_client.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +# coding: utf-8 +# +# Copyright 2010 Alexandre Fiori +# based on the original Tornado by Facebook +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import xmlrpclib + +srv = xmlrpclib.Server("http://localhost:8080/xmlrpc") +print "echo:", srv.echo("hello world!")