import os import sys import time import logging import logging.config import shutil import json import telnetlib import copy from threading import Thread from api_clients import api_client from configobj import ConfigObj # configure logging logging.config.fileConfig("logging.cfg") # loading config file try: config = ConfigObj('/etc/airtime/pypo.cfg') LS_HOST = config['ls_host'] LS_PORT = config['ls_port'] POLL_INTERVAL = int(config['poll_interval']) except Exception, e: logger = logging.getLogger() logger.error('Error loading config file: %s', e) sys.exit() class PypoFetch(Thread): def __init__(self, pypoFetch_q, pypoPush_q, media_q, telnet_lock): Thread.__init__(self) self.api_client = api_client.api_client_factory(config) self.fetch_queue = pypoFetch_q self.push_queue = pypoPush_q self.media_prepare_queue = media_q self.telnet_lock = telnet_lock self.logger = logging.getLogger(); self.cache_dir = os.path.join(config["cache_dir"], "scheduler") self.logger.debug("Cache dir %s", self.cache_dir) try: if not os.path.isdir(dir): """ We get here if path does not exist, or path does exist but is a file. We are not handling the second case, but don't think we actually care about handling it. """ self.logger.debug("Cache dir does not exist. Creating...") os.makedirs(dir) except Exception, e: pass self.schedule_data = [] self.logger.info("PypoFetch: init complete") """ Handle a message from RabbitMQ, put it into our yucky global var. Hopefully there is a better way to do this. """ def handle_message(self, message): try: self.logger.info("Received event from Pypo Message Handler: %s" % message) m = json.loads(message) command = m['event_type'] self.logger.info("Handling command: " + command) if command == 'update_schedule': self.schedule_data = m['schedule'] self.process_schedule(self.schedule_data) elif command == 'update_stream_setting': self.logger.info("Updating stream setting...") self.regenerateLiquidsoapConf(m['setting']) elif command == 'update_stream_format': self.logger.info("Updating stream format...") self.update_liquidsoap_stream_format(m['stream_format']) elif command == 'update_station_name': self.logger.info("Updating station name...") self.update_liquidsoap_station_name(m['station_name']) elif command == 'switch_source': self.logger.info("switch_on_source show command received...") self.switch_source(m['sourcename'], m['status']) elif command == 'disconnect_source': self.logger.info("disconnect_on_source show command received...") self.disconnect_source(m['sourcename']) except Exception, e: import traceback top = traceback.format_exc() self.logger.error('Exception: %s', e) self.logger.error("traceback: %s", top) self.logger.error("Exception in handling Message Handler message: %s", e) def disconnect_source(self,sourcename): self.logger.debug('Disconnecting source: %s', sourcename) command = "" if(sourcename == "master_dj"): command += "master_harbor.kick\n" elif(sourcename == "live_dj"): command += "live_dj_harbor.kick\n" self.telnet_lock.acquire() try: tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn.write(command) tn.write('exit\n') tn.read_all() except Exception, e: self.logger.error(str(e)) finally: self.telnet_lock.release() def switch_source(self, sourcename, status): self.logger.debug('Switching source: %s to "%s" status', sourcename, status) command = "streams." if(sourcename == "master_dj"): command += "master_dj_" elif(sourcename == "live_dj"): command += "live_dj_" elif(sourcename == "scheduled_play"): command += "scheduled_play_" if(status == "on"): command += "start\n" else: command += "stop\n" self.telnet_lock.acquire() try: tn = telnetlib.Telnet(LS_HOST, LS_PORT) tn.write(command) tn.write('exit\n') tn.read_all() except Exception, e: self.logger.error(str(e)) finally: self.telnet_lock.release() """ grabs some information that are needed to be set on bootstrap time and configures them """ def set_bootstrap_variables(self): self.logger.debug('Getting information needed on bootstrap from Airtime') info = self.api_client.get_bootstrap_info() self.logger.debug('info:%s',info) for k, v in info['switch_status'].iteritems(): self.switch_source(k, v) self.update_liquidsoap_stream_format(info['stream_label']) self.update_liquidsoap_station_name(info['station_name']) def regenerateLiquidsoapConf(self, setting_p): existing = {} # create a temp file fh = open('/etc/airtime/liquidsoap.cfg', 'r') self.logger.info("Reading existing config...") # read existing conf file and build dict while 1: line = fh.readline() if not line: break line = line.strip() if line.find('#') == 0: continue # if empty line if not line: continue key, value = line.split(' = ') key = key.strip() value = value.strip() value = value.replace('"', '') if value == "" or value == "0": value = '' existing[key] = value fh.close() # dict flag for any change in cofig change = {} # this flag is to detect diable -> disable change # in that case, we don't want to restart even if there are chnges. state_change_restart = {} #restart flag restart = False self.logger.info("Looking for changes...") setting = sorted(setting_p.items()) # look for changes for k, s in setting: if "output_sound_device" in s[u'keyname'] or "icecast_vorbis_metadata" in s[u'keyname']: dump, stream = s[u'keyname'].split('_', 1) state_change_restart[stream] = False # This is the case where restart is required no matter what if (existing[s[u'keyname']] != s[u'value']): self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname']) restart = True; elif "master_live_stream_port" in s[u'keyname'] or "master_live_stream_mp" in s[u'keyname'] or "dj_live_stream_port" in s[u'keyname'] or "dj_live_stream_mp" in s[u'keyname']: if (existing[s[u'keyname']] != s[u'value']): self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname']) restart = True; else: stream, dump = s[u'keyname'].split('_',1) if "_output" in s[u'keyname']: if (existing[s[u'keyname']] != s[u'value']): self.logger.info("'Need-to-restart' state detected for %s...", s[u'keyname']) restart = True; state_change_restart[stream] = True elif ( s[u'value'] != 'disabled'): state_change_restart[stream] = True else: state_change_restart[stream] = False else: # setting inital value if stream not in change: change[stream] = False if not (s[u'value'] == existing[s[u'keyname']]): self.logger.info("Keyname: %s, Curent value: %s, New Value: %s", s[u'keyname'], existing[s[u'keyname']], s[u'value']) change[stream] = True # set flag change for sound_device alway True self.logger.info("Change:%s, State_Change:%s...", change, state_change_restart) for k, v in state_change_restart.items(): if k == "sound_device" and v: restart = True elif v and change[k]: self.logger.info("'Need-to-restart' state detected for %s...", k) restart = True # rewrite if restart: fh = open('/etc/airtime/liquidsoap.cfg', 'w') self.logger.info("Rewriting liquidsoap.cfg...") fh.write("################################################\n") fh.write("# THIS FILE IS AUTO GENERATED. DO NOT CHANGE!! #\n") fh.write("################################################\n") for k, d in setting: buffer_str = d[u'keyname'] + " = " if(d[u'type'] == 'string'): temp = d[u'value'] if(temp == ""): temp = "" buffer_str += "\"" + temp + "\"" else: temp = d[u'value'] if(temp == ""): temp = "0" buffer_str += temp buffer_str += "\n" fh.write(api_client.encode_to(buffer_str)) fh.write("log_file = \"/var/log/airtime/pypo-liquidsoap/