Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Working on dynamic handlers and modules

  • Loading branch information...
commit 8efc7c2bf133d77c976e99c1ee0297355bcff9d5 0 parents
@parente authored
24 README.rst
@@ -0,0 +1,24 @@
+===========
+Handler Bag
+===========
+
+:Author: Peter Parente
+:Description: A little layer on top of the Tornado web server to manage a bag of dynamic handlers.
+
+Requirements
+============
+
+* A server that can run Tornado web server
+
+Use
+===
+
+Run handlerbag.py --help on the server for options.
+
+License
+=======
+
+Copyright (c) 2010, Peter Parente All Rights Reserved.
+All rights reserved.
+
+http://creativecommons.org/licenses/BSD/
121 handlerbag.py
@@ -0,0 +1,121 @@
+'''
+Server that can load Python modules defining handlers mapped to URLs.
+
+:requires: Python 2.6, Tornado 1.0
+:copyright: Peter Parente 2010
+:license: BSD
+'''
+# tornado
+import tornado.web
+import tornado.httpserver
+from tornado.options import define, options
+# std lib
+import glob
+import os.path
+import shelve
+import sys
+# handlerbag
+import hbag
+
+class HandlerBag(tornado.web.Application):
+ def __init__(self, **kwargs):
+ # always enabled debug for auto reload
+ kwargs['debug'] = False
+ # load the bag db
+ self.db = shelve.open('hbdata')
+ # import dynamic module
+ self.modules = {}
+
+ # always load the admin handler
+ import hbag.admin as admin
+ handlers = hbag.admin.get_handler_map(options.webroot)
+ self.modules['admin'] = admin
+
+ # store paths
+ self.appPath = os.path.dirname(os.path.abspath(__file__))
+ self.bagPath = os.path.dirname(hbag.__file__)
+
+ # set the initial handlers and options
+ super(HandlerBag, self).__init__(handlers, **kwargs)
+
+ def shutdown(self):
+ # close the db cleanly
+ self.db.close()
+
+ def add_dynamic_handlers(self, host, handlers, pos=0):
+ handlers = None
+ for regex, h in self.handlers:
+ if regex.pattern == host_pattern:
+ handlers = h
+ break
+ if handlers is None:
+ raise ValueError('cannot extend handlers for unknown host')
+ for spec in host_handlers:
+ if type(spec) is type(()):
+ assert len(spec) in (2, 3)
+ pattern = spec[0]
+ handler = spec[1]
+ if len(spec) == 3:
+ kwargs = spec[2]
+ else:
+ kwargs = {}
+ spec = tornado.web.URLSpec(pattern, handler, kwargs)
+ handlers.insert(pos, spec)
+
+ def remove_dynamic_handler(self, host, url):
+ handlers = None
+ for regex, h in self.handlers:
+ if regex.pattern == host_pattern:
+ handlers = h
+ break
+ if handlers is None:
+ raise ValueError('cannot remove handler for unknown host')
+ i = 0
+ if not url_pattern.endswith('$'):
+ url_pattern += '$'
+ while i < len(handlers):
+ handler = handlers[i]
+ if handler.regex.pattern == url_pattern:
+ handlers.pop(i)
+ else:
+ i += 1
+
+ def refresh_handlers_in_db(self):
+ g = glob.glob(os.path.join(self.bagPath, '*'))
+ avail = set((os.path.basename(d) for d in g if os.path.isdir(d)))
+ known = set(self.db.keys())
+ new = avail - known
+ for name in new:
+ self.db[name] = {'enabled' : False, 'options' : {}}
+ old = known - avail
+ for name in old:
+ del self.db[name]
+ return self.db
+
+ def set_handler_status(self, name, enable):
+ # not a known handler
+ if not self.db.has_key(name): return
+ info = self.db[name]
+ # no change
+ if info['enabled'] == enable: return
+
+ # set the state in the db
+ info = self.db[name]
+ info['enabled'] = enable
+ self.db[name] = info
+
+ # check if module already loaded
+
+if __name__ == '__main__':
+ define('webroot', default='/', help='absolute root url of all handlers (default: /)')
+ define('port', default=5000, type=int, help='drop server port (default: 5000)')
+ tornado.options.parse_command_line()
+
+ application = HandlerBag()
+ http_server = tornado.httpserver.HTTPServer(application)
+ http_server.listen(options.port)
+ ioloop = tornado.ioloop.IOLoop.instance()
+ try:
+ ioloop.start()
+ finally:
+ application.shutdown()
0  hbag/__init__.py
No changes.
7 hbag/admin/__init__.py
@@ -0,0 +1,7 @@
+from admin import AdminHandler
+
+def get_handler_map(webroot):
+ return [(webroot+'admin/?', AdminHandler)]
+
+def get_handler_opts():
+ return {}
51 hbag/admin/admin.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Handler Bag Admin</title>
+ <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/dojo/1.5/dojo/dojo.xd.js"></script>
+ <script type="text/javascript">
+ var tok;
+ function save() {
+ var cbs = dojo.query('[type="checkbox"]');
+ var status = dojo.byId('status');
+ var data = {};
+ cbs.forEach(function(item) {
+ var key = dojo.attr(item, 'id');
+ var val = dojo.attr(item, 'checked');
+ data[key] = val;
+ });
+ clearTimeout(tok);
+ status.innerHTML = 'Saving ...'
+ dojo.xhrPost({
+ url : '',
+ headers : {'Content-Type' : 'application/json'},
+ postData : dojo.toJson(data)
+ }).then(function() {
+ status.innerHTML = 'Saved';
+ tok = setTimeout(function() { status.innerHTML = ''; }, 2000);
+ }, function() {
+ status.innerHTML = 'Failed';
+ tok = setTimeout(function() { status.innerHTML = ''; }, 2000);
+ });
+
+ }
+ function reset() {
+ window.location.reload();
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Handler Bag Admin</h1>
+ <fieldset>
+ <legend>Enabled Handlers</legend>
+ {% for key, info in items %}
+ <p>
+ <input type="checkbox" id="{{ key }}" {{ 'checked' if info['enabled'] else '' }}/>
+ <label for="{{ key }}">{{ escape(key) }}</label>
+ </p>
+ {% end %}
+ </fieldset>
+ <button onclick="save();">Save</button> <button onclick="reset();">Reset</button> <span id="status"></span>
+ </body>
+</html>
24 hbag/admin/admin.py
@@ -0,0 +1,24 @@
+'''
+
+
+:requires: Python 2.6, Tornado 1.0
+:copyright: Peter Parente 2010
+:license: BSD
+'''
+# tornado
+import tornado.web
+# std lib
+import json
+
+class AdminHandler(tornado.web.RequestHandler):
+ def get(self, *args, **kwargs):
+ # force update of handler list
+ db = self.application.refresh_handlers_in_db()
+ # show all handlers but ourselves
+ items = (item for item in db.iteritems() if item[0] != 'admin')
+ self.render('admin.html', items=items)
+
+ def post(self, *args, **kwargs):
+ obj = json.loads(self.request.body)
+ for name, enabled in obj.iteritems():
+ self.application.set_handler_status(name, enabled)
4 hbag/xhrdrop/__init__.py
@@ -0,0 +1,4 @@
+from xhrdrop import DropHandler
+
+def get_handler_map(webroot):
+ return [(webroot+'xhrdrop', DropHandler)]
Please sign in to comment.
Something went wrong with that request. Please try again.