Skip to content

Instantly share code, notes, and snippets.

@clayg
Created May 11, 2011 19:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save clayg/967119 to your computer and use it in GitHub Desktop.
Save clayg/967119 to your computer and use it in GitHub Desktop.
#! /usr/bin/env python
"""
My take on resource CRUD mapped to RESTful url handling
"""
import errno
import json
import os
from optparse import OptionParser
import sys
import time
from threading import Thread
from SocketServer import ThreadingMixIn
from wsgiref.simple_server import WSGIServer, make_server
from webob.dec import wsgify
from webob import exc
from webob import Response
def background(f, *args, **kwargs):
# this should be removed
orig_f = f
def new_f(*args, **kwargs):
time.sleep(4)
return orig_f(*args, **kwargs)
f = new_f
Thread(target=f, args=args, kwargs=kwargs).start()
class MultiThreadWSGIServer(ThreadingMixIn, WSGIServer):
multithread = True
class Controller(object):
collection_action_map = {
'POST': 'create',
'GET': 'list',
}
resource_action_map = {
'PUT': 'create',
'GET': 'read',
'POST': 'update',
'DELETE': 'delete',
}
def __call__(self, req):
id = req.path_info_pop()
if not id:
action_map = self.collection_action_map
else:
remainder = req.path_info_pop()
if remainder:
return exc.HTTPBadRequest()
action_map = self.resource_action_map
try:
action = action_map[req.method]
except KeyError:
return exc.HTTPMethodNotAllowed()
try:
rv = getattr(self, action)(id=id, **req.params)
except exc.HTTPException:
raise
if isinstance(rv, exc.HTTPException):
return rv
elif rv is None:
return Response()
else:
return Response(json.dumps(rv) + '\n')
def list(self, **kwargs):
return exc.HTTPMethodNotAllowed()
def create(self, id, **kwargs):
return exc.HTTPMethodNotAllowed()
def read(self, id, **kwargs):
return exc.HTTPMethodNotAllowed()
def update(self, id, **kwargs):
return exc.HTTPMethodNotAllowed()
def delete(self, id, **kwargs):
return exc.HTTPMethodNotAllowed()
class Application(object):
@wsgify
def __call__(self, req):
rtype = req.path_info_pop().lower()
try:
controller = getattr(self, rtype)
except AttributeError:
time.sleep(int(req.params.get('sleep', 0)))
return exc.HTTPNotFound()
return controller(self)(req)
class ObjectController(Controller):
def __init__(self, app):
self.app = app
def list(self, name=None, **kwargs):
objs = os.listdir(self.app.path)
if name:
objs = [x for x in objs if x == name]
return objs
def _get_path(self, id=''):
return os.path.join(self.app.path, id)
def create(self, id, **kwargs):
if not id:
raise exc.HTTPBadRequest()
kwargs['name'] = kwargs.get('name', id)
kwargs['status'] = kwargs.get('status', 'NEW')
with open(self._get_path(id), 'w') as f:
f.write(json.dumps(kwargs))
# start a background job before returning
background(self.update, id, status='ACTIVE')
return kwargs
def update(self, id, **kwargs):
with open(self._get_path(id)) as f:
merged_kwargs = json.loads(f.read())
merged_kwargs.update(kwargs)
with open(self._get_path(id), 'w') as f:
f.write(json.dumps(merged_kwargs))
return merged_kwargs
def read(self, id, **kwargs):
try:
with open(self._get_path(id)) as f:
return json.loads(f.read())
except IOError, e:
if e.errno == errno.ENOENT:
raise exc.HTTPNotFound()
raise
def delete(self, id, **kwargs):
try:
os.remove(self._get_path(id))
except OSError, e:
if e.errno != errno.ENOENT:
raise
class MyApp(Application):
object = ObjectController
def __init__(self, path):
self.path = path
def main():
parser = OptionParser('%prog [options]\n' + __doc__.rstrip())
parser.add_option('-p', '--port', type="int", default=8080,
help="set port for server to listen on")
parser.add_option('-d', '--dir', default='./web',
help="set dir to use for content")
options, args = parser.parse_args()
path = os.path.abspath(options.dir)
httpd = make_server('', options.port, MyApp(path),
server_class=MultiThreadWSGIServer)
print "Serving objects from %s on port %s..." % (path, options.port)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print 'user quit'
if __name__ == "__main__":
sys.exit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment