mirror of
https://github.com/moparisthebest/SickRage
synced 2024-12-12 19:12:26 -05:00
Fixes more issues that were preventing proper shutdowns, restarts, and upgrades.
This commit is contained in:
parent
fa01711192
commit
7d52d079fa
34
SickBeard.py
34
SickBeard.py
@ -54,10 +54,10 @@ import getopt
|
|||||||
|
|
||||||
import sickbeard
|
import sickbeard
|
||||||
|
|
||||||
from sickbeard.webserveInit import webserverInit
|
|
||||||
from sickbeard import db
|
from sickbeard import db
|
||||||
from sickbeard.tv import TVShow
|
from sickbeard.tv import TVShow
|
||||||
from sickbeard import logger
|
from sickbeard import logger
|
||||||
|
from sickbeard import webserveInit
|
||||||
from sickbeard.version import SICKBEARD_VERSION
|
from sickbeard.version import SICKBEARD_VERSION
|
||||||
from sickbeard.databases.mainDB import MIN_DB_VERSION
|
from sickbeard.databases.mainDB import MIN_DB_VERSION
|
||||||
from sickbeard.databases.mainDB import MAX_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(stdout.fileno(), sys.stdout.fileno())
|
||||||
os.dup2(stderr.fileno(), sys.stderr.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():
|
def main():
|
||||||
"""
|
"""
|
||||||
TV for me
|
TV for me
|
||||||
@ -368,11 +361,14 @@ def main():
|
|||||||
'https_key': sickbeard.HTTPS_KEY,
|
'https_key': sickbeard.HTTPS_KEY,
|
||||||
}
|
}
|
||||||
|
|
||||||
def startup():
|
# init tornado
|
||||||
# Build from the DB to start with
|
webserveInit.initWebServer(options)
|
||||||
logger.log(u"Loading initial show list")
|
|
||||||
loadShowsFromDB()
|
|
||||||
|
|
||||||
|
# Build from the DB to start with
|
||||||
|
logger.log(u"Loading initial show list")
|
||||||
|
loadShowsFromDB()
|
||||||
|
|
||||||
|
def startup():
|
||||||
# Fire up all our threads
|
# Fire up all our threads
|
||||||
sickbeard.start()
|
sickbeard.start()
|
||||||
|
|
||||||
@ -384,17 +380,11 @@ def main():
|
|||||||
if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START:
|
if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START:
|
||||||
sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable
|
sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable
|
||||||
|
|
||||||
# init tornado
|
# init startup tasks
|
||||||
sickbeard.WEBSERVER = webserverInit(options)
|
IOLoop.current().add_timeout(datetime.timedelta(seconds=5), startup)
|
||||||
sickbeard.WEBSERVER.ioloop.add_timeout(datetime.timedelta(seconds=5), startup)
|
|
||||||
|
|
||||||
# check for commands to be executed in the background
|
# start IOLoop
|
||||||
task = PeriodicCallback(invoke_command, 1000)
|
IOLoop.current().start()
|
||||||
sickbeard.WEBSERVER.tasks.append(task)
|
|
||||||
|
|
||||||
# start tornado
|
|
||||||
sickbeard.WEBSERVER.start()
|
|
||||||
sickbeard.WEBSERVER.close()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -53,8 +53,6 @@ from lib.configobj import ConfigObj
|
|||||||
from tornado.ioloop import IOLoop
|
from tornado.ioloop import IOLoop
|
||||||
import xml.etree.ElementTree as ElementTree
|
import xml.etree.ElementTree as ElementTree
|
||||||
|
|
||||||
invoked_command = None
|
|
||||||
|
|
||||||
PID = None
|
PID = None
|
||||||
|
|
||||||
CFG = None
|
CFG = None
|
||||||
@ -77,7 +75,6 @@ PIDFILE = ''
|
|||||||
|
|
||||||
DAEMON = None
|
DAEMON = None
|
||||||
NO_RESIZE = False
|
NO_RESIZE = False
|
||||||
WEBSERVER = None
|
|
||||||
|
|
||||||
maintenanceScheduler = None
|
maintenanceScheduler = None
|
||||||
dailySearchScheduler = None
|
dailySearchScheduler = None
|
||||||
@ -1117,15 +1114,12 @@ def start():
|
|||||||
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
||||||
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
||||||
subtitlesFinderScheduler, USE_SUBTITLES,traktWatchListCheckerScheduler, \
|
subtitlesFinderScheduler, USE_SUBTITLES,traktWatchListCheckerScheduler, \
|
||||||
dailySearchScheduler, WEBSERVER, started
|
dailySearchScheduler, started
|
||||||
|
|
||||||
with INIT_LOCK:
|
with INIT_LOCK:
|
||||||
|
|
||||||
if __INITIALIZED__:
|
if __INITIALIZED__:
|
||||||
|
|
||||||
# start IOLoop tasks
|
|
||||||
WEBSERVER.start_tasks()
|
|
||||||
|
|
||||||
# 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 ...")
|
||||||
@ -1171,7 +1165,7 @@ def halt():
|
|||||||
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
showUpdateScheduler, versionCheckScheduler, showQueueScheduler, \
|
||||||
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
properFinderScheduler, autoPostProcesserScheduler, searchQueueScheduler, \
|
||||||
subtitlesFinderScheduler, traktWatchListCheckerScheduler, \
|
subtitlesFinderScheduler, traktWatchListCheckerScheduler, \
|
||||||
dailySearchScheduler, WEBSERVER, started
|
dailySearchScheduler, started
|
||||||
|
|
||||||
with INIT_LOCK:
|
with INIT_LOCK:
|
||||||
|
|
||||||
@ -1181,8 +1175,6 @@ def halt():
|
|||||||
|
|
||||||
# abort all the threads
|
# abort all the threads
|
||||||
|
|
||||||
WEBSERVER.stop_tasks()
|
|
||||||
|
|
||||||
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:
|
||||||
@ -1190,6 +1182,13 @@ def halt():
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
dailySearchScheduler.abort = True
|
||||||
|
logger.log(u"Waiting for the DAILYSEARCH 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:
|
||||||
@ -1281,7 +1280,6 @@ def sig_handler(signum=None, frame=None):
|
|||||||
logger.log(u"Signal %i caught, saving and exiting..." % int(signum))
|
logger.log(u"Signal %i caught, saving and exiting..." % int(signum))
|
||||||
saveAndShutdown()
|
saveAndShutdown()
|
||||||
|
|
||||||
|
|
||||||
def saveAll():
|
def saveAll():
|
||||||
global showList
|
global showList
|
||||||
|
|
||||||
@ -1294,21 +1292,19 @@ def saveAll():
|
|||||||
logger.log(u"Saving config file to disk")
|
logger.log(u"Saving config file to disk")
|
||||||
save_config()
|
save_config()
|
||||||
|
|
||||||
|
|
||||||
def saveAndShutdown(restart=False):
|
def saveAndShutdown(restart=False):
|
||||||
global WEBSERVER
|
|
||||||
|
|
||||||
halt()
|
|
||||||
saveAll()
|
|
||||||
|
|
||||||
logger.log('Shutting down tornado')
|
logger.log('Shutting down tornado')
|
||||||
try:
|
try:
|
||||||
WEBSERVER.stop()
|
IOLoop.current().stop()
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
pass
|
pass
|
||||||
except:
|
except:
|
||||||
logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR)
|
logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR)
|
||||||
|
|
||||||
|
halt()
|
||||||
|
saveAll()
|
||||||
|
|
||||||
if CREATEPID:
|
if CREATEPID:
|
||||||
logger.log(u"Removing pidfile " + str(PIDFILE))
|
logger.log(u"Removing pidfile " + str(PIDFILE))
|
||||||
remove_pid_file(PIDFILE)
|
remove_pid_file(PIDFILE)
|
||||||
@ -1341,17 +1337,15 @@ def saveAndShutdown(restart=False):
|
|||||||
|
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
|
||||||
def invoke_command(to_call, *args, **kwargs):
|
def invoke_command(to_call, *args, **kwargs):
|
||||||
global invoked_command
|
|
||||||
|
|
||||||
def delegate():
|
def delegate():
|
||||||
to_call(*args, **kwargs)
|
to_call(*args, **kwargs)
|
||||||
|
|
||||||
invoked_command = delegate
|
logger.log(u"Placed invoked command: " + repr(delegate) + " for " + repr(to_call) + " with " + repr(
|
||||||
logger.log(u"Placed invoked command: " + repr(invoked_command) + " for " + repr(to_call) + " with " + repr(
|
|
||||||
args) + " and " + repr(kwargs), logger.DEBUG)
|
args) + " and " + repr(kwargs), logger.DEBUG)
|
||||||
|
|
||||||
|
IOLoop.current().add_callback(delegate)
|
||||||
|
|
||||||
def invoke_restart(soft=True):
|
def invoke_restart(soft=True):
|
||||||
invoke_command(restart, soft=soft)
|
invoke_command(restart, soft=soft)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import os
|
import os
|
||||||
import datetime
|
|
||||||
import sickbeard
|
import sickbeard
|
||||||
import webserve
|
import webserve
|
||||||
|
|
||||||
@ -7,7 +6,6 @@ from sickbeard import logger
|
|||||||
from sickbeard.helpers import create_https_certificates
|
from sickbeard.helpers import create_https_certificates
|
||||||
from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPError
|
from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPError
|
||||||
from tornado.httpserver import HTTPServer
|
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):
|
||||||
@ -29,139 +27,108 @@ class MultiStaticFileHandler(StaticFileHandler):
|
|||||||
# Oops file not found anywhere!
|
# Oops file not found anywhere!
|
||||||
raise HTTPError(404)
|
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 http_error_401_hander(status, message, traceback, version):
|
||||||
def __init__(self, options, cycleTime=datetime.timedelta(seconds=3)):
|
""" 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'''<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>%s</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<br/>
|
||||||
|
<font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''' % ('Access denied', status)
|
||||||
|
|
||||||
self.amActive = False
|
def http_error_404_hander(status, message, traceback, version):
|
||||||
self.lastRun = datetime.datetime.fromordinal(1)
|
""" Custom handler for 404 error, redirect back to main page """
|
||||||
self.cycleTime = cycleTime
|
return r'''<!DOCTYPE html>
|
||||||
self.abort = False
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>404</title>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
<!--
|
||||||
|
location.href = "%s/home/"
|
||||||
|
//-->
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<br/>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
''' % options['web_root']
|
||||||
|
|
||||||
self.server = None
|
# tornado setup
|
||||||
self.ioloop = None
|
enable_https = options['enable_https']
|
||||||
self.tasks = []
|
https_cert = options['https_cert']
|
||||||
|
https_key = options['https_key']
|
||||||
|
|
||||||
self.options = options
|
if enable_https:
|
||||||
self.options.setdefault('port', 8081)
|
# If either the HTTPS certificate or key do not exist, make some self-signed ones.
|
||||||
self.options.setdefault('host', '0.0.0.0')
|
if not (https_cert and os.path.exists(https_cert)) or not (https_key and os.path.exists(https_key)):
|
||||||
self.options.setdefault('log_dir', None)
|
if not create_https_certificates(https_cert, https_key):
|
||||||
self.options.setdefault('username', '')
|
logger.log(u"Unable to create CERT/KEY files, disabling HTTPS")
|
||||||
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'''<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>%s</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<br/>
|
|
||||||
<font color="#0000FF">Error %s: You need to provide a valid username and password.</font>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
''' % ('Access denied', status)
|
|
||||||
|
|
||||||
def http_error_404_hander(status, message, traceback, version):
|
|
||||||
""" Custom handler for 404 error, redirect back to main page """
|
|
||||||
return r'''<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>404</title>
|
|
||||||
<script type="text/javascript" charset="utf-8">
|
|
||||||
<!--
|
|
||||||
location.href = "%s/home/"
|
|
||||||
//-->
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<br/>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
''' % 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)
|
|
||||||
sickbeard.ENABLE_HTTPS = False
|
sickbeard.ENABLE_HTTPS = False
|
||||||
enable_https = False
|
enable_https = False
|
||||||
|
|
||||||
# Load the app
|
if not (os.path.exists(https_cert) and os.path.exists(https_key)):
|
||||||
app = Application([],
|
logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
|
||||||
log_function=lambda x: None,
|
sickbeard.ENABLE_HTTPS = False
|
||||||
debug=False,
|
enable_https = False
|
||||||
gzip=True,
|
|
||||||
cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
|
|
||||||
login_url='/login',
|
|
||||||
autoreload=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Index Handler
|
# Load the app
|
||||||
app.add_handlers(".*$", [
|
app = Application([],
|
||||||
(r"/", RedirectHandler, {'url': '/home/'}),
|
debug=False,
|
||||||
(r'/login', webserve.LoginHandler),
|
gzip=True,
|
||||||
(r'%s(.*)(/?)' % self.options['web_root'], webserve.IndexHandler)
|
cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
|
||||||
])
|
login_url='/login'
|
||||||
|
)
|
||||||
|
|
||||||
# Static Path Handler
|
# Index Handler
|
||||||
app.add_handlers(".*$", [
|
app.add_handlers(".*$", [
|
||||||
('%s/%s/(.*)([^/]*)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
|
(r"/", RedirectHandler, {'url': '/home/'}),
|
||||||
{'paths': [os.path.join(self.options['data_root'], 'images'),
|
(r'/login', webserve.LoginHandler),
|
||||||
os.path.join(sickbeard.CACHE_DIR, 'images'),
|
(r'%s(.*)(/?)' % options['web_root'], webserve.IndexHandler)
|
||||||
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')]})
|
|
||||||
|
|
||||||
])
|
# 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(
|
global server
|
||||||
self.options['port']) + "/")
|
|
||||||
|
|
||||||
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):
|
logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(
|
||||||
self.server.listen(self.options['port'], self.options['host'])
|
options['port']) + "/")
|
||||||
self.ioloop.start()
|
|
||||||
|
|
||||||
def stop(self):
|
server.listen(options['port'], options['host'])
|
||||||
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()
|
|
Loading…
Reference in New Issue
Block a user