diff --git a/SickBeard.py b/SickBeard.py index 8da08582..73da7602 100755 --- a/SickBeard.py +++ b/SickBeard.py @@ -54,10 +54,10 @@ import getopt import sickbeard -from sickbeard.webserveInit import webserverInit from sickbeard import db from sickbeard.tv import TVShow from sickbeard import logger +from sickbeard import webserveInit from sickbeard.version import SICKBEARD_VERSION from sickbeard.databases.mainDB import MIN_DB_VERSION from sickbeard.databases.mainDB import MAX_DB_VERSION @@ -146,13 +146,6 @@ def daemonize(): os.dup2(stdout.fileno(), sys.stdout.fileno()) os.dup2(stderr.fileno(), sys.stderr.fileno()) - -# background update every x seconds -def invoke_command(): - if sickbeard.invoked_command: - sickbeard.invoked_command() - sickbeard.invoked_command = None - def main(): """ TV for me @@ -368,11 +361,14 @@ def main(): 'https_key': sickbeard.HTTPS_KEY, } - def startup(): - # Build from the DB to start with - logger.log(u"Loading initial show list") - loadShowsFromDB() + # init tornado + webserveInit.initWebServer(options) + # Build from the DB to start with + logger.log(u"Loading initial show list") + loadShowsFromDB() + + def startup(): # Fire up all our threads sickbeard.start() @@ -384,17 +380,11 @@ def main(): if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START: sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable - # init tornado - sickbeard.WEBSERVER = webserverInit(options) - sickbeard.WEBSERVER.ioloop.add_timeout(datetime.timedelta(seconds=5), startup) + # init startup tasks + IOLoop.current().add_timeout(datetime.timedelta(seconds=5), startup) - # check for commands to be executed in the background - task = PeriodicCallback(invoke_command, 1000) - sickbeard.WEBSERVER.tasks.append(task) - - # start tornado - sickbeard.WEBSERVER.start() - sickbeard.WEBSERVER.close() + # start IOLoop + IOLoop.current().start() return if __name__ == "__main__": diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 8ebf4c8e..1280dd81 100644 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -53,8 +53,6 @@ from lib.configobj import ConfigObj from tornado.ioloop import IOLoop import xml.etree.ElementTree as ElementTree -invoked_command = None - PID = None CFG = None @@ -77,7 +75,6 @@ PIDFILE = '' DAEMON = None NO_RESIZE = False -WEBSERVER = None maintenanceScheduler = None dailySearchScheduler = None @@ -1117,15 +1114,12 @@ def start(): showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ subtitlesFinderScheduler, USE_SUBTITLES,traktWatchListCheckerScheduler, \ - dailySearchScheduler, WEBSERVER, started + dailySearchScheduler, started with INIT_LOCK: if __INITIALIZED__: - # start IOLoop tasks - WEBSERVER.start_tasks() - # start the maintenance scheduler maintenanceScheduler.thread.start() logger.log(u"Performing initial maintenance tasks, please wait ...") @@ -1171,7 +1165,7 @@ def halt(): showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ subtitlesFinderScheduler, traktWatchListCheckerScheduler, \ - dailySearchScheduler, WEBSERVER, started + dailySearchScheduler, started with INIT_LOCK: @@ -1181,8 +1175,6 @@ def halt(): # abort all the threads - WEBSERVER.stop_tasks() - maintenanceScheduler.abort = True logger.log(u"Waiting for the MAINTENANCE scheduler thread to exit") try: @@ -1190,6 +1182,13 @@ def halt(): except: pass + dailySearchScheduler.abort = True + logger.log(u"Waiting for the DAILYSEARCH thread to exit") + try: + dailySearchScheduler.thread.join(10) + except: + pass + backlogSearchScheduler.abort = True logger.log(u"Waiting for the BACKLOG thread to exit") try: @@ -1281,7 +1280,6 @@ def sig_handler(signum=None, frame=None): logger.log(u"Signal %i caught, saving and exiting..." % int(signum)) saveAndShutdown() - def saveAll(): global showList @@ -1294,21 +1292,19 @@ def saveAll(): logger.log(u"Saving config file to disk") save_config() - def saveAndShutdown(restart=False): - global WEBSERVER - - halt() - saveAll() logger.log('Shutting down tornado') try: - WEBSERVER.stop() + IOLoop.current().stop() except RuntimeError: pass except: logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR) + halt() + saveAll() + if CREATEPID: logger.log(u"Removing pidfile " + str(PIDFILE)) remove_pid_file(PIDFILE) @@ -1341,17 +1337,15 @@ def saveAndShutdown(restart=False): os._exit(0) - def invoke_command(to_call, *args, **kwargs): - global invoked_command def delegate(): to_call(*args, **kwargs) - invoked_command = delegate - logger.log(u"Placed invoked command: " + repr(invoked_command) + " for " + repr(to_call) + " with " + repr( + logger.log(u"Placed invoked command: " + repr(delegate) + " for " + repr(to_call) + " with " + repr( args) + " and " + repr(kwargs), logger.DEBUG) + IOLoop.current().add_callback(delegate) def invoke_restart(soft=True): invoke_command(restart, soft=soft) diff --git a/sickbeard/webserveInit.py b/sickbeard/webserveInit.py index d2d0f0ff..577ce516 100644 --- a/sickbeard/webserveInit.py +++ b/sickbeard/webserveInit.py @@ -1,5 +1,4 @@ import os -import datetime import sickbeard import webserve @@ -7,7 +6,6 @@ from sickbeard import logger from sickbeard.helpers import create_https_certificates from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPError from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop class MultiStaticFileHandler(StaticFileHandler): def initialize(self, paths, default_filename=None): @@ -29,139 +27,108 @@ class MultiStaticFileHandler(StaticFileHandler): # Oops file not found anywhere! raise HTTPError(404) +def initWebServer(options={}): + options.setdefault('port', 8081) + options.setdefault('host', '0.0.0.0') + options.setdefault('log_dir', None) + options.setdefault('username', '') + options.setdefault('password', '') + options.setdefault('web_root', '/') + assert isinstance(options['port'], int) + assert 'data_root' in options -class webserverInit(): - def __init__(self, options, cycleTime=datetime.timedelta(seconds=3)): + def http_error_401_hander(status, message, traceback, version): + """ Custom handler for 401 error """ + if status != "401 Unauthorized": + logger.log(u"Tornado caught an error: %s %s" % (status, message), logger.ERROR) + logger.log(traceback, logger.DEBUG) + return r''' + + + %s + + +
+ Error %s: You need to provide a valid username and password. + + +''' % ('Access denied', status) - self.amActive = False - self.lastRun = datetime.datetime.fromordinal(1) - self.cycleTime = cycleTime - self.abort = False + def http_error_404_hander(status, message, traceback, version): + """ Custom handler for 404 error, redirect back to main page """ + return r''' + + + 404 + + + +
+ + +''' % options['web_root'] - self.server = None - self.ioloop = None - self.tasks = [] + # tornado setup + enable_https = options['enable_https'] + https_cert = options['https_cert'] + https_key = options['https_key'] - self.options = options - self.options.setdefault('port', 8081) - self.options.setdefault('host', '0.0.0.0') - self.options.setdefault('log_dir', None) - self.options.setdefault('username', '') - self.options.setdefault('password', '') - self.options.setdefault('web_root', '/') - assert isinstance(self.options['port'], int) - assert 'data_root' in self.options - - def http_error_401_hander(status, message, traceback, version): - """ Custom handler for 401 error """ - if status != "401 Unauthorized": - logger.log(u"Tornado caught an error: %s %s" % (status, message), logger.ERROR) - logger.log(traceback, logger.DEBUG) - return r''' - - - %s - - -
- Error %s: You need to provide a valid username and password. - - - ''' % ('Access denied', status) - - def http_error_404_hander(status, message, traceback, version): - """ Custom handler for 404 error, redirect back to main page """ - return r''' - - - 404 - - - -
- - - ''' % self.options['web_root'] - - # tornado setup - enable_https = self.options['enable_https'] - https_cert = self.options['https_cert'] - https_key = self.options['https_key'] - - if enable_https: - # If either the HTTPS certificate or key do not exist, make some self-signed ones. - if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)): - if not create_https_certificates(https_cert, https_key): - logger.log(u"Unable to create CERT/KEY files, disabling HTTPS") - sickbeard.ENABLE_HTTPS = False - enable_https = False - - if not (os.path.exists(https_cert) and os.path.exists(https_key)): - logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING) + if enable_https: + # If either the HTTPS certificate or key do not exist, make some self-signed ones. + if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)): + if not create_https_certificates(https_cert, https_key): + logger.log(u"Unable to create CERT/KEY files, disabling HTTPS") sickbeard.ENABLE_HTTPS = False enable_https = False - # Load the app - app = Application([], - log_function=lambda x: None, - debug=False, - gzip=True, - cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=', - login_url='/login', - autoreload=True - ) + if not (os.path.exists(https_cert) and os.path.exists(https_key)): + logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING) + sickbeard.ENABLE_HTTPS = False + enable_https = False - # Index Handler - app.add_handlers(".*$", [ - (r"/", RedirectHandler, {'url': '/home/'}), - (r'/login', webserve.LoginHandler), - (r'%s(.*)(/?)' % self.options['web_root'], webserve.IndexHandler) - ]) + # Load the app + app = Application([], + debug=False, + gzip=True, + cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=', + login_url='/login' + ) - # Static Path Handler - app.add_handlers(".*$", [ - ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'images'), MultiStaticFileHandler, - {'paths': [os.path.join(self.options['data_root'], 'images'), - os.path.join(sickbeard.CACHE_DIR, 'images'), - os.path.join(sickbeard.CACHE_DIR, 'images', 'thumbnails')]}), - ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'css'), MultiStaticFileHandler, - {'paths': [os.path.join(self.options['data_root'], 'css')]}), - ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'js'), MultiStaticFileHandler, - {'paths': [os.path.join(self.options['data_root'], 'js')]}) + # Index Handler + app.add_handlers(".*$", [ + (r"/", RedirectHandler, {'url': '/home/'}), + (r'/login', webserve.LoginHandler), + (r'%s(.*)(/?)' % options['web_root'], webserve.IndexHandler) + ]) - ]) + # Static Path Handler + app.add_handlers(".*$", [ + ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'images'), MultiStaticFileHandler, + {'paths': [os.path.join(options['data_root'], 'images'), + os.path.join(sickbeard.CACHE_DIR, 'images'), + os.path.join(sickbeard.CACHE_DIR, 'images', 'thumbnails')]}), + ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'css'), MultiStaticFileHandler, + {'paths': [os.path.join(options['data_root'], 'css')]}), + ('%s/%s/(.*)([^/]*)' % (options['web_root'], 'js'), MultiStaticFileHandler, + {'paths': [os.path.join(options['data_root'], 'js')]}) - if enable_https: - protocol = "https" - self.server = HTTPServer(app, no_keep_alive=True, - ssl_options={"certfile": https_cert, "keyfile": https_key}) - else: - protocol = "http" - self.server = HTTPServer(app, no_keep_alive=True) + ]) - logger.log(u"Starting SickRage on " + protocol + "://" + str(self.options['host']) + ":" + str( - self.options['port']) + "/") + global server - self.ioloop = IOLoop.current() + if enable_https: + protocol = "https" + server = HTTPServer(app, no_keep_alive=True, + ssl_options={"certfile": https_cert, "keyfile": https_key}) + else: + protocol = "http" + server = HTTPServer(app, no_keep_alive=True) - def start(self): - self.server.listen(self.options['port'], self.options['host']) - self.ioloop.start() + logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str( + options['port']) + "/") - def stop(self): - self.ioloop.stop() - - def close(self): - self.ioloop.close() - - def start_tasks(self): - for task in self.tasks: - task.start() - - def stop_tasks(self): - for task in self.tasks: - task.stop() + server.listen(options['port'], options['host']) \ No newline at end of file