From 489a181cdbaca0d45aa87f7cea115f3caef9ead1 Mon Sep 17 00:00:00 2001 From: echel0n Date: Mon, 16 Jun 2014 03:44:33 -0700 Subject: [PATCH] Auto-reloads app on code changes automatically detected from git. Fixed issues with basicauth/cookies and login page. Parse results now displayed all the time. --- SickBeard.py | 21 +++++++++++++--- sickbeard/__init__.py | 12 ++++++++- sickbeard/name_parser/parser.py | 4 +++ sickbeard/postProcessor.py | 2 -- sickbeard/ui.py | 6 ++--- sickbeard/versionChecker.py | 4 +-- sickbeard/webserve.py | 44 ++++++++++----------------------- sickbeard/webserveInit.py | 10 ++++++-- 8 files changed, 59 insertions(+), 44 deletions(-) diff --git a/SickBeard.py b/SickBeard.py index fed90122..af30a552 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -18,8 +18,10 @@ # along with SickRage. If not, see . # Check needed software dependencies to nudge users to fix their setup +import functools import sys import tornado.ioloop +import tornado.autoreload if sys.version_info < (2, 6): print "Sorry, requires Python 2.6 or 2.7." @@ -151,6 +153,8 @@ def main(): TV for me """ + io_loop = IOLoop.current() + # do some preliminary stuff sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__)) sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME) @@ -381,10 +385,21 @@ def main(): sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable # init startup tasks - IOLoop.current().add_timeout(datetime.timedelta(seconds=5), startup) + io_loop.add_timeout(datetime.timedelta(seconds=5), startup) - # start IOLoop - IOLoop.current().start() + def autoreload_shutdown(): + logger.log('SickRage is now auto-reloading, please stand by ...') + webserveInit.server.stop() + sickbeard.halt() + sickbeard.saveAll() + sickbeard.cleanup_tornado_sockets(io_loop) + + # autoreload. + tornado.autoreload.start(io_loop) + tornado.autoreload.add_reload_hook(autoreload_shutdown) + + # start IOLoop. + io_loop.start() sickbeard.saveAndShutdown() return diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 2226a0f6..0d5336c5 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -1279,7 +1279,7 @@ def remove_pid_file(PIDFILE): def sig_handler(signum=None, frame=None): if type(signum) != type(None): logger.log(u"Signal %i caught, saving and exiting..." % int(signum)) - saveAndShutdown() + webserveInit.shutdown() def saveAll(): global showList @@ -1293,10 +1293,20 @@ def saveAll(): logger.log(u"Saving config file to disk") save_config() +def cleanup_tornado_sockets(io_loop): + for fd in io_loop._handlers.keys(): + try: + os.close(fd) + except Exception: + pass + def saveAndShutdown(): + halt() saveAll() + cleanup_tornado_sockets(IOLoop.current()) + if CREATEPID: logger.log(u"Removing pidfile " + str(PIDFILE)) remove_pid_file(PIDFILE) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 27f50829..4e4f0b60 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -369,6 +369,8 @@ class NameParser(object): if cache_result: name_parser_cache.add(name, final_result) + logger.log(u"Parsed " + name + " into " + str(final_result).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) + return final_result @@ -547,6 +549,8 @@ class ParseResult(object): self.episode_numbers = new_episode_numbers self.season_number = new_season_numbers[0] + logger.log(u"Converted parsed result " + self.original_name + " into " + str(self).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) + return self def _is_air_by_date(self): diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index ede9a8dd..a203d80a 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -481,8 +481,6 @@ class PostProcessor(object): np = NameParser(file, useIndexers=True, convert=True) parse_result = np.parse(name) - self._log(u"Parsed " + name + " into " + str(parse_result).decode('utf-8', 'xmlcharrefreplace'), logger.DEBUG) - # couldn't find this in our show list if not parse_result.show: return to_return diff --git a/sickbeard/ui.py b/sickbeard/ui.py index bd98bcc6..1d3c8a94 100644 --- a/sickbeard/ui.py +++ b/sickbeard/ui.py @@ -19,13 +19,13 @@ import datetime import sickbeard -from tornado.httputil import HTTPHeaders +from tornado.web import RequestHandler MESSAGE = 'notice' ERROR = 'error' -class Notifications(object): +class Notifications(RequestHandler): """ A queue of Notification objects. """ @@ -71,7 +71,7 @@ class Notifications(object): notifications = Notifications() -class Notification(object): +class Notification(RequestHandler): """ Represents a single notification. Tracks its own timeout and a list of which clients have seen it before. diff --git a/sickbeard/versionChecker.py b/sickbeard/versionChecker.py index e78d9cb4..067d79e0 100644 --- a/sickbeard/versionChecker.py +++ b/sickbeard/versionChecker.py @@ -58,8 +58,8 @@ class CheckVersion(): if sickbeard.AUTO_UPDATE: logger.log(u"New update found for SickRage, starting auto-updater ...") if sickbeard.versionCheckScheduler.action.update(): - logger.log(u"Update was successfull, restarting SickRage ...") - threading.Timer(2, sickbeard.invoke_restart, [False]).start() + logger.log(u"Update was successfull, auto-reloading SickRage ...") + #threading.Timer(2, sickbeard.invoke_restart, [False]).start() def find_install_type(self): """ diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 33ce3d48..8c3ccaae 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -105,15 +105,13 @@ def require_basic_auth(handler_class): return True auth_header = handler.request.headers.get('Authorization') - if auth_header is None or not auth_header.startswith('Basic '): - get_auth() - - auth_decoded = base64.decodestring(auth_header[6:]) - basicauth_user, basicauth_pass = auth_decoded.split(':', 2) - if basicauth_user == sickbeard.WEB_USERNAME and basicauth_pass == sickbeard.WEB_PASSWORD: - if not handler.get_secure_cookie("user"): - handler.set_secure_cookie("user", str(time.time())) - return True + if auth_header and auth_header.startswith('Basic '): + auth_decoded = base64.decodestring(auth_header[6:]) + basicauth_user, basicauth_pass = auth_decoded.split(':', 2) + if basicauth_user == sickbeard.WEB_USERNAME and basicauth_pass == sickbeard.WEB_PASSWORD: + if not handler.get_secure_cookie("user"): + handler.set_secure_cookie("user", str(time.time())) + return True handler.clear_cookie("user") get_auth() @@ -128,28 +126,12 @@ def require_basic_auth(handler_class): handler_class._execute = wrap_execute(handler_class._execute) return handler_class - +@require_basic_auth class RedirectHandler(RequestHandler): - """Redirects the client to the given URL for all GET requests. - You should provide the keyword argument ``url`` to the handler, e.g.:: - - application = web.Application([ - (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}), - ]) - """ - - def get(self, path): + def get(self, path, **kwargs): self.redirect(path, permanent=True) - -@require_basic_auth -class LoginHandler(RedirectHandler): - def get(self, path): - self.redirect(self.get_argument("next", u"/")) - - -@require_basic_auth class IndexHandler(RedirectHandler): def __init__(self, application, request, **kwargs): super(IndexHandler, self).__init__(application, request, **kwargs) @@ -171,10 +153,7 @@ class IndexHandler(RedirectHandler): return args def _dispatch(self): - """ - Load up the requested URL if it matches one of our own methods. - Skip methods that start with an underscore (_). - """ + args = None path = self.request.uri.split('?')[0] @@ -469,6 +448,9 @@ class IndexHandler(RedirectHandler): browser = WebFileBrowser +class LoginHandler(IndexHandler): + def get(self): + self.redirect(self.get_argument("next", u"/")) class PageTemplate(Template): def __init__(self, *args, **KWs): diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index f6e2ec30..797c06db 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -10,6 +10,8 @@ from sickbeard.helpers import create_https_certificates from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPError from tornado.httpserver import HTTPServer +server = None + class MultiStaticFileHandler(StaticFileHandler): def initialize(self, paths, default_filename=None): self.paths = paths @@ -95,10 +97,11 @@ def initWebServer(options={}): # Load the app app = Application([], - debug=True, + log_function=lambda x: None, + debug=False, gzip=True, autoreload=True, - xheaders=False, + xheaders=True, cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=', login_url='/login' ) @@ -140,9 +143,12 @@ def initWebServer(options={}): server.listen(options['port'], options['host']) def shutdown(): + global server + logger.log('Shutting down tornado') try: IOLoop.current().stop() + server.stop() except RuntimeError: pass except: