From 40f01dca6f04eb48f0b9940774a3ba3cc834a2f4 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 2 Jun 2014 13:31:18 +0200 Subject: [PATCH 1/3] Use async request for all api calls --- couchpotato/api.py | 58 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/couchpotato/api.py b/couchpotato/api.py index f251841c..7b863559 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): From 3bd831782cac6a09b5132d6534601497d9f5e456 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 2 Jun 2014 14:02:55 +0200 Subject: [PATCH 2/3] Release lock inside thread --- couchpotato/api.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/couchpotato/api.py b/couchpotato/api.py index 7b863559..cd0bb046 100644 --- a/couchpotato/api.py +++ b/couchpotato/api.py @@ -33,10 +33,10 @@ def run_async(func): def run_handler(route, kwargs, callback = None): try: res = api[route](**kwargs) - callback(res) + callback(res, route) except: log.error('Failed doing api request "%s": %s', (route, traceback.format_exc())) - callback({'success': False, 'error': 'Failed returning results'}) + callback({'success': False, 'error': 'Failed returning results'}, route) # NonBlock API handler @@ -115,11 +115,11 @@ class ApiHandler(RequestHandler): self.write({'success': False, 'error': 'Failed returning results'}) self.finish() - api_locks[route].release() + api_locks[route].release() post = get - def taskFinished(self, result): + def taskFinished(self, result, route): if self.request.connection.stream.closed(): return @@ -142,6 +142,8 @@ class ApiHandler(RequestHandler): try: self.finish({'success': False, 'error': 'Failed returning results'}) except: pass + api_locks[route].release() + def addApiView(route, func, static = False, docs = None, **kwargs): From 0314910bbeb234a2a2cde0ab8033484324d9e7e1 Mon Sep 17 00:00:00 2001 From: Ruud Date: Mon, 2 Jun 2014 14:11:26 +0200 Subject: [PATCH 3/3] Don't migrate empty library items --- couchpotato/core/database.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/couchpotato/core/database.py b/couchpotato/core/database.py index 40b29285..1b9501c2 100644 --- a/couchpotato/core/database.py +++ b/couchpotato/core/database.py @@ -372,10 +372,10 @@ class Database(object): m = medias[x] status = statuses.get(m['status_id']).get('identifier') - l = libraries[m['library_id']] + l = libraries.get(m['library_id']) # Only migrate wanted movies, Skip if no identifier present - if not getImdb(l.get('identifier')): continue + if not l or not getImdb(l.get('identifier')): continue profile_id = profile_link.get(m['profile_id']) category_id = category_link.get(m['category_id'])