1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-08-13 16:53:54 -04:00

Improved async threading code for WebUI

This commit is contained in:
echel0n 2014-12-08 07:34:14 -08:00
parent d2b6145f8c
commit 46bd600da0
2 changed files with 65 additions and 39 deletions

View File

@ -17,8 +17,8 @@
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
from __future__ import with_statement
import threading
import threading
import traceback
import os
import time
@ -75,11 +75,31 @@ except ImportError:
from Cheetah.Template import Template
from functools import wraps
from tornado.routes import route
from tornado.web import RequestHandler, authenticated, asynchronous
from bug_tracker import BugTracker
route_locks = {}
def run_async(func):
@wraps(func)
def async_func(*args, **kwargs):
func_hl = threading.Thread(target = func, args = args, kwargs = kwargs)
func_hl.start()
return async_func
@run_async
def run_handler(route, kwargs, callback = None):
try:
res = route(**kwargs)
callback(res, route)
except:
logger.log('Failed doing api request "%s": %s' % (route, traceback.format_exc()), logger.ERROR)
callback({'success': False, 'error': 'Failed returning results'}, route)
def page_not_found(rh):
index_url = sickbeard.WEB_ROOT
url = rh.request.uri[len(index_url):]
@ -91,23 +111,6 @@ def page_not_found(rh):
rh.set_status(404)
rh.write('Wrong API key used')
class Worker(threading.Thread):
def __init__(self, func, params=None, callback=None, *args, **kwargs):
super(Worker, self).__init__(*args, **kwargs)
self.callback = callback
self.func = func
self.params = params
def run(self):
# Get response
resp = self.func(**self.params)
if resp:
# Issue callback
try:
self.callback(ek.ss(resp).encode('utf-8', 'xmlcharrefreplace'))
except:
self.callback(resp)
class PageTemplate(Template):
def __init__(self, rh, *args, **kwargs):
kwargs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/", kwargs['file'])
@ -260,31 +263,52 @@ class WebHandler(BaseHandler):
route = route.strip('/')
try:
route = getattr(self, route, self.index)
if not callable(route):
self.set_status(404)
self.write('Could not load webui module')
return
route = getattr(self, route)
except:
page_not_found(self)
return
route = getattr(self, 'index')
# Sanitize argument lists:
params = self.request.arguments
for arg, value in params.items():
if len(value) == 1:
params[arg] = value[0]
# acquire route lock
route_locks[route] = threading.Lock()
route_locks[route].acquire()
Worker(route, params, self.worker_done).start()
def worker_done(self, value):
try:
self.write(value)
# Sanitize argument lists:
kwargs = self.request.arguments
for arg, value in kwargs.items():
if len(value) == 1:
kwargs[arg] = value[0]
run_handler(route, kwargs, callback=self.taskFinished)
except:
route_locks[route].release()
page_not_found(self)
def taskFinished(self, result, route):
try:
if result:
# encode result data
result = ek.ss(result).encode('utf-8', 'xmlcharrefreplace')
# 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()
else:
self.write(result)
self.finish()
except UnicodeDecodeError:
logger.log('Failed proper encode: %s' % traceback.format_exc(), logger.ERROR)
except:
logger.log("Failed doing web request '%s': %s" % (route, traceback.format_exc()), logger.ERROR)
self.write({'success': False, 'error': 'Failed returning results'})
try:self.finish({'success': False, 'error': 'Failed returning results'})
except:pass
self.finish()
# release route lock
route_locks[route].release()
# link post to get
post = get

View File

@ -12,6 +12,7 @@ from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
from tornado.routes import route
class MultiStaticFileHandler(StaticFileHandler):
def initialize(self, paths, default_filename=None):
self.paths = paths
@ -76,7 +77,7 @@ class SRWebServer(threading.Thread):
if self.enable_https:
# If either the HTTPS certificate or key do not exist, make some self-signed ones.
if not (self.https_cert and os.path.exists(self.https_cert)) or not (
self.https_key and os.path.exists(self.https_key)):
self.https_key and os.path.exists(self.https_key)):
if not create_https_certificates(self.https_cert, self.https_key):
logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
sickbeard.ENABLE_HTTPS = False
@ -101,9 +102,10 @@ class SRWebServer(threading.Thread):
self.app.add_handlers(".*$", [
(r'%s(/?)' % self.options['api_root'], ApiHandler),
(r'%s/getkey(/?)' % self.options['web_root'], KeyHandler),
(r'%s/api/builder' % self.options['web_root'], RedirectHandler, {"url": self.options['web_root'] + '/apibuilder/'}),
(r'%s/api/builder' % self.options['web_root'], RedirectHandler,
{"url": self.options['web_root'] + '/apibuilder/'}),
(r'%s/login(/?)' % self.options['web_root'], LoginHandler),
(r'%s/logout(/?)' % self.options['web_root'], LogoutHandler)
(r'%s/logout(/?)' % self.options['web_root'], LogoutHandler),
] + route.get_routes())
# Static Path Handlers