import os import threading import time import traceback import datetime import sickbeard import webserve from sickbeard.exceptions import ex 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, PeriodicCallback class MultiStaticFileHandler(StaticFileHandler): def initialize(self, paths, default_filename=None): self.paths = paths def get(self, path, include_body=True): for p in self.paths: try: # Initialize the Static file with a path super(MultiStaticFileHandler, self).initialize(p) # Try to get the file return super(MultiStaticFileHandler, self).get(path) except HTTPError as exc: # File not found, carry on if exc.status_code == 404: continue raise # Oops file not found anywhere! raise HTTPError(404) class webserverInit(): def __init__(self, options, cycleTime=datetime.timedelta(seconds=3)): self.amActive = False self.lastRun = datetime.datetime.fromordinal(1) self.cycleTime = cycleTime self.abort = False self.server = None self.thread = None 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) 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' ) # Index Handler app.add_handlers(".*$", [ (r"/", RedirectHandler, {'url': '/home/'}), (r'/login', webserve.LoginHandler), (r'%s(.*)(/?)' % self.options['web_root'], webserve.IndexHandler) ]) # 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')]}) ]) 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']) + "/") self.server.listen(self.options['port'], self.options['host']) def start(self): if self.thread == None or not self.thread.isAlive(): self.thread = threading.Thread(None, IOLoop.current().start, 'TORNADO') self.thread.start() def shutdown(self): if self.thread: logger.log('Shutting down tornado') # stop tornado io loop IOLoop.instance().stop() # stop tornado thread try: self.thread.join(10) except: pass # stop tornado http server self.server.stop() # remove thread object self.thread = None