diff --git a/couchpotato/api.py b/couchpotato/api.py index f251841..7b86355 100644 --- a/couchpotato/api.py +++ b/couchpotato/api.py @@ -1,3 +1,5 @@ +from functools import wraps +from threading import Thread import json import threading import traceback @@ -5,7 +7,6 @@ import urllib from couchpotato.core.helpers.request import getParams from couchpotato.core.logger import CPLog -from tornado.gen import coroutine from tornado.web import RequestHandler, asynchronous @@ -20,6 +21,24 @@ 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 async_func + +@run_async +def run_handler(route, kwargs, callback = None): + try: + res = api[route](**kwargs) + callback(res) + except: + log.error('Failed doing api request "%s": %s', (route, traceback.format_exc())) + callback({'success': False, 'error': 'Failed returning results'}) + + # NonBlock API handler class NonBlockHandler(RequestHandler): @@ -65,7 +84,7 @@ def addNonBlockApiView(route, func_tuple, docs = None, **kwargs): # Blocking API handler class ApiHandler(RequestHandler): - @coroutine + @asynchronous def get(self, route, *args, **kwargs): route = route.strip('/') if not api.get(route): @@ -88,31 +107,40 @@ class ApiHandler(RequestHandler): try: del kwargs['t'] except: pass - # Fire api handler(s) - try: - result = api[route](**kwargs) - except: - log.error('Failed doing api request "%s": %s', (route, traceback.format_exc())) - result = {'success': False, 'error': 'Failed returning results'} + # Add async callback handler + run_handler(route, kwargs, callback = self.taskFinished) + + except: + log.error('Failed doing api request "%s": %s', (route, traceback.format_exc())) + self.write({'success': False, 'error': 'Failed returning results'}) + self.finish() + + api_locks[route].release() + + post = get + + def taskFinished(self, result): + if self.request.connection.stream.closed(): + return + + try: # Check JSONP callback jsonp_callback = self.get_argument('callback_func', default = None) if jsonp_callback: self.write(str(jsonp_callback) + '(' + json.dumps(result) + ')') self.set_header("Content-Type", "text/javascript") + self.finish() elif isinstance(result, tuple) and result[0] == 'redirect': self.redirect(result[1]) else: self.write(result) - + self.finish() except: - log.error('Failed doing api request "%s": %s', (route, traceback.format_exc())) - self.write({'success': False, 'error': 'Failed returning results'}) - - api_locks[route].release() - - post = get + log.debug('Failed doing request, probably already closed: %s', (traceback.format_exc())) + try: self.finish({'success': False, 'error': 'Failed returning results'}) + except: pass def addApiView(route, func, static = False, docs = None, **kwargs):