from couchpotato.core.helpers.request import getParams from functools import wraps from threading import Thread from tornado.gen import coroutine from tornado.web import RequestHandler, asynchronous import json import threading import tornado import urllib api = {} api_locks = {} api_nonblock = {} api_docs = {} api_docs_missing = [] def run_async(func): @wraps(func) def async_func(*args, **kwargs): func_hl = Thread(target = func, args = args, kwargs = kwargs) func_hl.start() return func_hl return async_func # NonBlock API handler class NonBlockHandler(RequestHandler): stopper = None @asynchronous def get(self, route, *args, **kwargs): route = route.strip('/') start, stop = api_nonblock[route] self.stopper = stop start(self.onNewMessage, last_id = self.get_argument('last_id', None)) def onNewMessage(self, response): if self.request.connection.stream.closed(): return self.write(response) def on_connection_close(self): if self.stopper: self.stopper(self.onNewMessage) self.stopper = None def addNonBlockApiView(route, func_tuple, docs = None, **kwargs): api_nonblock[route] = func_tuple if docs: api_docs[route[4:] if route[0:4] == 'api.' else route] = docs else: api_docs_missing.append(route) # Blocking API handler class ApiHandler(RequestHandler): @coroutine def get(self, route, *args, **kwargs): route = route.strip('/') if not api.get(route): self.write('API call doesn\'t seem to exist') return api_locks[route].acquire() kwargs = {} for x in self.request.arguments: kwargs[x] = urllib.unquote(self.get_argument(x)) # Split array arguments kwargs = getParams(kwargs) # Remove t random string try: del kwargs['t'] except: pass # Add async callback handler @run_async def run_handler(callback): result = api[route](**kwargs) callback(result) result = yield tornado.gen.Task(run_handler) # Check JSONP callback jsonp_callback = self.get_argument('callback_func', default = None) if jsonp_callback: self.write(str(jsonp_callback) + '(' + json.dumps(result) + ')') elif isinstance(result, (tuple)) and result[0] == 'redirect': self.redirect(result[1]) else: self.write(result) api_locks[route].release() def addApiView(route, func, static = False, docs = None, **kwargs): if static: func(route) else: api[route] = func api_locks[route] = threading.Lock() if docs: api_docs[route[4:] if route[0:4] == 'api.' else route] = docs else: api_docs_missing.append(route)