mirror of
https://github.com/moparisthebest/SickRage
synced 2025-01-06 03:18:01 -05:00
Fixed startup/restart/shutdown issues on Windows, Linux, FreeBSD platforms tested.
Fixed for updating issues. Fixed high cpu and memory usage.
This commit is contained in:
parent
1fc909299d
commit
12ac388dc2
617
SickBeard.py
617
SickBeard.py
@ -20,8 +20,10 @@
|
||||
# Check needed software dependencies to nudge users to fix their setup
|
||||
from __future__ import with_statement
|
||||
|
||||
import time
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
|
||||
if sys.version_info < (2, 6):
|
||||
print "Sorry, requires Python 2.6 or 2.7."
|
||||
@ -59,13 +61,12 @@ import sickbeard
|
||||
from sickbeard import db
|
||||
from sickbeard.tv import TVShow
|
||||
from sickbeard import logger
|
||||
from sickbeard import webserveInit
|
||||
from sickbeard.webserveInit import SRWebServer
|
||||
from sickbeard.version import SICKBEARD_VERSION
|
||||
from sickbeard.databases.mainDB import MIN_DB_VERSION
|
||||
from sickbeard.databases.mainDB import MAX_DB_VERSION
|
||||
|
||||
from lib.configobj import ConfigObj
|
||||
from tornado.ioloop import IOLoop
|
||||
from daemon import Daemon
|
||||
|
||||
signal.signal(signal.SIGINT, sickbeard.sig_handler)
|
||||
@ -73,331 +74,343 @@ signal.signal(signal.SIGTERM, sickbeard.sig_handler)
|
||||
|
||||
throwaway = datetime.datetime.strptime('20110101', '%Y%m%d')
|
||||
|
||||
restart = False
|
||||
daemon = None
|
||||
startPort = None
|
||||
forceUpdate = None
|
||||
noLaunch = None
|
||||
web_options = None
|
||||
class SickRage(object):
|
||||
|
||||
def loadShowsFromDB():
|
||||
"""
|
||||
Populates the showList with shows from the database
|
||||
"""
|
||||
def loadShowsFromDB(self):
|
||||
"""
|
||||
Populates the showList with shows from the database
|
||||
"""
|
||||
|
||||
logger.log(u"Loading initial show list")
|
||||
logger.log(u"Loading initial show list")
|
||||
|
||||
myDB = db.DBConnection()
|
||||
sqlResults = myDB.select("SELECT * FROM tv_shows")
|
||||
myDB = db.DBConnection()
|
||||
sqlResults = myDB.select("SELECT * FROM tv_shows")
|
||||
|
||||
sickbeard.showList = []
|
||||
for sqlShow in sqlResults:
|
||||
sickbeard.showList = []
|
||||
for sqlShow in sqlResults:
|
||||
try:
|
||||
curShow = TVShow(int(sqlShow["indexer"]), int(sqlShow["indexer_id"]))
|
||||
sickbeard.showList.append(curShow)
|
||||
except Exception, e:
|
||||
logger.log(
|
||||
u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'),
|
||||
logger.ERROR)
|
||||
logger.log(traceback.format_exc(), logger.DEBUG)
|
||||
|
||||
def restore(self, srcDir, dstDir):
|
||||
try:
|
||||
curShow = TVShow(int(sqlShow["indexer"]), int(sqlShow["indexer_id"]))
|
||||
sickbeard.showList.append(curShow)
|
||||
except Exception, e:
|
||||
logger.log(
|
||||
u"There was an error creating the show in " + sqlShow["location"] + ": " + str(e).decode('utf-8'),
|
||||
logger.ERROR)
|
||||
logger.log(traceback.format_exc(), logger.DEBUG)
|
||||
for file in os.listdir(srcDir):
|
||||
srcFile = os.path.join(srcDir, file)
|
||||
dstFile = os.path.join(dstDir, file)
|
||||
bakFile = os.path.join(dstDir, file + '.bak')
|
||||
shutil.move(dstFile, bakFile)
|
||||
shutil.move(srcFile, dstFile)
|
||||
|
||||
# TODO: update the existing shows if the showlist has something in it
|
||||
os.rmdir(srcDir)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def restore(srcDir, dstDir):
|
||||
try:
|
||||
for file in os.listdir(srcDir):
|
||||
srcFile = os.path.join(srcDir, file)
|
||||
dstFile = os.path.join(dstDir, file)
|
||||
bakFile = os.path.join(dstDir, file + '.bak')
|
||||
shutil.move(dstFile, bakFile)
|
||||
shutil.move(srcFile, dstFile)
|
||||
def __init__(self):
|
||||
self.daemon = None
|
||||
self.webserver = None
|
||||
self.runAsDaemon = False
|
||||
self.CREATEPID = False
|
||||
self.PIDFILE = None
|
||||
self.forceUpdate = False
|
||||
self.forcedPort = None
|
||||
self.noLaunch = False
|
||||
|
||||
os.rmdir(srcDir)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""
|
||||
TV for me
|
||||
"""
|
||||
|
||||
global daemon, startPort, forceUpdate, noLaunch, web_options
|
||||
|
||||
# do some preliminary stuff
|
||||
sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__))
|
||||
sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME)
|
||||
sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME)
|
||||
sickbeard.DATA_DIR = sickbeard.PROG_DIR
|
||||
sickbeard.MY_ARGS = sys.argv[1:]
|
||||
sickbeard.DAEMON = False
|
||||
sickbeard.CREATEPID = False
|
||||
|
||||
sickbeard.SYS_ENCODING = None
|
||||
|
||||
try:
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
sickbeard.SYS_ENCODING = locale.getpreferredencoding()
|
||||
except (locale.Error, IOError):
|
||||
pass
|
||||
|
||||
# For OSes that are poorly configured I'll just randomly force UTF-8
|
||||
if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
|
||||
sickbeard.SYS_ENCODING = 'UTF-8'
|
||||
|
||||
if not hasattr(sys, "setdefaultencoding"):
|
||||
reload(sys)
|
||||
|
||||
try:
|
||||
# pylint: disable=E1101
|
||||
# On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError
|
||||
sys.setdefaultencoding(sickbeard.SYS_ENCODING)
|
||||
except:
|
||||
print 'Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable'
|
||||
print 'or find another way to force Python to use ' + sickbeard.SYS_ENCODING + ' for string encoding.'
|
||||
sys.exit(1)
|
||||
|
||||
# Need console logging for SickBeard.py and SickBeard-console.exe
|
||||
consoleLogging = (not hasattr(sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0)
|
||||
|
||||
# Rename the main thread
|
||||
threading.currentThread().name = "MAIN"
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "qfdp::",
|
||||
['quiet', 'forceupdate', 'daemon', 'port=', 'pidfile=', 'nolaunch', 'config=',
|
||||
'datadir=']) # @UnusedVariable
|
||||
except getopt.GetoptError:
|
||||
print "Available Options: --quiet, --forceupdate, --port, --daemon, --pidfile, --config, --datadir"
|
||||
sys.exit()
|
||||
|
||||
forceUpdate = False
|
||||
forcedPort = None
|
||||
noLaunch = False
|
||||
|
||||
for o, a in opts:
|
||||
# For now we'll just silence the logging
|
||||
if o in ('-q', '--quiet'):
|
||||
consoleLogging = False
|
||||
|
||||
# Should we update (from indexer) all shows in the DB right away?
|
||||
if o in ('-f', '--forceupdate'):
|
||||
forceUpdate = True
|
||||
|
||||
# Suppress launching web browser
|
||||
# Needed for OSes without default browser assigned
|
||||
# Prevent duplicate browser window when restarting in the app
|
||||
if o in ('--nolaunch',):
|
||||
noLaunch = True
|
||||
|
||||
# Override default/configured port
|
||||
if o in ('-p', '--port'):
|
||||
forcedPort = int(a)
|
||||
|
||||
# Run as a double forked daemon
|
||||
if o in ('-d', '--daemon'):
|
||||
sickbeard.DAEMON = True
|
||||
# When running as daemon disable consoleLogging and don't start browser
|
||||
consoleLogging = False
|
||||
noLaunch = True
|
||||
|
||||
if sys.platform == 'win32':
|
||||
sickbeard.DAEMON = False
|
||||
|
||||
# Specify folder to load the config file from
|
||||
if o in ('--config',):
|
||||
sickbeard.CONFIG_FILE = os.path.abspath(a)
|
||||
|
||||
# Specify folder to use as the data dir
|
||||
if o in ('--datadir',):
|
||||
sickbeard.DATA_DIR = os.path.abspath(a)
|
||||
|
||||
# Prevent resizing of the banner/posters even if PIL is installed
|
||||
if o in ('--noresize',):
|
||||
sickbeard.NO_RESIZE = True
|
||||
|
||||
# Write a pidfile if requested
|
||||
if o in ('--pidfile',):
|
||||
sickbeard.CREATEPID = True
|
||||
sickbeard.PIDFILE = str(a)
|
||||
|
||||
# If the pidfile already exists, sickbeard may still be running, so exit
|
||||
if os.path.exists(sickbeard.PIDFILE):
|
||||
sys.exit("PID file: " + sickbeard.PIDFILE + " already exists. Exiting.")
|
||||
|
||||
# The pidfile is only useful in daemon mode, make sure we can write the file properly
|
||||
if sickbeard.CREATEPID:
|
||||
if sickbeard.DAEMON:
|
||||
pid_dir = os.path.dirname(sickbeard.PIDFILE)
|
||||
if not os.access(pid_dir, os.F_OK):
|
||||
sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.")
|
||||
if not os.access(pid_dir, os.W_OK):
|
||||
sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.")
|
||||
|
||||
else:
|
||||
if consoleLogging:
|
||||
sys.stdout.write("Not running in daemon mode. PID file creation disabled.\n")
|
||||
|
||||
sickbeard.CREATEPID = False
|
||||
|
||||
# If they don't specify a config file then put it in the data dir
|
||||
if not sickbeard.CONFIG_FILE:
|
||||
sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini")
|
||||
|
||||
# Make sure that we can create the data dir
|
||||
if not os.access(sickbeard.DATA_DIR, os.F_OK):
|
||||
try:
|
||||
os.makedirs(sickbeard.DATA_DIR, 0744)
|
||||
except os.error, e:
|
||||
raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'")
|
||||
|
||||
# Make sure we can write to the data dir
|
||||
if not os.access(sickbeard.DATA_DIR, os.W_OK):
|
||||
raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'")
|
||||
|
||||
# Make sure we can write to the config file
|
||||
if not os.access(sickbeard.CONFIG_FILE, os.W_OK):
|
||||
if os.path.isfile(sickbeard.CONFIG_FILE):
|
||||
raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.")
|
||||
elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK):
|
||||
raise SystemExit(
|
||||
"Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable.")
|
||||
|
||||
# Check if we need to perform a restore first
|
||||
restoreDir = os.path.join(sickbeard.DATA_DIR, 'restore')
|
||||
if os.path.exists(restoreDir):
|
||||
if restore(restoreDir, sickbeard.DATA_DIR):
|
||||
logger.log(u"Restore successful...")
|
||||
else:
|
||||
logger.log(u"Restore FAILED!", logger.ERROR)
|
||||
|
||||
os.chdir(sickbeard.DATA_DIR)
|
||||
|
||||
if consoleLogging:
|
||||
print "Starting up SickRage " + SICKBEARD_VERSION + " from " + sickbeard.CONFIG_FILE
|
||||
|
||||
# Load the config and publish it to the sickbeard package
|
||||
if not os.path.isfile(sickbeard.CONFIG_FILE):
|
||||
logger.log(u"Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!", logger.ERROR)
|
||||
|
||||
sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE)
|
||||
|
||||
CUR_DB_VERSION = db.DBConnection().checkDBVersion()
|
||||
|
||||
if CUR_DB_VERSION > 0:
|
||||
if CUR_DB_VERSION < MIN_DB_VERSION:
|
||||
raise SystemExit("Your database version (" + str(
|
||||
CUR_DB_VERSION) + ") is too old to migrate from with this version of SickRage (" + str(
|
||||
MIN_DB_VERSION) + ").\n" + \
|
||||
"Upgrade using a previous version of SB first, or start with no database file to begin fresh.")
|
||||
if CUR_DB_VERSION > MAX_DB_VERSION:
|
||||
raise SystemExit("Your database version (" + str(
|
||||
CUR_DB_VERSION) + ") has been incremented past what this version of SickRage supports (" + str(
|
||||
MAX_DB_VERSION) + ").\n" + \
|
||||
"If you have used other forks of SB, your database may be unusable due to their modifications.")
|
||||
|
||||
# Initialize the config and our threads
|
||||
sickbeard.initialize(consoleLogging=consoleLogging)
|
||||
|
||||
if forcedPort:
|
||||
logger.log(u"Forcing web server to port " + str(forcedPort))
|
||||
startPort = forcedPort
|
||||
else:
|
||||
startPort = sickbeard.WEB_PORT
|
||||
|
||||
if sickbeard.WEB_LOG:
|
||||
log_dir = sickbeard.LOG_DIR
|
||||
else:
|
||||
log_dir = None
|
||||
|
||||
# sickbeard.WEB_HOST is available as a configuration value in various
|
||||
# places but is not configurable. It is supported here for historic reasons.
|
||||
if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0':
|
||||
webhost = sickbeard.WEB_HOST
|
||||
else:
|
||||
if sickbeard.WEB_IPV6:
|
||||
webhost = '::'
|
||||
else:
|
||||
webhost = '0.0.0.0'
|
||||
|
||||
# web server options
|
||||
web_options = {
|
||||
'port': int(startPort),
|
||||
'host': webhost,
|
||||
'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME),
|
||||
'web_root': sickbeard.WEB_ROOT,
|
||||
'log_dir': log_dir,
|
||||
'username': sickbeard.WEB_USERNAME,
|
||||
'password': sickbeard.WEB_PASSWORD,
|
||||
'enable_https': sickbeard.ENABLE_HTTPS,
|
||||
'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY,
|
||||
'https_cert': sickbeard.HTTPS_CERT,
|
||||
'https_key': sickbeard.HTTPS_KEY,
|
||||
}
|
||||
|
||||
# Start SickRage
|
||||
if daemon and daemon.is_running():
|
||||
daemon.restart(daemonize=sickbeard.DAEMON)
|
||||
else:
|
||||
daemon = SickRage(sickbeard.PIDFILE)
|
||||
daemon.start(daemonize=sickbeard.DAEMON)
|
||||
|
||||
class SickRage(Daemon):
|
||||
def run(self):
|
||||
global restart, startPort, forceUpdate, noLaunch, web_options
|
||||
|
||||
# Use this PID for everything
|
||||
sickbeard.PID = os.getpid()
|
||||
def start(self):
|
||||
# do some preliminary stuff
|
||||
sickbeard.MY_FULLNAME = os.path.normpath(os.path.abspath(__file__))
|
||||
sickbeard.MY_NAME = os.path.basename(sickbeard.MY_FULLNAME)
|
||||
sickbeard.PROG_DIR = os.path.dirname(sickbeard.MY_FULLNAME)
|
||||
sickbeard.DATA_DIR = sickbeard.PROG_DIR
|
||||
sickbeard.MY_ARGS = sys.argv[1:]
|
||||
sickbeard.SYS_ENCODING = None
|
||||
|
||||
try:
|
||||
webserveInit.initWebServer(web_options)
|
||||
except IOError:
|
||||
logger.log(u"Unable to start web server, is something else running on port %d?" % startPort, logger.ERROR)
|
||||
if sickbeard.LAUNCH_BROWSER and not sickbeard.DAEMON:
|
||||
logger.log(u"Launching browser and exiting", logger.ERROR)
|
||||
sickbeard.launchBrowser(startPort)
|
||||
locale.setlocale(locale.LC_ALL, "")
|
||||
sickbeard.SYS_ENCODING = locale.getpreferredencoding()
|
||||
except (locale.Error, IOError):
|
||||
pass
|
||||
|
||||
# For OSes that are poorly configured I'll just randomly force UTF-8
|
||||
if not sickbeard.SYS_ENCODING or sickbeard.SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
|
||||
sickbeard.SYS_ENCODING = 'UTF-8'
|
||||
|
||||
if not hasattr(sys, "setdefaultencoding"):
|
||||
reload(sys)
|
||||
|
||||
try:
|
||||
# pylint: disable=E1101
|
||||
# On non-unicode builds this will raise an AttributeError, if encoding type is not valid it throws a LookupError
|
||||
sys.setdefaultencoding(sickbeard.SYS_ENCODING)
|
||||
except:
|
||||
print 'Sorry, you MUST add the SickRage folder to the PYTHONPATH environment variable'
|
||||
print 'or find another way to force Python to use ' + sickbeard.SYS_ENCODING + ' for string encoding.'
|
||||
sys.exit(1)
|
||||
|
||||
# Need console logging for SickBeard.py and SickBeard-console.exe
|
||||
self.consoleLogging = (not hasattr(sys, "frozen")) or (sickbeard.MY_NAME.lower().find('-console') > 0)
|
||||
|
||||
# Rename the main thread
|
||||
threading.currentThread().name = "MAIN"
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "qfdp::",
|
||||
['quiet', 'forceupdate', 'daemon', 'port=', 'pidfile=', 'nolaunch', 'config=',
|
||||
'datadir=']) # @UnusedVariable
|
||||
except getopt.GetoptError:
|
||||
print "Available Options: --quiet, --forceupdate, --port, --daemon, --pidfile, --config, --datadir"
|
||||
sys.exit()
|
||||
|
||||
for o, a in opts:
|
||||
# For now we'll just silence the logging
|
||||
if o in ('-q', '--quiet'):
|
||||
self.consoleLogging = False
|
||||
|
||||
# Should we update (from indexer) all shows in the DB right away?
|
||||
if o in ('-f', '--forceupdate'):
|
||||
self.forceUpdate = True
|
||||
|
||||
# Suppress launching web browser
|
||||
# Needed for OSes without default browser assigned
|
||||
# Prevent duplicate browser window when restarting in the app
|
||||
if o in ('--nolaunch',):
|
||||
self.noLaunch = True
|
||||
|
||||
# Override default/configured port
|
||||
if o in ('-p', '--port'):
|
||||
self.forcedPort = int(a)
|
||||
|
||||
# Run as a double forked daemon
|
||||
if o in ('-d', '--daemon'):
|
||||
self.runAsDaemon = True
|
||||
# When running as daemon disable consoleLogging and don't start browser
|
||||
self.consoleLogging = False
|
||||
self.noLaunch = True
|
||||
|
||||
if sys.platform == 'win32':
|
||||
self.runAsDaemon = False
|
||||
|
||||
# Specify folder to load the config file from
|
||||
if o in ('--config',):
|
||||
sickbeard.CONFIG_FILE = os.path.abspath(a)
|
||||
|
||||
# Specify folder to use as the data dir
|
||||
if o in ('--datadir',):
|
||||
sickbeard.DATA_DIR = os.path.abspath(a)
|
||||
|
||||
# Prevent resizing of the banner/posters even if PIL is installed
|
||||
if o in ('--noresize',):
|
||||
sickbeard.NO_RESIZE = True
|
||||
|
||||
# Write a pidfile if requested
|
||||
if o in ('--pidfile',):
|
||||
self.CREATEPID = True
|
||||
self.PIDFILE = str(a)
|
||||
|
||||
# If the pidfile already exists, sickbeard may still be running, so exit
|
||||
if os.path.exists(self.PIDFILE):
|
||||
sys.exit("PID file: " + self.PIDFILE + " already exists. Exiting.")
|
||||
|
||||
# The pidfile is only useful in daemon mode, make sure we can write the file properly
|
||||
if self.CREATEPID:
|
||||
if self.runAsDaemon:
|
||||
pid_dir = os.path.dirname(self.PIDFILE)
|
||||
if not os.access(pid_dir, os.F_OK):
|
||||
sys.exit("PID dir: " + pid_dir + " doesn't exist. Exiting.")
|
||||
if not os.access(pid_dir, os.W_OK):
|
||||
sys.exit("PID dir: " + pid_dir + " must be writable (write permissions). Exiting.")
|
||||
|
||||
else:
|
||||
if self.consoleLogging:
|
||||
sys.stdout.write("Not running in daemon mode. PID file creation disabled.\n")
|
||||
|
||||
self.CREATEPID = False
|
||||
|
||||
# If they don't specify a config file then put it in the data dir
|
||||
if not sickbeard.CONFIG_FILE:
|
||||
sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini")
|
||||
|
||||
# Make sure that we can create the data dir
|
||||
if not os.access(sickbeard.DATA_DIR, os.F_OK):
|
||||
try:
|
||||
os.makedirs(sickbeard.DATA_DIR, 0744)
|
||||
except os.error, e:
|
||||
raise SystemExit("Unable to create datadir '" + sickbeard.DATA_DIR + "'")
|
||||
|
||||
# Make sure we can write to the data dir
|
||||
if not os.access(sickbeard.DATA_DIR, os.W_OK):
|
||||
raise SystemExit("Datadir must be writeable '" + sickbeard.DATA_DIR + "'")
|
||||
|
||||
# Make sure we can write to the config file
|
||||
if not os.access(sickbeard.CONFIG_FILE, os.W_OK):
|
||||
if os.path.isfile(sickbeard.CONFIG_FILE):
|
||||
raise SystemExit("Config file '" + sickbeard.CONFIG_FILE + "' must be writeable.")
|
||||
elif not os.access(os.path.dirname(sickbeard.CONFIG_FILE), os.W_OK):
|
||||
raise SystemExit(
|
||||
"Config file root dir '" + os.path.dirname(sickbeard.CONFIG_FILE) + "' must be writeable.")
|
||||
|
||||
# Check if we need to perform a restore first
|
||||
restoreDir = os.path.join(sickbeard.DATA_DIR, 'restore')
|
||||
if os.path.exists(restoreDir):
|
||||
if self.restore(restoreDir, sickbeard.DATA_DIR):
|
||||
logger.log(u"Restore successful...")
|
||||
else:
|
||||
logger.log(u"Restore FAILED!", logger.ERROR)
|
||||
|
||||
os.chdir(sickbeard.DATA_DIR)
|
||||
|
||||
# Load the config and publish it to the sickbeard package
|
||||
if not os.path.isfile(sickbeard.CONFIG_FILE):
|
||||
logger.log(u"Unable to find '" + sickbeard.CONFIG_FILE + "' , all settings will be default!", logger.ERROR)
|
||||
|
||||
sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE)
|
||||
|
||||
CUR_DB_VERSION = db.DBConnection().checkDBVersion()
|
||||
|
||||
if CUR_DB_VERSION > 0:
|
||||
if CUR_DB_VERSION < MIN_DB_VERSION:
|
||||
raise SystemExit("Your database version (" + str(
|
||||
CUR_DB_VERSION) + ") is too old to migrate from with this version of SickRage (" + str(
|
||||
MIN_DB_VERSION) + ").\n" + \
|
||||
"Upgrade using a previous version of SB first, or start with no database file to begin fresh.")
|
||||
if CUR_DB_VERSION > MAX_DB_VERSION:
|
||||
raise SystemExit("Your database version (" + str(
|
||||
CUR_DB_VERSION) + ") has been incremented past what this version of SickRage supports (" + str(
|
||||
MAX_DB_VERSION) + ").\n" + \
|
||||
"If you have used other forks of SB, your database may be unusable due to their modifications.")
|
||||
|
||||
# Initialize the config and our threads
|
||||
sickbeard.initialize(consoleLogging=self.consoleLogging)
|
||||
|
||||
if self.runAsDaemon:
|
||||
self.daemon = Daemon(self.PIDFILE or os.path.join(sickbeard.DATA_DIR, 'sickbeard.pid'))
|
||||
self.daemon.daemonize()
|
||||
|
||||
# Get PID
|
||||
sickbeard.PID = os.getpid()
|
||||
|
||||
if self.forcedPort:
|
||||
logger.log(u"Forcing web server to port " + str(self.forcedPort))
|
||||
self.startPort = self.forcedPort
|
||||
else:
|
||||
self.startPort = sickbeard.WEB_PORT
|
||||
|
||||
if sickbeard.WEB_LOG:
|
||||
self.log_dir = sickbeard.LOG_DIR
|
||||
else:
|
||||
self.log_dir = None
|
||||
|
||||
# sickbeard.WEB_HOST is available as a configuration value in various
|
||||
# places but is not configurable. It is supported here for historic reasons.
|
||||
if sickbeard.WEB_HOST and sickbeard.WEB_HOST != '0.0.0.0':
|
||||
self.webhost = sickbeard.WEB_HOST
|
||||
else:
|
||||
if sickbeard.WEB_IPV6:
|
||||
self.webhost = '::'
|
||||
else:
|
||||
self.webhost = '0.0.0.0'
|
||||
|
||||
# web server options
|
||||
self.web_options = {
|
||||
'port': int(self.startPort),
|
||||
'host': self.webhost,
|
||||
'data_root': os.path.join(sickbeard.PROG_DIR, 'gui', sickbeard.GUI_NAME),
|
||||
'web_root': sickbeard.WEB_ROOT,
|
||||
'log_dir': self.log_dir,
|
||||
'username': sickbeard.WEB_USERNAME,
|
||||
'password': sickbeard.WEB_PASSWORD,
|
||||
'enable_https': sickbeard.ENABLE_HTTPS,
|
||||
'handle_reverse_proxy': sickbeard.HANDLE_REVERSE_PROXY,
|
||||
'https_cert': sickbeard.HTTPS_CERT,
|
||||
'https_key': sickbeard.HTTPS_KEY,
|
||||
}
|
||||
|
||||
# start web server
|
||||
try:
|
||||
self.webserver = SRWebServer(self.web_options)
|
||||
self.webserver.start()
|
||||
except IOError:
|
||||
logger.log(u"Unable to start web server, is something else running on port %d?" % self.startPort,
|
||||
logger.ERROR)
|
||||
if sickbeard.LAUNCH_BROWSER and not self.runAsDaemon:
|
||||
logger.log(u"Launching browser and exiting", logger.ERROR)
|
||||
sickbeard.launchBrowser(self.startPort)
|
||||
os._exit(1)
|
||||
|
||||
if self.consoleLogging:
|
||||
print "Starting up SickRage " + SICKBEARD_VERSION + " from " + sickbeard.CONFIG_FILE
|
||||
|
||||
# Build from the DB to start with
|
||||
loadShowsFromDB()
|
||||
self.loadShowsFromDB()
|
||||
|
||||
# Fire up all our threads
|
||||
sickbeard.start()
|
||||
|
||||
# Launch browser if we're supposed to
|
||||
if sickbeard.LAUNCH_BROWSER and not noLaunch:
|
||||
sickbeard.launchBrowser(startPort)
|
||||
|
||||
# Start an update if we're supposed to
|
||||
if forceUpdate or sickbeard.UPDATE_SHOWS_ON_START:
|
||||
if self.forceUpdate or sickbeard.UPDATE_SHOWS_ON_START:
|
||||
sickbeard.showUpdateScheduler.action.run(force=True) # @UndefinedVariable
|
||||
|
||||
if sickbeard.LAUNCH_BROWSER and not (noLaunch or sickbeard.DAEMON or restart):
|
||||
sickbeard.launchBrowser(startPort)
|
||||
if sickbeard.LAUNCH_BROWSER and not (self.noLaunch or self.runAsDaemon):
|
||||
sickbeard.launchBrowser(self.startPort)
|
||||
|
||||
# reset this if sickrage was restarted
|
||||
restart = False
|
||||
|
||||
# start IO loop
|
||||
IOLoop.current().start()
|
||||
|
||||
# close IO loop
|
||||
IOLoop.current().close(True)
|
||||
|
||||
# stop all tasks
|
||||
sickbeard.halt()
|
||||
|
||||
# save all shows to DB
|
||||
sickbeard.saveAll()
|
||||
while(sickbeard.started):
|
||||
time.sleep(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.hexversion >= 0x020600F0:
|
||||
freeze_support()
|
||||
|
||||
while(not sickbeard.shutdown):
|
||||
main()
|
||||
sr = None
|
||||
try:
|
||||
# init sickrage
|
||||
sr = SickRage()
|
||||
|
||||
logger.log("SickRage is restarting, please stand by ...")
|
||||
restart = True
|
||||
# start sickrage
|
||||
sr.start()
|
||||
|
||||
logger.log("Goodbye ...")
|
||||
# shutdown web server
|
||||
sr.webserver.shutDown()
|
||||
sr.webserver.join()
|
||||
sr.webserver = None
|
||||
|
||||
# if run as daemon delete the pidfile
|
||||
if sr.runAsDaemon:
|
||||
sr.daemon.delpid()
|
||||
|
||||
if not sickbeard.shutdown:
|
||||
install_type = sickbeard.versionCheckScheduler.action.install_type
|
||||
|
||||
popen_list = []
|
||||
|
||||
if install_type in ('git', 'source'):
|
||||
popen_list = [sys.executable, sickbeard.MY_FULLNAME]
|
||||
elif install_type == 'win':
|
||||
if hasattr(sys, 'frozen'):
|
||||
# c:\dir\to\updater.exe 12345 c:\dir\to\sickbeard.exe
|
||||
popen_list = [os.path.join(sickbeard.PROG_DIR, 'updater.exe'), str(sickbeard.PID), sys.executable]
|
||||
else:
|
||||
logger.log(u"Unknown SB launch method, please file a bug report about this", logger.ERROR)
|
||||
popen_list = [sys.executable, os.path.join(sickbeard.PROG_DIR, 'updater.py'), str(sickbeard.PID), sys.executable,
|
||||
sickbeard.MY_FULLNAME]
|
||||
|
||||
if popen_list:
|
||||
popen_list += sickbeard.MY_ARGS
|
||||
if '--nolaunch' not in popen_list:
|
||||
popen_list += ['--nolaunch']
|
||||
logger.log(u"Restarting SickRage with " + str(popen_list))
|
||||
logger.close()
|
||||
subprocess.Popen(popen_list, cwd=os.getcwd())
|
||||
|
||||
# exit process
|
||||
os._exit(0)
|
||||
except:
|
||||
if sr:
|
||||
logger.log(traceback.format_exc(), logger.ERROR)
|
||||
else:
|
||||
print(traceback.format_exc())
|
||||
sys.exit(1)
|
@ -1,26 +1,3 @@
|
||||
'''
|
||||
***
|
||||
Modified generic daemon class
|
||||
***
|
||||
|
||||
Author: http://www.jejik.com/articles/2007/02/
|
||||
a_simple_unix_linux_daemon_in_python/www.boxedice.com
|
||||
|
||||
License: http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
Changes: 23rd Jan 2009 (David Mytton <david@boxedice.com>)
|
||||
- Replaced hard coded '/dev/null in __init__ with os.devnull
|
||||
- Added OS check to conditionally remove code that doesn't
|
||||
work on OS X
|
||||
- Added output to console on completion
|
||||
- Tidied up formatting
|
||||
11th Mar 2009 (David Mytton <david@boxedice.com>)
|
||||
- Fixed problem with daemon exiting on Python 2.4
|
||||
(before SystemExit was part of the Exception base)
|
||||
13th Aug 2010 (David Mytton <david@boxedice.com>
|
||||
- Fixed unhandled exception if PID file is empty
|
||||
'''
|
||||
|
||||
# Core modules
|
||||
import atexit
|
||||
import os
|
||||
@ -57,7 +34,7 @@ class Daemon(object):
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# Exit first parent
|
||||
sys.exit(0)
|
||||
os._exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write(
|
||||
"fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||
@ -73,7 +50,7 @@ class Daemon(object):
|
||||
pid = os.fork()
|
||||
if pid > 0:
|
||||
# Exit from second parent
|
||||
sys.exit(0)
|
||||
os._exit(0)
|
||||
except OSError, e:
|
||||
sys.stderr.write(
|
||||
"fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
|
||||
@ -93,11 +70,6 @@ class Daemon(object):
|
||||
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||
|
||||
def sigtermhandler(signum, frame):
|
||||
self.daemon_alive = False
|
||||
signal.signal(signal.SIGTERM, sigtermhandler)
|
||||
signal.signal(signal.SIGINT, sigtermhandler)
|
||||
|
||||
if self.verbose >= 1:
|
||||
print "Started"
|
||||
|
||||
@ -110,43 +82,38 @@ class Daemon(object):
|
||||
def delpid(self):
|
||||
os.remove(self.pidfile)
|
||||
|
||||
def start(self, daemonize=True, *args, **kwargs):
|
||||
def start(self, *args, **kwargs):
|
||||
"""
|
||||
Start the daemon
|
||||
"""
|
||||
|
||||
if daemonize:
|
||||
if self.verbose >= 1:
|
||||
print "Starting..."
|
||||
if self.verbose >= 1:
|
||||
print "Starting..."
|
||||
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
except SystemExit:
|
||||
pid = None
|
||||
# Check for a pidfile to see if the daemon already runs
|
||||
try:
|
||||
pf = file(self.pidfile, 'r')
|
||||
pid = int(pf.read().strip())
|
||||
pf.close()
|
||||
except IOError:
|
||||
pid = None
|
||||
except SystemExit:
|
||||
pid = None
|
||||
|
||||
if pid:
|
||||
message = "pidfile %s already exists. Is it already running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
if pid:
|
||||
message = "pidfile %s already exists. Is it already running?\n"
|
||||
sys.stderr.write(message % self.pidfile)
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon
|
||||
self.daemonize()
|
||||
self.run(*args, **kwargs)
|
||||
|
||||
def stop(self, daemonize=True):
|
||||
def stop(self):
|
||||
"""
|
||||
Stop the daemon
|
||||
"""
|
||||
|
||||
if not daemonize:
|
||||
return
|
||||
|
||||
if self.verbose >= 1:
|
||||
print "Stopping..."
|
||||
|
||||
@ -185,12 +152,12 @@ class Daemon(object):
|
||||
if self.verbose >= 1:
|
||||
print "Stopped"
|
||||
|
||||
def restart(self, daemonize=True):
|
||||
def restart(self):
|
||||
"""
|
||||
Restart the daemon
|
||||
"""
|
||||
self.stop(daemonize=daemonize)
|
||||
self.start(daemonize=daemonize)
|
||||
self.stop()
|
||||
self.start()
|
||||
|
||||
def get_pid(self):
|
||||
try:
|
||||
|
@ -174,10 +174,19 @@ class LockBase:
|
||||
else:
|
||||
self.tname = ""
|
||||
dirname = os.path.dirname(self.lock_file)
|
||||
|
||||
# unique name is mostly about the current process, but must
|
||||
# also contain the path -- otherwise, two adjacent locked
|
||||
# files conflict (one file gets locked, creating lock-file and
|
||||
# unique file, the other one gets locked, creating lock-file
|
||||
# and overwriting the already existing lock-file, then one
|
||||
# gets unlocked, deleting both lock-file and unique file,
|
||||
# finally the last lock errors out upon releasing.
|
||||
self.unique_name = os.path.join(dirname,
|
||||
"%s%s.%s" % (self.hostname,
|
||||
self.tname,
|
||||
self.pid))
|
||||
"%s%s.%s%s" % (self.hostname,
|
||||
self.tname,
|
||||
self.pid,
|
||||
hash(self.path)))
|
||||
self.timeout = timeout
|
||||
|
||||
def acquire(self, timeout=None):
|
||||
|
@ -28,6 +28,7 @@ from urllib2 import getproxies
|
||||
from threading import Lock
|
||||
|
||||
# apparently py2exe won't build these unless they're imported somewhere
|
||||
import sys
|
||||
from sickbeard import providers, metadata, config, webserveInit
|
||||
from sickbeard.providers.generic import GenericProvider
|
||||
from providers import ezrss, tvtorrents, btn, newznab, womble, thepiratebay, torrentleech, kat, iptorrents, \
|
||||
@ -1269,7 +1270,7 @@ def halt():
|
||||
pass
|
||||
|
||||
__INITIALIZED__ = False
|
||||
|
||||
started = False
|
||||
|
||||
def remove_pid_file(PIDFILE):
|
||||
try:
|
||||
@ -1283,12 +1284,9 @@ def remove_pid_file(PIDFILE):
|
||||
|
||||
|
||||
def sig_handler(signum=None, frame=None):
|
||||
global shutdown
|
||||
|
||||
if type(signum) != type(None):
|
||||
logger.log(u"Signal %i caught, saving and exiting..." % int(signum))
|
||||
shutdown = True
|
||||
IOLoop.current().stop()
|
||||
saveAndShutdown()
|
||||
|
||||
def saveAll():
|
||||
global showList
|
||||
@ -1303,22 +1301,14 @@ def saveAll():
|
||||
save_config()
|
||||
|
||||
def saveAndShutdown(restart=False):
|
||||
global shutdown
|
||||
global shutdown, started
|
||||
|
||||
# flag restart/shutdown
|
||||
if not restart:
|
||||
shutdown = True
|
||||
|
||||
# stop tornado web server
|
||||
webserveInit.server.stop()
|
||||
|
||||
# stop all tasks
|
||||
halt()
|
||||
|
||||
# save all shows to db
|
||||
saveAll()
|
||||
|
||||
#stop tornado io loop
|
||||
IOLoop.current().stop()
|
||||
# proceed with shutdown
|
||||
started = False
|
||||
|
||||
def invoke_command(to_call, *args, **kwargs):
|
||||
|
||||
@ -1333,11 +1323,8 @@ def invoke_command(to_call, *args, **kwargs):
|
||||
def invoke_restart(soft=True):
|
||||
invoke_command(restart, soft=soft)
|
||||
|
||||
|
||||
def invoke_shutdown():
|
||||
global shutdown
|
||||
shutdown = True
|
||||
invoke_command(IOLoop.current().stop)
|
||||
invoke_command(saveAndShutdown, False)
|
||||
|
||||
def restart(soft=True):
|
||||
if soft:
|
||||
@ -1346,7 +1333,7 @@ def restart(soft=True):
|
||||
logger.log(u"Re-initializing all data")
|
||||
initialize()
|
||||
else:
|
||||
IOLoop.current().stop()
|
||||
saveAndShutdown(True)
|
||||
|
||||
|
||||
def save_config():
|
||||
|
@ -349,6 +349,8 @@ class BTNCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -260,6 +260,8 @@ class HDBitsCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
ql.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if ql:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(ql)
|
||||
|
@ -382,6 +382,8 @@ class HDTorrentsCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -323,6 +323,8 @@ class IPTorrentsCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -460,6 +460,8 @@ class KATCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -347,6 +347,8 @@ class NewznabCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
ql.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if ql:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(ql)
|
||||
|
@ -372,6 +372,8 @@ class NextGenCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -345,6 +345,8 @@ class PublicHDCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
ql.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if ql:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(ql)
|
||||
|
@ -367,6 +367,8 @@ class SCCCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -307,6 +307,8 @@ class SpeedCDCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
ql.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if ql:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(ql)
|
||||
|
@ -440,6 +440,8 @@ class ThePirateBayCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -331,6 +331,8 @@ class TorrentDayCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -326,6 +326,8 @@ class TorrentLeechCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -15,6 +15,7 @@
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
|
||||
import time
|
||||
|
||||
import sickbeard
|
||||
import generic
|
||||
@ -73,6 +74,8 @@ class WombleCache(tvcache.TVCache):
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -128,6 +128,8 @@ class TVCache():
|
||||
if ci is not None:
|
||||
cl.append(ci)
|
||||
|
||||
time.sleep(.2)
|
||||
|
||||
if cl:
|
||||
myDB = self._getDB()
|
||||
myDB.mass_action(cl)
|
||||
|
@ -1,5 +1,8 @@
|
||||
import os
|
||||
import traceback
|
||||
import socket
|
||||
import time
|
||||
import threading
|
||||
import sys
|
||||
import sickbeard
|
||||
import webserve
|
||||
import webapi
|
||||
@ -10,9 +13,6 @@ from tornado.web import Application, StaticFileHandler, RedirectHandler, HTTPErr
|
||||
from tornado.httpserver import HTTPServer
|
||||
from tornado.ioloop import IOLoop
|
||||
|
||||
server = None
|
||||
|
||||
|
||||
class MultiStaticFileHandler(StaticFileHandler):
|
||||
def initialize(self, paths, default_filename=None):
|
||||
self.paths = paths
|
||||
@ -34,85 +34,106 @@ class MultiStaticFileHandler(StaticFileHandler):
|
||||
# Oops file not found anywhere!
|
||||
raise HTTPError(404)
|
||||
|
||||
class SRWebServer(threading.Thread):
|
||||
def __init__(self, options=[], io_loop=None):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.alive = True
|
||||
self.name = "TORNADO"
|
||||
self.io_loop = io_loop or IOLoop.current()
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
# tornado setup
|
||||
enable_https = options['enable_https']
|
||||
https_cert = options['https_cert']
|
||||
https_key = options['https_key']
|
||||
# tornado setup
|
||||
self.enable_https = self.options['enable_https']
|
||||
self.https_cert = self.options['https_cert']
|
||||
self.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")
|
||||
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)):
|
||||
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
|
||||
enable_https = False
|
||||
|
||||
if not (os.path.exists(self.https_cert) and os.path.exists(self.https_key)):
|
||||
logger.log(u"Disabled HTTPS because of missing CERT and KEY files", logger.WARNING)
|
||||
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
|
||||
enable_https = False
|
||||
# Load the app
|
||||
self.app = Application([],
|
||||
debug=False,
|
||||
gzip=True,
|
||||
xheaders=sickbeard.HANDLE_REVERSE_PROXY,
|
||||
cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo='
|
||||
)
|
||||
|
||||
# Load the app
|
||||
app = Application([],
|
||||
debug=False,
|
||||
gzip=True,
|
||||
xheaders=sickbeard.HANDLE_REVERSE_PROXY,
|
||||
cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo='
|
||||
)
|
||||
# Main Handler
|
||||
self.app.add_handlers(".*$", [
|
||||
(r"%s" % self.options['web_root'], RedirectHandler, {'url': '%s/home/' % self.options['web_root']}),
|
||||
(r'%s/api/(.*)(/?)' % self.options['web_root'], webapi.Api),
|
||||
(r'%s/(.*)(/?)' % self.options['web_root'], webserve.MainHandler)
|
||||
])
|
||||
|
||||
# Main Handler
|
||||
app.add_handlers(".*$", [
|
||||
(r"%s" % options['web_root'], RedirectHandler, {'url': '%s/home/' % options['web_root']}),
|
||||
(r'%s/api/(.*)(/?)' % options['web_root'], webapi.Api),
|
||||
(r'%s/(.*)(/?)' % options['web_root'], webserve.MainHandler)
|
||||
])
|
||||
# Static Path Handler
|
||||
self.app.add_handlers(".*$", [
|
||||
(r'%s/(favicon\.ico)' % self.options['web_root'], MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(self.options['data_root'], 'images/ico/favicon.ico')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'images'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(self.options['data_root'], 'images'),
|
||||
os.path.join(sickbeard.CACHE_DIR, 'images')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'css'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(self.options['data_root'], 'css')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (self.options['web_root'], 'js'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(self.options['data_root'], 'js')]})
|
||||
|
||||
# Static Path Handler
|
||||
app.add_handlers(".*$", [
|
||||
(r'%s/(favicon\.ico)' % options['web_root'], MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(options['data_root'], 'images/ico/favicon.ico')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (options['web_root'], 'images'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(options['data_root'], 'images'),
|
||||
os.path.join(sickbeard.CACHE_DIR, 'images')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (options['web_root'], 'css'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(options['data_root'], 'css')]}),
|
||||
(r'%s/%s/(.*)(/?)' % (options['web_root'], 'js'), MultiStaticFileHandler,
|
||||
{'paths': [os.path.join(options['data_root'], 'js')]})
|
||||
])
|
||||
|
||||
])
|
||||
def run(self):
|
||||
if self.enable_https:
|
||||
protocol = "https"
|
||||
self.server = HTTPServer(self.app, no_keep_alive=True,
|
||||
ssl_options={"certfile": self.https_cert, "keyfile": self.https_key})
|
||||
else:
|
||||
protocol = "http"
|
||||
self.server = HTTPServer(self.app, no_keep_alive=True)
|
||||
|
||||
global server
|
||||
logger.log(u"Starting SickRage on " + protocol + "://" + str(self.options['host']) + ":" + str(
|
||||
self.options['port']) + "/")
|
||||
|
||||
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)
|
||||
try:
|
||||
self.server.listen(self.options['port'], self.options['host'])
|
||||
except:
|
||||
etype, evalue, etb = sys.exc_info()
|
||||
logger.log("Could not start webserver on %s. Excpeption: %s, Error: %s" % (self.options['port'], etype, evalue), logger.ERROR)
|
||||
return
|
||||
|
||||
logger.log(u"Starting SickRage on " + protocol + "://" + str(options['host']) + ":" + str(
|
||||
options['port']) + "/")
|
||||
try:
|
||||
self.io_loop.start()
|
||||
self.io_loop.close(True)
|
||||
|
||||
server.listen(options['port'], options['host'])
|
||||
# stop all tasks
|
||||
sickbeard.halt()
|
||||
|
||||
def shutdown():
|
||||
# save all shows to DB
|
||||
sickbeard.saveAll()
|
||||
|
||||
logger.log('Shutting down tornado IO loop')
|
||||
try:
|
||||
IOLoop.current().stop()
|
||||
except RuntimeError:
|
||||
pass
|
||||
except:
|
||||
logger.log('Failed shutting down tornado IO loop: %s' % traceback.format_exc(), logger.ERROR)
|
||||
except ValueError:
|
||||
# Ignore errors like "ValueError: I/O operation on closed kqueue fd". These might be thrown during a reload.
|
||||
pass
|
||||
|
||||
def shutDown(self):
|
||||
self.alive = False
|
||||
if self.server:
|
||||
self.server.stop()
|
||||
self.io_loop.stop()
|
Loading…
Reference in New Issue
Block a user