Fixed issues with restarts and updates.

This commit is contained in:
echel0n 2014-06-15 22:45:52 -07:00
parent 4676c2b7b1
commit d8358882de
7 changed files with 102 additions and 88 deletions

View file

@ -385,6 +385,7 @@ def main():
# start IOLoop
IOLoop.current().start()
sickbeard.saveAndShutdown()
return
if __name__ == "__main__":

View file

@ -37,7 +37,7 @@ function is_alive() {
$('#restart_loading').hide();
$('#restart_success').show();
$('#refresh_message').show();
window.location = sb_base_url+'/home';
window.location = sb_base_url+'/home/';
}
}
}, 'jsonp');
@ -66,7 +66,7 @@ $(document).ready(function()
$('#restart_success').show();
$('#refresh_message').show();
}, 3000);
setTimeout("window.location = sb_base_url+'/home'", 5000);
setTimeout("window.location = sb_base_url+'/home/'", 5000);
}
}

View file

@ -105,6 +105,7 @@ CUR_COMMIT_HASH = None
INIT_LOCK = Lock()
__INITIALIZED__ = False
started = False
restarted = False
ACTUAL_LOG_DIR = None
LOG_DIR = None
@ -1292,16 +1293,7 @@ def saveAll():
logger.log(u"Saving config file to disk")
save_config()
def saveAndShutdown(restart=False):
if not restart:
logger.log('Shutting down tornado')
try:
IOLoop.current().stop()
except RuntimeError:
pass
except:
logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR)
def saveAndShutdown():
halt()
saveAll()
@ -1309,7 +1301,7 @@ def saveAndShutdown(restart=False):
logger.log(u"Removing pidfile " + str(PIDFILE))
remove_pid_file(PIDFILE)
if restart:
if restarted:
install_type = versionCheckScheduler.action.install_type
popen_list = []
@ -1352,18 +1344,20 @@ def invoke_restart(soft=True):
def invoke_shutdown():
invoke_command(saveAndShutdown)
invoke_command(webserveInit.shutdown)
def restart(soft=True):
global restarted
if soft:
halt()
saveAll()
logger.log(u"Re-initializing all data")
initialize()
else:
saveAndShutdown(restart=True)
restarted=True
webserveInit.shutdown()
def save_config():

View file

@ -102,10 +102,10 @@ def foldersAtPath(path, includeParent=False):
class WebFileBrowser(RequestHandler):
def index(self, path=''):
HTTPHeaders()['Content-Type'] = "application/json"
self.set_header("Content-Type", "application/json")
return self.finish(json.dumps(foldersAtPath(path, True)))
def complete(self, term):
HTTPHeaders()['Content-Type'] = "application/json"
self.set_header("Content-Type", "application/json")
paths = [entry['path'] for entry in foldersAtPath(os.path.dirname(term)) if 'path' in entry]
return self.finish(json.dumps(paths))

View file

@ -157,14 +157,14 @@ class Api(webserve.IndexHandler):
else:
t.apikey = "api key not generated"
return self.finish(webserve._munge(t))
return webserve._munge(t)
def _out_as_json(self, dict):
""" set cherrypy response to json """
self.h["content-type"] = "application/json;charset=UTF-8"
self.set_header("Content-Type", "application/json")
try:
out = json.dumps(dict, indent=self.intent, sort_keys=True)
callback = self.h.get('callback' ,None) or self.h.get('jsonp' ,None)
callback = self.request.headers.get('callback', None) or self.request.headers.get('jsonp', None)
if callback != None:
out = callback + '(' + out + ');' # wrap with JSONP call if requested
except Exception, e: # if we fail to generate the output fake an error
@ -175,7 +175,7 @@ class Api(webserve.IndexHandler):
def _grand_access(self, realKey, args, kwargs):
""" validate api key and log result """
remoteIp = sickbeard.REMOTE_IP
remoteIp = self.request.remote_ip
apiKey = kwargs.get("apikey", None)
if not apiKey:
if args: # if we have keyless vars we assume first one is the api key, always !
@ -1506,7 +1506,7 @@ class CMD_SickBeardPing(ApiCall):
def run(self):
""" check to see if sickbeard is running """
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
if sickbeard.started:
return _responds(RESULT_SUCCESS, {"pid": sickbeard.PID}, "Pong")
else:

View file

@ -28,12 +28,8 @@ import re
import threading
import datetime
import random
from Cheetah.Template import Template
import sys
from tornado import gen
from tornado.httputil import HTTPHeaders
from tornado.web import RequestHandler, HTTPError, asynchronous, authenticated
import sickbeard
from sickbeard import config, sab
@ -80,13 +76,19 @@ except ImportError:
from lib import adba
#def _handle_reverse_proxy():
from Cheetah.Template import Template
from tornado import gen
from tornado.web import RequestHandler, HTTPError, asynchronous, authenticated
# def _handle_reverse_proxy():
# if sickbeard.HANDLE_REVERSE_PROXY:
# cherrypy.lib.cptools.proxy()
# cherrypy.tools.handle_reverse_proxy = cherrypy.Tool('before_handler', _handle_reverse_proxy)
req_headers = None
def require_basic_auth(handler_class):
def wrap_execute(handler_execute):
def require_basic_auth(handler, kwargs):
@ -115,15 +117,18 @@ def require_basic_auth(handler_class):
handler.clear_cookie("user")
get_auth()
def _execute(self, transforms, *args, **kwargs):
if not require_basic_auth(self, kwargs):
return False
return handler_execute(self, transforms, *args, **kwargs)
return _execute
handler_class._execute = wrap_execute(handler_class._execute)
return handler_class
class RedirectHandler(RequestHandler):
"""Redirects the client to the given URL for all GET requests.
@ -133,47 +138,25 @@ class RedirectHandler(RequestHandler):
(r"/oldpath", web.RedirectHandler, {"url": "/newpath"}),
])
"""
def get(self, path):
self.redirect(path, permanent=True)
@require_basic_auth
class LoginHandler(RedirectHandler):
def get(self, path):
self.redirect(self.get_argument("next", u"/"))
@require_basic_auth
class IndexHandler(RedirectHandler):
def __init__(self, application, request, **kwargs):
super(IndexHandler, self).__init__(application, request, **kwargs)
global req_headers
self.remote_ip = sickbeard.REMOTE_IP = self.request.headers.get('X-Forwarded-For',
self.request.headers.get('X-Real-Ip', self.request.remote_ip))
self.h = HTTPHeaders({"content-type": "text/html"})
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.h['Content-Type'] = 'text/javascript'
self.h['Access-Control-Allow-Origin'] = '*'
self.h['Access-Control-Allow-Headers'] = 'x-requested-with'
if 'Host' in self.h:
if self.h['Host'][0] == '[':
self.sbHost = re.match("^\[.*\]", self.h['Host'], re.X | re.M | re.S).group(0)
else:
self.sbHost = re.match("^[^:]+", self.h['Host'], re.X | re.M | re.S).group(0)
if sickbeard.NZBS and sickbeard.NZBS_UID and sickbeard.NZBS_HASH:
logger.log(u"NZBs.org has been replaced, please check the config to configure the new provider!",
logger.ERROR)
ui.notifications.error("NZBs.org Config Update",
"NZBs.org has a new site. Please <a href=\"" + sickbeard.WEB_ROOT + "/config/providers\">update your config</a> with the api key from <a href=\"http://nzbs.org/login\">http://nzbs.org</a> and then disable the old NZBs.org provider.")
if "X-Forwarded-Host" in self.h:
self.sbHost = self.h['X-Forwarded-Host']
if "X-Forwarded-Port" in self.h:
sbHttpPort = self.h['X-Forwarded-Port']
self.sbHttpsPort = sbHttpPort
if "X-Forwarded-Proto" in self.h:
self.sbHttpsEnabled = True if self.h['X-Forwarded-Proto'] == 'https' else False
sickbeard.REMOTE_IP = self.request.remote_ip
req_headers = self.request.headers
def delist_arguments(self, args):
"""
@ -200,8 +183,10 @@ class IndexHandler(RedirectHandler):
return inspect.isclass(c) and c.__module__ == pred.__module__
try:
klass = [cls[1] for cls in inspect.getmembers(sys.modules[__name__], pred) + [(self.__class__.__name__, self.__class__)] if
cls[0].lower() == method.lower() or method in cls[1].__dict__.keys()][0](self.application, self.request)
klass = [cls[1] for cls in
inspect.getmembers(sys.modules[__name__], pred) + [(self.__class__.__name__, self.__class__)] if
cls[0].lower() == method.lower() or method in cls[1].__dict__.keys()][0](self.application,
self.request)
except:
klass = None
@ -416,7 +401,7 @@ class IndexHandler(RedirectHandler):
""" Provides a subscribeable URL for iCal subscriptions
"""
logger.log(u"Receiving iCal request from %s" % self.request.remote.ip)
logger.log(u"Receiving iCal request from %s" % self.request.remote_ip)
poster_url = self.request.url().replace('ical', '')
@ -479,18 +464,33 @@ class IndexHandler(RedirectHandler):
browser = WebFileBrowser
class PageTemplate(Template):
def __init__(self, *args, **KWs):
KWs['file'] = os.path.join(sickbeard.PROG_DIR, "gui/" + sickbeard.GUI_NAME + "/interfaces/default/",
KWs['file'])
super(PageTemplate, self).__init__(*args, **KWs)
global req_headers
self.sbRoot = sickbeard.WEB_ROOT
self.sbHttpPort = sickbeard.WEB_PORT
self.sbHttpsPort = sickbeard.WEB_PORT
self.sbHost = sickbeard.WEB_HOST
self.sbHttpsEnabled = sickbeard.ENABLE_HTTPS
self.sbHandleReverseProxy = sickbeard.HANDLE_REVERSE_PROXY
if req_headers['Host'][0] == '[':
self.sbHost = re.match("^\[.*\]", req_headers['Host'], re.X | re.M | re.S).group(0)
else:
self.sbHost = re.match("^[^:]+", req_headers['Host'], re.X | re.M | re.S).group(0)
if "X-Forwarded-Host" in req_headers:
self.sbHost = req_headers['X-Forwarded-Host']
if "X-Forwarded-Port" in req_headers:
sbHttpPort = req_headers['X-Forwarded-Port']
self.sbHttpsPort = sbHttpPort
if "X-Forwarded-Proto" in req_headers:
self.sbHttpsEnabled = True if req_headers['X-Forwarded-Proto'] == 'https' else False
logPageTitle = 'Logs &amp; Errors'
if len(classes.ErrorViewer.errors):
logPageTitle += ' (' + str(len(classes.ErrorViewer.errors)) + ')'
@ -1070,8 +1070,8 @@ class Manage(IndexHandler):
exceptions_list = []
curErrors += self.editShow(curShow, new_show_dir, anyQualities, bestQualities, exceptions_list,
new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime,
scene=new_scene, directCall=True)
new_flatten_folders, new_paused, subtitles=new_subtitles, anime=new_anime,
scene=new_scene, directCall=True)
if curErrors:
logger.log(u"Errors: " + str(curErrors), logger.ERROR)
@ -1346,6 +1346,7 @@ ConfigMenu = [
{'title': 'Anime', 'path': 'config/anime/'},
]
class ConfigGeneral(IndexHandler):
def index(self, *args, **kwargs):
@ -2432,8 +2433,8 @@ class ConfigAnime(IndexHandler):
self.redirect("/config/anime/")
class Config(IndexHandler):
class Config(IndexHandler):
def index(self, *args, **kwargs):
t = PageTemplate(file="config.tmpl")
t.submenu = ConfigMenu
@ -2449,6 +2450,7 @@ class Config(IndexHandler):
notifications = ConfigNotifications
anime = ConfigAnime
def haveXBMC():
return sickbeard.USE_XBMC and sickbeard.XBMC_UPDATE_LIBRARY
@ -2976,6 +2978,11 @@ class Home(IndexHandler):
else:
return "Error: Unsupported Request. Send jsonp request with 'callback' variable in the query string."
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
self.set_header('Content-Type', 'text/javascript')
self.set_header('Access-Control-Allow-Origin', '*')
self.set_header('Access-Control-Allow-Headers', 'x-requested-with')
if sickbeard.started:
return callback + '(' + json.dumps({"msg": str(sickbeard.PID)}) + ');'
else:
@ -3031,7 +3038,7 @@ class Home(IndexHandler):
def testGrowl(self, host=None, password=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host, default_port=23053)
@ -3048,7 +3055,7 @@ class Home(IndexHandler):
def testProwl(self, prowl_api=None, prowl_priority=0):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.prowl_notifier.test_notify(prowl_api, prowl_priority)
if result:
@ -3058,7 +3065,7 @@ class Home(IndexHandler):
def testBoxcar(self, username=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.boxcar_notifier.test_notify(username)
if result:
@ -3068,7 +3075,7 @@ class Home(IndexHandler):
def testBoxcar2(self, accesstoken=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.boxcar2_notifier.test_notify(accesstoken)
if result:
@ -3078,7 +3085,7 @@ class Home(IndexHandler):
def testPushover(self, userKey=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.pushover_notifier.test_notify(userKey)
if result:
@ -3088,13 +3095,13 @@ class Home(IndexHandler):
def twitterStep1(self, *args, **kwargs):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
return notifiers.twitter_notifier._get_authorization()
def twitterStep2(self, key):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.twitter_notifier._get_credentials(key)
logger.log(u"result: " + str(result))
@ -3105,7 +3112,7 @@ class Home(IndexHandler):
def testTwitter(self, *args, **kwargs):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.twitter_notifier.test_notify()
if result:
@ -3115,7 +3122,7 @@ class Home(IndexHandler):
def testXBMC(self, host=None, username=None, password=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_hosts(host)
finalResult = ''
@ -3131,7 +3138,7 @@ class Home(IndexHandler):
def testPLEX(self, host=None, username=None, password=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
finalResult = ''
for curHost in [x.strip() for x in host.split(",")]:
@ -3146,7 +3153,7 @@ class Home(IndexHandler):
def testLibnotify(self, *args, **kwargs):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
if notifiers.libnotify_notifier.test_notify():
return "Tried sending desktop notification via libnotify"
@ -3155,7 +3162,7 @@ class Home(IndexHandler):
def testNMJ(self, host=None, database=None, mount=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host)
result = notifiers.nmj_notifier.test_notify(urllib.unquote_plus(host), database, mount)
@ -3166,7 +3173,7 @@ class Home(IndexHandler):
def settingsNMJ(self, host=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host)
result = notifiers.nmj_notifier.notify_settings(urllib.unquote_plus(host))
@ -3178,7 +3185,7 @@ class Home(IndexHandler):
def testNMJv2(self, host=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host)
result = notifiers.nmjv2_notifier.test_notify(urllib.unquote_plus(host))
@ -3189,7 +3196,7 @@ class Home(IndexHandler):
def settingsNMJv2(self, host=None, dbloc=None, instance=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host)
result = notifiers.nmjv2_notifier.notify_settings(urllib.unquote_plus(host), dbloc, instance)
@ -3202,7 +3209,7 @@ class Home(IndexHandler):
def testTrakt(self, api=None, username=None, password=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.trakt_notifier.test_notify(api, username, password)
if result:
@ -3212,7 +3219,7 @@ class Home(IndexHandler):
def loadShowNotifyLists(self, *args, **kwargs):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
with db.DBConnection() as myDB:
rows = myDB.select("SELECT show_id, show_name, notify_list FROM tv_shows ORDER BY show_name ASC")
@ -3227,7 +3234,7 @@ class Home(IndexHandler):
def testEmail(self, host=None, port=None, smtp_from=None, use_tls=None, user=None, pwd=None, to=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
host = config.clean_host(host)
if notifiers.email_notifier.test_notify(host, port, smtp_from, use_tls, user, pwd, to):
@ -3237,7 +3244,7 @@ class Home(IndexHandler):
def testNMA(self, nma_api=None, nma_priority=0):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.nma_notifier.test_notify(nma_api, nma_priority)
if result:
@ -3247,7 +3254,7 @@ class Home(IndexHandler):
def testPushalot(self, authorizationToken=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.pushalot_notifier.test_notify(authorizationToken)
if result:
@ -3257,7 +3264,7 @@ class Home(IndexHandler):
def testPushbullet(self, api=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.pushbullet_notifier.test_notify(api)
if result:
@ -3267,7 +3274,7 @@ class Home(IndexHandler):
def getPushbulletDevices(self, api=None):
self.h['Cache-Control'] = "max-age=0,no-cache,no-store"
self.set_header('Cache-Control', "max-age=0,no-cache,no-store")
result = notifiers.pushbullet_notifier.get_devices(api)
if result:

View file

@ -1,5 +1,7 @@
import os
import traceback
import sickbeard
from tornado.ioloop import IOLoop
import webserve
import webapi
@ -93,9 +95,10 @@ def initWebServer(options={}):
# Load the app
app = Application([],
debug=False,
debug=True,
gzip=True,
autoreload=True,
xheaders=False,
cookie_secret='61oETzKXQAGaYdkL5gEmGeJJFuYh7EQnp2XdTP1o/Vo=',
login_url='/login'
)
@ -135,3 +138,12 @@ def initWebServer(options={}):
options['port']) + "/")
server.listen(options['port'], options['host'])
def shutdown():
logger.log('Shutting down tornado')
try:
IOLoop.current().stop()
except RuntimeError:
pass
except:
logger.log('Failed shutting down the server: %s' % traceback.format_exc(), logger.ERROR)