1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-12-13 11:32:20 -05:00

Improved startup/shutdown of tornado.

Fixed issues with notifications related to tornado.
This commit is contained in:
echel0n 2014-06-15 00:16:55 -07:00
parent 04681b3297
commit abff43f568
5 changed files with 135 additions and 101 deletions

View File

@ -361,12 +361,8 @@ def main():
'https_key': sickbeard.HTTPS_KEY, 'https_key': sickbeard.HTTPS_KEY,
} }
# init tornado web server # init tornado server
sickbeard.webserveInitScheduler = sickbeard.scheduler.Scheduler(webserverInit(options), sickbeard.WEBSERVER = webserverInit(options)
cycleTime=datetime.timedelta(seconds=3),
threadName="TORNADO",
silent=True,
runImmediately=True)
# Build from the DB to start with # Build from the DB to start with
logger.log(u"Loading initial show list") logger.log(u"Loading initial show list")
@ -375,6 +371,9 @@ def main():
# Fire up all our threads # Fire up all our threads
sickbeard.start() sickbeard.start()
# start tornado thread
sickbeard.WEBSERVER.thread.start()
# Launch browser if we're supposed to # Launch browser if we're supposed to
if sickbeard.LAUNCH_BROWSER and not noLaunch and not sickbeard.DAEMON: if sickbeard.LAUNCH_BROWSER and not noLaunch and not sickbeard.DAEMON:
sickbeard.launchBrowser(startPort) sickbeard.launchBrowser(startPort)

View File

@ -29,7 +29,7 @@ from urllib2 import getproxies
from threading import Lock from threading import Lock
# apparently py2exe won't build these unless they're imported somewhere # apparently py2exe won't build these unless they're imported somewhere
from sickbeard import providers, metadata, config from sickbeard import providers, metadata, config, webserveInit
from sickbeard.providers.generic import GenericProvider from sickbeard.providers.generic import GenericProvider
from providers import ezrss, tvtorrents, btn, newznab, womble, thepiratebay, torrentleech, kat, iptorrents, \ from providers import ezrss, tvtorrents, btn, newznab, womble, thepiratebay, torrentleech, kat, iptorrents, \
omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, nextgen, speedcd, nyaatorrents, fanzub omgwtfnzbs, scc, hdtorrents, torrentday, hdbits, nextgen, speedcd, nyaatorrents, fanzub
@ -77,6 +77,7 @@ PIDFILE = ''
DAEMON = None DAEMON = None
NO_RESIZE = False NO_RESIZE = False
WEBSERVER = None
maintenanceScheduler = None maintenanceScheduler = None
dailySearchScheduler = None dailySearchScheduler = None
@ -89,7 +90,6 @@ properFinderScheduler = None
autoPostProcesserScheduler = None autoPostProcesserScheduler = None
subtitlesFinderScheduler = None subtitlesFinderScheduler = None
traktWatchListCheckerScheduler = None traktWatchListCheckerScheduler = None
webserveInitScheduler = None
showList = None showList = None
loadingShowList = None loadingShowList = None
@ -479,7 +479,7 @@ def initialize(consoleLogging=True):
USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, REMOTE_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, \ USE_FAILED_DOWNLOADS, DELETE_FAILED, ANON_REDIRECT, LOCALHOST_IP, REMOTE_IP, TMDB_API_KEY, DEBUG, PROXY_SETTING, \
AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \ AUTOPOSTPROCESSER_FREQUENCY, DEFAULT_AUTOPOSTPROCESSER_FREQUENCY, MIN_AUTOPOSTPROCESSER_FREQUENCY, \
ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \ ANIME_DEFAULT, NAMING_ANIME, ANIMESUPPORT, USE_ANIDB, ANIDB_USERNAME, ANIDB_PASSWORD, ANIDB_USE_MYLIST, \
ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT, WEB_DATA_ROOT, webserveInitScheduler ANIME_SPLIT_HOME, maintenanceScheduler, SCENE_DEFAULT, WEB_DATA_ROOT, WEBSERVER
if __INITIALIZED__: if __INITIALIZED__:
return False return False
@ -1119,15 +1119,12 @@ def start():
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, USE_SUBTITLES,traktWatchListCheckerScheduler, \ subtitlesFinderScheduler, USE_SUBTITLES,traktWatchListCheckerScheduler, \
dailySearchScheduler, webserveInitScheduler, started dailySearchScheduler, started
with INIT_LOCK: with INIT_LOCK:
if __INITIALIZED__: if __INITIALIZED__:
# start tornado web server
webserveInitScheduler.thread.start()
# start the maintenance scheduler # start the maintenance scheduler
maintenanceScheduler.thread.start() maintenanceScheduler.thread.start()
logger.log(u"Performing initial maintenance tasks, please wait ...") logger.log(u"Performing initial maintenance tasks, please wait ...")
@ -1173,7 +1170,7 @@ def halt():
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \ showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \ properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
subtitlesFinderScheduler, traktWatchListCheckerScheduler, \ subtitlesFinderScheduler, traktWatchListCheckerScheduler, \
dailySearchScheduler, webserveInitScheduler, started dailySearchScheduler, started
with INIT_LOCK: with INIT_LOCK:
@ -1183,13 +1180,6 @@ def halt():
# abort all the threads # abort all the threads
webserveInitScheduler.about = True
logger.log(u"Waiting for the TORNADO thread to exit")
try:
webserveInitScheduler.thread.join(10)
except:
pass
maintenanceScheduler.abort = True maintenanceScheduler.abort = True
logger.log(u"Waiting for the MAINTENANCE scheduler thread to exit") logger.log(u"Waiting for the MAINTENANCE scheduler thread to exit")
try: try:
@ -1197,13 +1187,6 @@ def halt():
except: except:
pass pass
dailySearchScheduler.abort = True
logger.log(u"Waiting for the DAILYSEARCHER thread to exit")
try:
dailySearchScheduler.thread.join(10)
except:
pass
backlogSearchScheduler.abort = True backlogSearchScheduler.abort = True
logger.log(u"Waiting for the BACKLOG thread to exit") logger.log(u"Waiting for the BACKLOG thread to exit")
try: try:
@ -1310,16 +1293,12 @@ def saveAll():
def saveAndShutdown(restart=False): def saveAndShutdown(restart=False):
global WEBSERVER
halt() halt()
saveAll() saveAll()
logger.log(u"Killing tornado") IOLoop.instance().add_callback(WEBSERVER.shutdown)
try:
IOLoop.current().stop()
except RuntimeError:
pass
except:
logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR)
if CREATEPID: if CREATEPID:
logger.log(u"Removing pidfile " + str(PIDFILE)) logger.log(u"Removing pidfile " + str(PIDFILE))

View File

@ -163,7 +163,7 @@ def change_AUTOPOSTPROCESSER_FREQUENCY(freq):
if sickbeard.AUTOPOSTPROCESSER_FREQUENCY < sickbeard.MIN_AUTOPOSTPROCESSER_FREQUENCY: if sickbeard.AUTOPOSTPROCESSER_FREQUENCY < sickbeard.MIN_AUTOPOSTPROCESSER_FREQUENCY:
sickbeard.AUTOPOSTPROCESSER_FREQUENCY = sickbeard.MIN_AUTOPOSTPROCESSER_FREQUENCY sickbeard.AUTOPOSTPROCESSER_FREQUENCY = sickbeard.MIN_AUTOPOSTPROCESSER_FREQUENCY
sickbeard.autoPostProcessorScheduler.cycleTime = datetime.timedelta(minutes=sickbeard.AUTOPOSTPROCESSER_FREQUENCY) sickbeard.autoPostProcesserScheduler.cycleTime = datetime.timedelta(minutes=sickbeard.AUTOPOSTPROCESSER_FREQUENCY)
def change_DAILYSEARCH_FREQUENCY(freq): def change_DAILYSEARCH_FREQUENCY(freq):
sickbeard.DAILYSEARCH_FREQUENCY = to_int(freq, default=sickbeard.DEFAULT_DAILYSEARCH_FREQUENCY) sickbeard.DAILYSEARCH_FREQUENCY = to_int(freq, default=sickbeard.DEFAULT_DAILYSEARCH_FREQUENCY)

View File

@ -190,6 +190,7 @@ class IndexHandler(RedirectHandler):
args[arg] = value[0] args[arg] = value[0]
return args return args
@asynchronous
def _dispatch(self): def _dispatch(self):
""" """
Load up the requested URL if it matches one of our own methods. Load up the requested URL if it matches one of our own methods.
@ -235,12 +236,10 @@ class IndexHandler(RedirectHandler):
def get_current_user(self): def get_current_user(self):
return self.get_secure_cookie("user") return self.get_secure_cookie("user")
@asynchronous
@authenticated @authenticated
def get(self, *args, **kwargs): def get(self, *args, **kwargs):
return self._dispatch() return self._dispatch()
@asynchronous
def post(self, *args, **kwargs): def post(self, *args, **kwargs):
return self._dispatch() return self._dispatch()
@ -1065,7 +1064,7 @@ class Manage(IndexHandler):
exceptions_list = [] exceptions_list = []
curErrors += Home().editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list, curErrors += self.editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list,
new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime, new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime,
scene=new_scene, directCall=True) scene=new_scene, directCall=True)
@ -1602,9 +1601,9 @@ class ConfigPostProcessing(IndexHandler):
config.change_AUTOPOSTPROCESSER_FREQUENCY(autopostprocesser_frequency) config.change_AUTOPOSTPROCESSER_FREQUENCY(autopostprocesser_frequency)
if sickbeard.PROCESS_AUTOMATICALLY: if sickbeard.PROCESS_AUTOMATICALLY:
sickbeard.autoPostProcessorScheduler.silent = False sickbeard.autoPostProcesserScheduler.silent = False
else: else:
sickbeard.autoPostProcessorScheduler.silent = True sickbeard.autoPostProcesserScheduler.silent = True
if unpack: if unpack:
if self.isRarSupported() != 'not supported': if self.isRarSupported() != 'not supported':
@ -3281,8 +3280,7 @@ class Home(IndexHandler):
title = "Shutting down" title = "Shutting down"
message = "SickRage is shutting down..." message = "SickRage is shutting down..."
return _genericMessage(title, message) return self.finish(_genericMessage(title, message))
def restart(self, pid=None): def restart(self, pid=None):
@ -3311,8 +3309,8 @@ class Home(IndexHandler):
t = PageTemplate(file="restart_bare.tmpl") t = PageTemplate(file="restart_bare.tmpl")
return self.finish(_munge(t)) return self.finish(_munge(t))
else: else:
return _genericMessage("Update Failed", return self.finish(_genericMessage("Update Failed",
"Update wasn't successful, not restarting. Check your log for more information.") "Update wasn't successful, not restarting. Check your log for more information."))
def displayShow(self, show=None): def displayShow(self, show=None):
@ -3477,7 +3475,7 @@ class Home(IndexHandler):
if directCall: if directCall:
return [errString] return [errString]
else: else:
return _genericMessage("Error", errString) return self.finish(_genericMessage("Error", errString))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
@ -3486,7 +3484,7 @@ class Home(IndexHandler):
if directCall: if directCall:
return [errString] return [errString]
else: else:
return _genericMessage("Error", errString) return self.finish(_genericMessage("Error", errString))
showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid) showObj.exceptions = scene_exceptions.get_scene_exceptions(showObj.indexerid)
@ -3727,16 +3725,16 @@ class Home(IndexHandler):
def deleteShow(self, show=None): def deleteShow(self, show=None):
if show is None: if show is None:
return _genericMessage("Error", "Invalid show ID") return self.finish(_genericMessage("Error", "Invalid show ID"))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if showObj is None: if showObj is None:
return _genericMessage("Error", "Unable to find the specified show") return self.finish(_genericMessage("Error", "Unable to find the specified show"))
if sickbeard.showQueueScheduler.action.isBeingAdded( if sickbeard.showQueueScheduler.action.isBeingAdded(
showObj) or sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): # @UndefinedVariable showObj) or sickbeard.showQueueScheduler.action.isBeingUpdated(showObj): # @UndefinedVariable
return _genericMessage("Error", "Shows can't be deleted while they're being added or updated.") return self.finish(_genericMessage("Error", "Shows can't be deleted while they're being added or updated."))
showObj.deleteShow() showObj.deleteShow()
@ -3747,12 +3745,12 @@ class Home(IndexHandler):
def refreshShow(self, show=None): def refreshShow(self, show=None):
if show is None: if show is None:
return _genericMessage("Error", "Invalid show ID") return self.finish(_genericMessage("Error", "Invalid show ID"))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if showObj is None: if showObj is None:
return _genericMessage("Error", "Unable to find the specified show") return self.finish(_genericMessage("Error", "Unable to find the specified show"))
# force the update from the DB # force the update from the DB
try: try:
@ -3769,12 +3767,12 @@ class Home(IndexHandler):
def updateShow(self, show=None, force=0): def updateShow(self, show=None, force=0):
if show is None: if show is None:
return _genericMessage("Error", "Invalid show ID") return self.finish(_genericMessage("Error", "Invalid show ID"))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if showObj is None: if showObj is None:
return _genericMessage("Error", "Unable to find the specified show") return self.finish(_genericMessage("Error", "Unable to find the specified show"))
# force the update # force the update
try: try:
@ -3792,12 +3790,12 @@ class Home(IndexHandler):
def subtitleShow(self, show=None, force=0): def subtitleShow(self, show=None, force=0):
if show is None: if show is None:
return _genericMessage("Error", "Invalid show ID") return self.finish(_genericMessage("Error", "Invalid show ID"))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if showObj is None: if showObj is None:
return _genericMessage("Error", "Unable to find the specified show") return self.finish(_genericMessage("Error", "Unable to find the specified show"))
# search and download subtitles # search and download subtitles
sickbeard.showQueueScheduler.action.downloadSubtitles(showObj, bool(force)) # @UndefinedVariable sickbeard.showQueueScheduler.action.downloadSubtitles(showObj, bool(force)) # @UndefinedVariable
@ -3840,7 +3838,7 @@ class Home(IndexHandler):
ui.notifications.error('Error', errMsg) ui.notifications.error('Error', errMsg)
return json.dumps({'result': 'error'}) return json.dumps({'result': 'error'})
else: else:
return _genericMessage("Error", errMsg) return self.finish(_genericMessage("Error", errMsg))
if not statusStrings.has_key(int(status)): if not statusStrings.has_key(int(status)):
errMsg = "Invalid status" errMsg = "Invalid status"
@ -3848,7 +3846,7 @@ class Home(IndexHandler):
ui.notifications.error('Error', errMsg) ui.notifications.error('Error', errMsg)
return json.dumps({'result': 'error'}) return json.dumps({'result': 'error'})
else: else:
return _genericMessage("Error", errMsg) return self.finish(_genericMessage("Error", errMsg))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
@ -3858,7 +3856,7 @@ class Home(IndexHandler):
ui.notifications.error('Error', errMsg) ui.notifications.error('Error', errMsg)
return json.dumps({'result': 'error'}) return json.dumps({'result': 'error'})
else: else:
return _genericMessage("Error", errMsg) return self.finish(_genericMessage("Error", errMsg))
segment = {} segment = {}
if eps is not None: if eps is not None:
@ -3873,7 +3871,7 @@ class Home(IndexHandler):
epObj = showObj.getEpisode(int(epInfo[0]), int(epInfo[1])) epObj = showObj.getEpisode(int(epInfo[0]), int(epInfo[1]))
if epObj is None: if epObj is None:
return _genericMessage("Error", "Episode couldn't be retrieved") return self.finish(_genericMessage("Error", "Episode couldn't be retrieved"))
if int(status) in [WANTED, FAILED]: if int(status) in [WANTED, FAILED]:
# figure out what episodes are wanted so we can backlog them # figure out what episodes are wanted so we can backlog them
@ -3949,17 +3947,17 @@ class Home(IndexHandler):
def testRename(self, show=None): def testRename(self, show=None):
if show is None: if show is None:
return _genericMessage("Error", "You must specify a show") return self.finish(_genericMessage("Error", "You must specify a show"))
showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) showObj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if showObj is None: if showObj is None:
return _genericMessage("Error", "Show not in show list") return self.finish(_genericMessage("Error", "Show not in show list"))
try: try:
show_loc = showObj.location # @UnusedVariable show_loc = showObj.location # @UnusedVariable
except exceptions.ShowDirNotFoundException: except exceptions.ShowDirNotFoundException:
return _genericMessage("Error", "Can't rename episodes when the show dir is missing.") return self.finish(_genericMessage("Error", "Can't rename episodes when the show dir is missing."))
ep_obj_rename_list = [] ep_obj_rename_list = []
@ -3996,18 +3994,18 @@ class Home(IndexHandler):
if show is None or eps is None: if show is None or eps is None:
errMsg = "You must specify a show and at least one episode" errMsg = "You must specify a show and at least one episode"
return _genericMessage("Error", errMsg) return self.finish(_genericMessage("Error", errMsg))
show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show)) show_obj = sickbeard.helpers.findCertainShow(sickbeard.showList, int(show))
if show_obj is None: if show_obj is None:
errMsg = "Error", "Show not in show list" errMsg = "Error", "Show not in show list"
return _genericMessage("Error", errMsg) return self.finish(_genericMessage("Error", errMsg))
try: try:
show_loc = show_obj.location # @UnusedVariable show_loc = show_obj.location # @UnusedVariable
except exceptions.ShowDirNotFoundException: except exceptions.ShowDirNotFoundException:
return _genericMessage("Error", "Can't rename episodes when the show dir is missing.") return self.finish(_genericMessage("Error", "Can't rename episodes when the show dir is missing."))
if eps is None: if eps is None:
self.redirect("/home/displayShow?show=" + show) self.redirect("/home/displayShow?show=" + show)

View File

@ -1,11 +1,17 @@
import os import os
import threading
import time
import traceback
import datetime
import sickbeard import sickbeard
import webserve import webserve
import tornado.httpserver from sickbeard.exceptions import ex
import tornado.ioloop
from sickbeard import logger from sickbeard import logger
from sickbeard.helpers import create_https_certificates from sickbeard.helpers import create_https_certificates
from tornado.web import Application, StaticFileHandler, HTTPError, RedirectHandler from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPError
from tornado.httpserver import HTTPServer
from tornado.ioloop import IOLoop
class MultiStaticFileHandler(StaticFileHandler): class MultiStaticFileHandler(StaticFileHandler):
def initialize(self, paths, default_filename=None): def initialize(self, paths, default_filename=None):
@ -27,17 +33,27 @@ class MultiStaticFileHandler(StaticFileHandler):
# Oops file not found anywhere! # Oops file not found anywhere!
raise HTTPError(404) raise HTTPError(404)
class webserverInit(): class webserverInit():
def __init__(self, options): def __init__(self, options, cycleTime=datetime.timedelta(seconds=3)):
self.amActive = False self.amActive = False
options.setdefault('port', 8081) self.lastRun = datetime.datetime.fromordinal(1)
options.setdefault('host', '0.0.0.0') self.cycleTime = cycleTime
options.setdefault('log_dir', None) self.abort = False
options.setdefault('username', '')
options.setdefault('password', '') self.server = None
options.setdefault('web_root', '/') self.thread = None
assert isinstance(options['port'], int)
assert 'data_root' in options 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): def http_error_401_hander(status, message, traceback, version):
""" Custom handler for 401 error """ """ Custom handler for 401 error """
@ -72,12 +88,12 @@ class webserverInit():
<br/> <br/>
</body> </body>
</html> </html>
''' % options['web_root'] ''' % self.options['web_root']
# tornado setup # tornado setup
enable_https = options['enable_https'] enable_https = self.options['enable_https']
https_cert = options['https_cert'] https_cert = self.options['https_cert']
https_key = options['https_key'] https_key = self.options['https_key']
if enable_https: if enable_https:
# If either the HTTPS certificate or key do not exist, make some self-signed ones. # If either the HTTPS certificate or key do not exist, make some self-signed ones.
@ -103,42 +119,84 @@ class webserverInit():
# Index Handler # Index Handler
app.add_handlers(".*$", [ app.add_handlers(".*$", [
(r"/", tornado.web.RedirectHandler, {'url': '/home/'}), (r"/", RedirectHandler, {'url': '/home/'}),
(r'/login', webserve.LoginHandler), (r'/login', webserve.LoginHandler),
(r'%s(.*)(/?)' % options['web_root'], webserve.IndexHandler) (r'%s(.*)(/?)' % self.options['web_root'], webserve.IndexHandler)
]) ])
# Static Path Handler # Static Path Handler
app.add_handlers(".*$", [ app.add_handlers(".*$", [
('%s/%s/(.*)([^/]*)' % (options['web_root'], 'images'), MultiStaticFileHandler, ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
{'paths': [os.path.join(options['data_root'], 'images'), {'paths': [os.path.join(self.options['data_root'], 'images'),
os.path.join(sickbeard.CACHE_DIR, 'images'), os.path.join(sickbeard.CACHE_DIR, 'images'),
os.path.join(sickbeard.CACHE_DIR, 'images', 'thumbnails')]}), os.path.join(sickbeard.CACHE_DIR, 'images', 'thumbnails')]}),
('%s/%s/(.*)([^/]*)' % (options['web_root'], 'css'), MultiStaticFileHandler, ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'css'), MultiStaticFileHandler,
{'paths': [os.path.join(options['data_root'], 'css')]}), {'paths': [os.path.join(self.options['data_root'], 'css')]}),
('%s/%s/(.*)([^/]*)' % (options['web_root'], 'js'), MultiStaticFileHandler, ('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'js'), MultiStaticFileHandler,
{'paths': [os.path.join(options['data_root'], 'js')]}) {'paths': [os.path.join(self.options['data_root'], 'js')]})
]) ])
if enable_https: if enable_https:
protocol = "https" protocol = "https"
server = tornado.httpserver.HTTPServer(app, no_keep_alive=True, self.server = HTTPServer(app, no_keep_alive=True,
ssl_options={"certfile": https_cert, "keyfile": https_key}) ssl_options={"certfile": https_cert, "keyfile": https_key})
else: else:
protocol = "http" protocol = "http"
server = tornado.httpserver.HTTPServer(app, no_keep_alive=True) self.server = HTTPServer(app, no_keep_alive=True)
logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str( logger.log(u"Starting SickRage on " + protocol + "://" + str(self.options['host']) + ":" + str(
options['port']) + "/") self.options['port']) + "/")
server.listen(options['port'], options['host']) self.server.listen(self.options['port'], self.options['host'])
if self.thread == None or not self.thread.isAlive():
self.thread = threading.Thread(None, self.monitor, 'TORNADO')
def monitor(self):
while True:
currentTime = datetime.datetime.now()
if currentTime - self.lastRun > self.cycleTime:
self.lastRun = currentTime
try:
logger.log(u"Starting tornado", logger.DEBUG)
IOLoop.instance().start()
except Exception, e:
logger.log(u"Exception generated in tornado: " + ex(e), logger.ERROR)
logger.log(repr(traceback.format_exc()), logger.DEBUG)
if self.abort:
self.abort = False
self.thread = None
return
time.sleep(1)
def shutdown(self):
logger.logging.info('Shutting down tornado')
def run(self, force=False):
try: try:
self.amActive = True self.abort = True
tornado.ioloop.IOLoop.instance().start() self.server.stop()
deadline = time.time() + 10
io_loop = IOLoop.instance()
def stop_loop():
now = time.time()
if now < deadline:
if io_loop._callbacks:
io_loop.add_timeout(now + 1, stop_loop)
return
stop_loop()
self.thread.join(10)
except: except:
self.amActive = False pass
raise
logger.logging.info('Tornado is now shutdown')