1import re 2from itertools import ifilter 3from functools import wraps 4from twisted.web.resource import Resource, NoResource 5 6class _FakeResource(Resource): 7 _result = '' 8 isLeaf = True 9 def __init__(self, result): 10 Resource.__init__(self) 11 self._result = result 12 def render(self, request): 13 return self._result 14 15 16def maybeResource(f): 17 @wraps(f) 18 def inner(*args, **kwargs): 19 result = f(*args, **kwargs) 20 if not isinstance(result, Resource): 21 result = _FakeResource(result) 22 return result 23 return inner 24 25 26class APIResource(Resource): 27 28 _registry = None 29 30 def __init__(self, *args, **kwargs): 31 Resource.__init__(self, *args, **kwargs) 32 self._registry = [] 33 34 def _get_callback(self, request): 35 filterf = lambda t:t[0] in (request.method, 'ALL') 36 path_to_check = getattr(request, '_remaining_path', request.path) 37 for m, r, cb in ifilter(filterf, self._registry): 38 result = r.search(path_to_check) 39 if result: 40 request._remaining_path = path_to_check[result.span()[1]:] 41 return cb, result.groupdict() 42 return None, None 43 44 def register(self, method, regex, callback): 45 self._registry.append((method, re.compile(regex), callback)) 46 47 def unregister(self, method=None, regex=None, callback=None): 48 if regex is not None: regex = re.compile(regex) 49 for m, r, cb in self._registry[:]: 50 if not method or (method and m==method): 51 if not regex or (regex and r==regex): 52 if not callback or (callback and cb==callback): 53 self._registry.remove((m, r, cb)) 54 55 def getChild(self, name, request): 56 r = self.children.get(name, None) 57 if r is None: 58 # Go into the thing 59 callback, args = self._get_callback(request) 60 if callback is None: 61 return NoResource() 62 else: 63 return maybeResource(callback)(request, **args) 64 else: 65 return r 66