CC-4910: Need to properly handle non-200 http status codes in api client

-fixed
This commit is contained in:
Martin Konecny 2013-02-04 16:05:58 -05:00
parent 20a3f674b4
commit 331386f74f
12 changed files with 156 additions and 156 deletions

View File

@ -146,7 +146,6 @@ class AirtimeApiClient(object):
sys.exit(1) sys.exit(1)
def __get_airtime_version(self): def __get_airtime_version(self):
# TODO : maybe fix this function to drop an exception?
try: return self.services.version_url()[u'version'] try: return self.services.version_url()[u'version']
except Exception: return -1 except Exception: return -1
@ -154,18 +153,18 @@ class AirtimeApiClient(object):
logger = self.logger logger = self.logger
version = self.__get_airtime_version() version = self.__get_airtime_version()
# logger.info('Airtime version found: ' + str(version)) # logger.info('Airtime version found: ' + str(version))
if (version == -1): if version == -1:
if (verbose): if (verbose):
logger.info('Unable to get Airtime version number.\n') logger.info('Unable to get Airtime version number.\n')
return False return False
elif (version[0:3] != AIRTIME_VERSION[0:3]): elif version[0:3] != AIRTIME_VERSION[0:3]:
if (verbose): if verbose:
logger.info('Airtime version found: ' + str(version)) logger.info('Airtime version found: ' + str(version))
logger.info('pypo is at version ' + AIRTIME_VERSION + logger.info('pypo is at version ' + AIRTIME_VERSION +
' and is not compatible with this version of Airtime.\n') ' and is not compatible with this version of Airtime.\n')
return False return False
else: else:
if (verbose): if verbose:
logger.info('Airtime version: ' + str(version)) logger.info('Airtime version: ' + str(version))
logger.info('pypo is at version ' + AIRTIME_VERSION + ' and is compatible with this version of Airtime.') logger.info('pypo is at version ' + AIRTIME_VERSION + ' and is compatible with this version of Airtime.')
return True return True
@ -193,14 +192,6 @@ class AirtimeApiClient(object):
self.logger.error(str(e)) self.logger.error(str(e))
return None return None
# TODO : get this routine out of here it doesn't belong at all here
def get_liquidsoap_data(self, pkey, schedule):
playlist = schedule[pkey]
data = dict()
try: data["schedule_id"] = playlist['id']
except Exception: data["schedule_id"] = 0
return data
def get_shows_to_record(self): def get_shows_to_record(self):
try: try:
return self.services.show_schedule_url() return self.services.show_schedule_url()
@ -259,12 +250,12 @@ class AirtimeApiClient(object):
url = url.replace("%%api_key%%", self.config["api_key"]) url = url.replace("%%api_key%%", self.config["api_key"])
return url return url
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def setup_media_monitor(self): def setup_media_monitor(self):
try: return self.services.media_setup_url()
return self.services.media_setup_url()
except Exception, e:
#TODO
self.logger.info(str(e))
def send_media_monitor_requests(self, action_list, dry=False): def send_media_monitor_requests(self, action_list, dry=False):
""" """
@ -323,37 +314,40 @@ class AirtimeApiClient(object):
self.logger.error("Could not find index 'files' in dictionary: %s", self.logger.error("Could not find index 'files' in dictionary: %s",
str(response)) str(response))
return [] return []
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def list_all_watched_dirs(self): def list_all_watched_dirs(self):
try: return self.services.list_all_watched_dirs()
return self.services.list_all_watched_dirs()
except Exception, e:
#TODO
self.logger.error(str(e))
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def add_watched_dir(self, path): def add_watched_dir(self, path):
try: return self.services.add_watched_dir(path=base64.b64encode(path))
return self.services.add_watched_dir(path=base64.b64encode(path))
except Exception, e:
#TODO
self.logger.error(str(e))
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def remove_watched_dir(self, path): def remove_watched_dir(self, path):
try: return self.services.remove_watched_dir(path=base64.b64encode(path))
return self.services.remove_watched_dir(path=base64.b64encode(path))
except Exception, e:
#TODO
self.logger.error(str(e))
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def set_storage_dir(self, path): def set_storage_dir(self, path):
return self.services.set_storage_dir(path=base64.b64encode(path)) return self.services.set_storage_dir(path=base64.b64encode(path))
"""
Caller of this method needs to catch any exceptions such as
ValueError thrown by json.loads or URLError by urllib2.urlopen
"""
def get_stream_setting(self): def get_stream_setting(self):
logger = self.logger return self.services.get_stream_setting()
try: return self.services.get_stream_setting()
except Exception, e:
logger.error("Exception: %s", e)
return None
def register_component(self, component): def register_component(self, component):
""" Purpose of this method is to contact the server with a "Hey its """ Purpose of this method is to contact the server with a "Hey its
@ -361,11 +355,7 @@ class AirtimeApiClient(object):
(component = media-monitor, pypo etc.) ip address, and later use it (component = media-monitor, pypo etc.) ip address, and later use it
to query monit via monit's http service, or download log files via a to query monit via monit's http service, or download log files via a
http server. """ http server. """
try: return self.services.register_component(component=component)
return self.services.register_component(component=component)
except Exception, e:
#TODO
self.logger.error(str(e))
def notify_liquidsoap_status(self, msg, stream_id, time): def notify_liquidsoap_status(self, msg, stream_id, time):
logger = self.logger logger = self.logger
@ -388,11 +378,7 @@ class AirtimeApiClient(object):
def get_bootstrap_info(self): def get_bootstrap_info(self):
""" Retrieve infomations needed on bootstrap time """ """ Retrieve infomations needed on bootstrap time """
try: return self.services.get_bootstrap_info()
return self.services.get_bootstrap_info()
except Exception, e:
#TODO
self.logger.error(str(e))
def get_files_without_replay_gain_value(self, dir_id): def get_files_without_replay_gain_value(self, dir_id):
""" """
@ -404,8 +390,8 @@ class AirtimeApiClient(object):
try: try:
return self.services.get_files_without_replay_gain(dir_id=dir_id) return self.services.get_files_without_replay_gain(dir_id=dir_id)
except Exception, e: except Exception, e:
#TODO
self.logger.error(str(e)) self.logger.error(str(e))
return []
def get_files_without_silan_value(self): def get_files_without_silan_value(self):
""" """
@ -416,20 +402,16 @@ class AirtimeApiClient(object):
try: try:
return self.services.get_files_without_silan_value() return self.services.get_files_without_silan_value()
except Exception, e: except Exception, e:
#TODO
self.logger.error(str(e)) self.logger.error(str(e))
return []
def update_replay_gain_values(self, pairs): def update_replay_gain_values(self, pairs):
""" """
'pairs' is a list of pairs in (x, y), where x is the file's database 'pairs' is a list of pairs in (x, y), where x is the file's database
row id and y is the file's replay_gain value in dB row id and y is the file's replay_gain value in dB
""" """
try: self.logger.debug(self.services.update_replay_gain_value(
self.logger.debug(self.services.update_replay_gain_value( _post_data={'data': json.dumps(pairs)}))
_post_data={'data': json.dumps(pairs)}))
except Exception, e:
#TODO
self.logger.error(str(e))
def update_cue_values_by_silan(self, pairs): def update_cue_values_by_silan(self, pairs):
@ -437,11 +419,7 @@ class AirtimeApiClient(object):
'pairs' is a list of pairs in (x, y), where x is the file's database 'pairs' is a list of pairs in (x, y), where x is the file's database
row id and y is the file's cue values in dB row id and y is the file's cue values in dB
""" """
try: return self.services.update_cue_values_by_silan(_post_data={'data': json.dumps(pairs)})
print self.services.update_cue_values_by_silan(_post_data={'data': json.dumps(pairs)})
except Exception, e:
#TODO
self.logger.error(str(e))
def notify_webstream_data(self, data, media_id): def notify_webstream_data(self, data, media_id):
@ -449,30 +427,18 @@ class AirtimeApiClient(object):
Update the server with the latest metadata we've received from the Update the server with the latest metadata we've received from the
external webstream external webstream
""" """
try: self.logger.info( self.services.notify_webstream_data.req(
self.logger.info( self.services.notify_webstream_data.req( _post_data={'data':data}, media_id=str(media_id)).retry(5))
_post_data={'data':data}, media_id=str(media_id)).retry(5))
except Exception, e:
#TODO
self.logger.error(str(e))
def get_stream_parameters(self): def get_stream_parameters(self):
try: response = self.services.get_stream_parameters()
response = self.services.get_stream_parameters() self.logger.debug(response)
self.logger.debug(response) return response
return response
except Exception, e:
#TODO
self.logger.error(str(e))
def push_stream_stats(self, data): def push_stream_stats(self, data):
# TODO : users of this method should do their own error handling # TODO : users of this method should do their own error handling
try: response = self.services.push_stream_stats(_post_data={'data': json.dumps(data)})
response = self.services.push_stream_stats(_post_data={'data': json.dumps(data)}) return response
return response
except Exception, e:
#TODO
self.logger.error(str(e))
def update_stream_setting_table(self, data): def update_stream_setting_table(self, data):
try: try:

View File

@ -58,18 +58,18 @@ class AirtimeMediaMonitorBootstrap():
""" """
returns the path and its corresponding database row idfor all watched directories. Also returns the path and its corresponding database row idfor all watched directories. Also
returns the Stor directory, which can be identified by its row id (always has value of "1") returns the Stor directory, which can be identified by its row id (always has value of "1")
Return type is a dictionary similar to: Return type is a dictionary similar to:
{"1":"/srv/airtime/stor/"} {"1":"/srv/airtime/stor/"}
""" """
def get_list_of_watched_dirs(self): def get_list_of_watched_dirs(self):
json = self.api_client.list_all_watched_dirs() json = self.api_client.list_all_watched_dirs()
try: try:
return json["dirs"] return json["dirs"]
except KeyError as e: except KeyError as e:
self.logger.error("Could not find index 'dirs' in dictionary: %s", str(json)) self.logger.error("Could not find index 'dirs' in dictionary: %s", str(json))
self.logger.error(e) self.logger.error(str(e))
return {} return {}
""" """
@ -94,7 +94,7 @@ class AirtimeMediaMonitorBootstrap():
db_known_files_set = set() db_known_files_set = set()
files = self.list_db_files(dir_id) files = self.list_db_files(dir_id)
for f in files: for f in files:
db_known_files_set.add(f) db_known_files_set.add(f)

View File

@ -19,31 +19,35 @@ class AirtimeDB(Loggable):
saas = user().root_path saas = user().root_path
# dirs_setup is a dict with keys: try:
# u'watched_dirs' and u'stor' which point to lists of corresponding # dirs_setup is a dict with keys:
# dirs # u'watched_dirs' and u'stor' which point to lists of corresponding
dirs_setup = self.apc.setup_media_monitor() # dirs
dirs_setup[u'stor'] = normpath( join(saas, dirs_setup[u'stor'] ) ) dirs_setup = self.apc.setup_media_monitor()
dirs_setup[u'watched_dirs'] = map(lambda p: normpath(join(saas,p)), dirs_setup[u'stor'] = normpath( join(saas, dirs_setup[u'stor'] ) )
dirs_setup[u'watched_dirs']) dirs_setup[u'watched_dirs'] = map(lambda p: normpath(join(saas,p)),
dirs_with_id = dict([ (k,normpath(v)) for k,v in dirs_setup[u'watched_dirs'])
self.apc.list_all_watched_dirs()['dirs'].iteritems() ]) dirs_with_id = dict([ (k,normpath(v)) for k,v in
self.apc.list_all_watched_dirs()['dirs'].iteritems() ])
self.id_to_dir = dirs_with_id self.id_to_dir = dirs_with_id
self.dir_to_id = dict([ (v,k) for k,v in dirs_with_id.iteritems() ]) self.dir_to_id = dict([ (v,k) for k,v in dirs_with_id.iteritems() ])
self.base_storage = dirs_setup[u'stor'] self.base_storage = dirs_setup[u'stor']
self.storage_paths = mmp.expand_storage( self.base_storage ) self.storage_paths = mmp.expand_storage( self.base_storage )
self.base_id = self.dir_to_id[self.base_storage] self.base_id = self.dir_to_id[self.base_storage]
# hack to get around annoying schema of airtime db # hack to get around annoying schema of airtime db
self.dir_to_id[ self.recorded_path() ] = self.base_id self.dir_to_id[ self.recorded_path() ] = self.base_id
self.dir_to_id[ self.import_path() ] = self.base_id self.dir_to_id[ self.import_path() ] = self.base_id
# We don't know from the x_to_y dict which directory is watched or
# store...
self.watched_directories = set([ os.path.normpath(p) for p in
dirs_setup[u'watched_dirs'] ])
except Exception, e:
self.logger.info(str(e))
# We don't know from the x_to_y dict which directory is watched or
# store...
self.watched_directories = set([ os.path.normpath(p) for p in
dirs_setup[u'watched_dirs'] ])
def to_id(self, directory): def to_id(self, directory):
""" directory path -> id """ """ directory path -> id """

View File

@ -85,7 +85,15 @@ class MM2(InstanceThread, Loggable):
ToucherThread(path=user().touch_file_path(), ToucherThread(path=user().touch_file_path(),
interval=int(config['touch_interval'])) interval=int(config['touch_interval']))
apiclient.register_component('media-monitor') success = False
while not success:
try:
apiclient.register_component('media-monitor')
success = True
except Exception, e:
self.logger.error(str(e))
import time
time.sleep(10)
manager.loop() manager.loop()

View File

@ -26,13 +26,10 @@ def generate_liquidsoap_config(ss):
logging.basicConfig(format='%(message)s') logging.basicConfig(format='%(message)s')
ac = AirtimeApiClient(logging.getLogger()) ac = AirtimeApiClient(logging.getLogger())
ss = ac.get_stream_setting() try:
ss = ac.get_stream_setting()
if ss is not None: generate_liquidsoap_config(ss)
try: except Exception, e:
generate_liquidsoap_config(ss) logging.error(str(e))
except Exception, e:
logging.error(e)
else:
print "Unable to connect to the Airtime server." print "Unable to connect to the Airtime server."
sys.exit(1) sys.exit(1)

View File

@ -103,7 +103,10 @@ class ListenerStat(Thread):
self.update_listener_stat_error(v["mount"], 'OK') self.update_listener_stat_error(v["mount"], 'OK')
except Exception, e: except Exception, e:
self.logger.error('Exception: %s', e) self.logger.error('Exception: %s', e)
self.update_listener_stat_error(v["mount"], str(e)) try:
self.update_listener_stat_error(v["mount"], str(e))
except Exception, e:
self.logger.error('Exception: %s', e)
return stats return stats

View File

@ -67,15 +67,15 @@ class ReplayGainUpdater(Thread):
self.logger.error(e) self.logger.error(e)
self.logger.debug(traceback.format_exc()) self.logger.debug(traceback.format_exc())
def run(self): def run(self):
try: while True:
while True: try:
self.logger.info("Runnning replaygain updater") self.logger.info("Running replaygain updater")
self.main() self.main()
# Sleep for 5 minutes in case new files have been added # Sleep for 5 minutes in case new files have been added
time.sleep(60 * 5) except Exception, e:
except Exception, e: self.logger.error('ReplayGainUpdater Exception: %s', traceback.format_exc())
self.logger.error('ReplayGainUpdater Exception: %s', traceback.format_exc()) self.logger.error(e)
self.logger.error(e) time.sleep(60 * 5)
if __name__ == "__main__": if __name__ == "__main__":
rgu = ReplayGainUpdater() rgu = ReplayGainUpdater()

View File

@ -179,7 +179,14 @@ if __name__ == '__main__':
ReplayGainUpdater.start_reply_gain(api_client) ReplayGainUpdater.start_reply_gain(api_client)
api_client.register_component("pypo") success = False
while not success:
try:
api_client.register_component('pypo')
success = True
except Exception, e:
logger.error(str(e))
time.sleep(10)
pypoFetch_q = Queue() pypoFetch_q = Queue()
recorder_q = Queue() recorder_q = Queue()

View File

@ -206,23 +206,25 @@ class PypoFetch(Thread):
""" """
def set_bootstrap_variables(self): def set_bootstrap_variables(self):
self.logger.debug('Getting information needed on bootstrap from Airtime') self.logger.debug('Getting information needed on bootstrap from Airtime')
info = self.api_client.get_bootstrap_info() try:
if info is None: info = self.api_client.get_bootstrap_info()
except Exception, e:
self.logger.error('Unable to get bootstrap info.. Exiting pypo...') self.logger.error('Unable to get bootstrap info.. Exiting pypo...')
else: self.logger.error(str(e))
self.logger.debug('info:%s', info)
commands = []
for k, v in info['switch_status'].iteritems():
commands.append(self.switch_source_temp(k, v))
stream_format = info['stream_label'] self.logger.debug('info:%s', info)
station_name = info['station_name'] commands = []
fade = info['transition_fade'] for k, v in info['switch_status'].iteritems():
commands.append(self.switch_source_temp(k, v))
commands.append(('vars.stream_metadata_type %s\n' % stream_format).encode('utf-8')) stream_format = info['stream_label']
commands.append(('vars.station_name %s\n' % station_name).encode('utf-8')) station_name = info['station_name']
commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8')) fade = info['transition_fade']
PypoFetch.telnet_send(self.logger, self.telnet_lock, commands)
commands.append(('vars.stream_metadata_type %s\n' % stream_format).encode('utf-8'))
commands.append(('vars.station_name %s\n' % station_name).encode('utf-8'))
commands.append(('vars.default_dj_fade %s\n' % fade).encode('utf-8'))
PypoFetch.telnet_send(self.logger, self.telnet_lock, commands)
def restart_liquidsoap(self): def restart_liquidsoap(self):

View File

@ -189,9 +189,17 @@ class Recorder(Thread):
self.server_timezone = '' self.server_timezone = ''
self.queue = q self.queue = q
self.loops = 0 self.loops = 0
self.api_client.register_component("show-recorder")
self.logger.info("RecorderFetch: init complete") self.logger.info("RecorderFetch: init complete")
success = False
while not success:
try:
self.api_client.register_component('show-recorder')
success = True
except Exception, e:
self.logger.error(str(e))
time.sleep(10)
def handle_message(self): def handle_message(self):
if not self.queue.empty(): if not self.queue.empty():
message = self.queue.get() message = self.queue.get()

View File

@ -75,15 +75,16 @@ def format_dir_string(path):
return path return path
def helper_get_stor_dir(): def helper_get_stor_dir():
res = api_client.list_all_watched_dirs() try:
if(res is None): res = api_client.list_all_watched_dirs()
except Exception, e:
return res return res
if(res['dirs']['1'][-1] != '/'):
out = res['dirs']['1']+'/'
return out
else: else:
if(res['dirs']['1'][-1] != '/'): return res['dirs']['1']
out = res['dirs']['1']+'/'
return out
else:
return res['dirs']['1']
def checkOtherOption(args): def checkOtherOption(args):
for i in args: for i in args:
@ -162,8 +163,9 @@ def WatchAddAction(option, opt, value, parser):
path = apc.encode_to(path, 'utf-8') path = apc.encode_to(path, 'utf-8')
if(os.path.isdir(path)): if(os.path.isdir(path)):
#os.chmod(path, 0765) #os.chmod(path, 0765)
res = api_client.add_watched_dir(path) try:
if(res is None): res = api_client.add_watched_dir(path)
except Exception, e:
exit("Unable to connect to the server.") exit("Unable to connect to the server.")
# sucess # sucess
if(res['msg']['code'] == 0): if(res['msg']['code'] == 0):
@ -179,8 +181,9 @@ def WatchListAction(option, opt, value, parser):
errorIfMultipleOption(parser.rargs) errorIfMultipleOption(parser.rargs)
if(len(parser.rargs) > 0): if(len(parser.rargs) > 0):
raise OptionValueError("This option doesn't take any arguments.") raise OptionValueError("This option doesn't take any arguments.")
res = api_client.list_all_watched_dirs() try:
if(res is None): res = api_client.list_all_watched_dirs()
except Exception, e:
exit("Unable to connect to the Airtime server.") exit("Unable to connect to the Airtime server.")
dirs = res["dirs"].items() dirs = res["dirs"].items()
# there will be always 1 which is storage folder # there will be always 1 which is storage folder
@ -204,8 +207,9 @@ def WatchRemoveAction(option, opt, value, parser):
path = currentDir+path path = currentDir+path
path = apc.encode_to(path, 'utf-8') path = apc.encode_to(path, 'utf-8')
if(os.path.isdir(path)): if(os.path.isdir(path)):
res = api_client.remove_watched_dir(path) try:
if(res is None): res = api_client.remove_watched_dir(path)
except Exception, e:
exit("Unable to connect to the Airtime server.") exit("Unable to connect to the Airtime server.")
# sucess # sucess
if(res['msg']['code'] == 0): if(res['msg']['code'] == 0):
@ -249,10 +253,11 @@ def StorageSetAction(option, opt, value, parser):
path = currentDir+path path = currentDir+path
path = apc.encode_to(path, 'utf-8') path = apc.encode_to(path, 'utf-8')
if(os.path.isdir(path)): if(os.path.isdir(path)):
res = api_client.set_storage_dir(path) try:
if(res is None): res = api_client.set_storage_dir(path)
except Exception, e:
exit("Unable to connect to the Airtime server.") exit("Unable to connect to the Airtime server.")
# sucess # success
if(res['msg']['code'] == 0): if(res['msg']['code'] == 0):
print "Successfully set storage folder to %s" % path print "Successfully set storage folder to %s" % path
else: else:

View File

@ -68,7 +68,7 @@ try:
subtotal += total subtotal += total
total = 0 total = 0
try: try:
api_client.update_cue_values_by_silan(processed_data) print api_client.update_cue_values_by_silan(processed_data)
except Exception ,e: except Exception ,e:
print e print e
print traceback.format_exc() print traceback.format_exc()