示例#1
0
def scheduler(request):
    scheduler_path =  settings.SCHEDULER_PATH
    schedulerconfig = CombaSchedulerConfig(scheduler_path)
    jobs =  schedulerconfig.getJobs()
    jobs = sorted(jobs, key=lambda k: k['time'])
    html = render_to_string('scheduler.html', {'jobs':jobs})
    data = {'data': html}
    return HttpResponse(simplejson.dumps(data),content_type='application/json')
示例#2
0
 def scheduler_data(self):
     """
     Scheduler Config ausliefern
     """
     jobs = []
     
     try:
         # Das scheduler.xml laden            
         schedulerconfig = CombaSchedulerConfig(self.sender.schedule_config)
         jobs = schedulerconfig.getJobs()
     except:
         # Das scheint kein gültiges XML zu sein            
         self.warning('01', False)
                 
     self.success('00', simplejson.dumps(jobs))
     self.notifyClient()
示例#3
0
 def scheduler_store(self, adminuser, adminpassword, json):
     """
     Scheduler Config zurückschreiben
     """   
     if not self.userdb.hasAdminRights(adminuser, adminpassword):        
         self.warning('01', False)
         self.notifyClient()
         return
     try:
         schedulerconfig = CombaSchedulerConfig(self.sender.schedule_config)
     except:
         self.warning('02', False)
         self.notifyClient()
     try:
         schedulerconfig.storeJsonToXml( base64.b64decode(json))
     except:
         self.warning('02', False)
         self.notifyClient()
     else:                    
         if self.scheduler_reload():
             self.success('00', True)
         else:
             self.warning('02', False)            
     self.notifyClient()
示例#4
0
 def getJobs(self):
     error_type = 'fatal' if self.initial else 'error'
     try:
         # Das scheduler.xml laden
         self.config = CombaSchedulerConfig(self.config_path)
     except:
         # Das scheint kein gültiges XML zu sein
         self.messenger.send('Config is broken', '0301', error_type, 'loadConfig', None, 'config')
         # Wenn das beim Start passiert können wir nix tun
         if self.initial:
             self.ready = False
         return False
     jobs = self.config.getJobs()
     
     for job in jobs:
         if job['job'] == 'start_recording' or job['job'] == 'play_playlist':
             stopjob = self._getStopJob(job)
             jobs.append(stopjob)
             
     return jobs   
示例#5
0
    def start(self):      
        """
        Monitor Loop starten
        """
        self.config = CombaSchedulerConfig(self.config_path)
        #TODO: Unterscheide bei den Funktionsnamen zwischen scheduler.xml und comba.ini
        ## die comba.ini laden
        self.loadConfig()
        self.messenger.setMailAddresses(self.get('frommail'), self.get('adminmail'))
        ## die scheduler.xml laden
        self._loadConfig()

        # Der erste Watcher ist ein Signal-Watcher, der den sauberen Abbruch ermöglicht
        self.watchers = [pyev.Signal(sig, self.loop, self.signal_cb)
                         for sig in self.stopsignals]
        
        self.watchers.append(self.loop.timer(0, 20, self.checkComponents))
        
        self.watchers.append(self.loop.timer(0, 60, self.checkPlaylistEvent))        
        
        # Der dritte Watcher sendet alle 20 Sekunden ein Lebenszeichen
        say_alive = self.loop.timer(0, 20, self.sayAlive) 

        #self.audiowatcher = self.loop.timer(0, 0,self.combine_audiofiles, self.audiowatcher_data)
        self.watchers.append(say_alive)
        
        # Alle watcher starten
        for watcher in self.watchers:
            watcher.start()        
        
        logging.debug("{0}: started".format(self))             
        try:
            self.loop.start()
        except:
            self.messenger.send("Loop did'nt start", '0101', 'fatal', 'appstart' , None, 'appinternal')
        else:
            self.messenger.send("Monitor started", '0100', 'success', 'appstart' , None, 'appinternal')    
示例#6
0
class CombaScheduler(CombaBase):

    def __init__(self, CombaClient_instance, config):
        """
        Constructor
        @type    CombaClient_instance: object
        @param   CombaClient_instance: Der Client für Liquidsoap
        @type    config:               string
        @param   config:               Pfad zum scheduler.xml
        """
        self.client = CombaClient_instance
        self.loadConfig()
        # Messenger für Systemzustände initieren
        self.messenger = CombaMessenger()
        self.messenger.setChannel('scheduler')
        self.messenger.setSection('execjob')
        self.messenger.setMailAddresses(self.get('frommail'), self.get('adminmail'))
        self.config_path = config
        self.config = object

        # Die Signale, die Abbruch signalisieren
        self.stopsignals = (signal.SIGTERM, signal.SIGINT)

        # das pyev Loop-Object
        self.loop = pyev.default_loop()

        # Das ist kein Reload
        self.initial = True

        # Der Scheduler wartet noch auf den Start Befehl
        self.ready = False

        # DIe Config laden
        self._loadConfig()

        self.scriptdir = os.path.dirname(os.path.abspath(__file__)) + '/..'

        errors_file = os.path.dirname(os.path.realpath(__file__)) + '/error/combas_error.js'
        json_data = open(errors_file)
        self.errorData = simplejson.load(json_data)

        self.messenger.send('Scheduler started', '0000', 'success', 'initApp', None, 'appinternal')

    #------------------------------------------------------------------------------------------#
    def set(self, key, value):
        """
        Eine property setzen
        @type    key: string
        @param   key: Der Key
        @type    value: mixed
        @param   value: Beliebiger Wert
        """
        self.__dict__[key] = value

    #------------------------------------------------------------------------------------------#
    def reload(self):
        """
        Reload Scheduler - Config neu einlesen
        """
        self.stop()
        # Scheduler Config neu laden
        if self._loadConfig():
            self.messenger.send('Scheduler reloaded by user', '0500', 'success', 'reload', None, 'appinternal')
        self.start()

    #------------------------------------------------------------------------------------------#
    def _loadConfig(self):
        """
        Scheduler-Config importieren
        @rtype:   boolean
        @return:  True/False
        """
        # Wenn das Scheduling bereits läuft, muss der Scheduler nicht unbedingt angehalten werden         
        error_type = 'fatal' if self.initial else 'error'
        watcher_jobs = self.getJobs()
        try:
            # Die Jobs aus der Config ...
            watcher_jobs = self.getJobs()
        except:
            self.messenger.send('Config is broken', '0301', error_type, 'loadConfig', None, 'config')
            if self.initial:
                self.ready = False
            return False

            # Fehlermeldung senden, wenn keine Jobs gefunden worden sind
        if len(watcher_jobs) == 0:
            self.messenger.send('No Jobs found in Config', '0302', error_type, 'loadConfig', None, 'config')

        # Der erste Watcher ist ein Signal-Watcher, der den sauberen Abbruch ermöglicht
        self.watchers = [pyev.Signal(sig, self.loop, self.signal_cb)
                         for sig in self.stopsignals]

        # Der zweite Watcher soll das Signal zum Reload der Config ermöglicen
        sig_reload = self.loop.signal(signal.SIGUSR1, self.signal_reload)

        self.watchers.append(sig_reload)

        # Der dritte Watcher sendet alle 20 Sekunden ein Lebenszeichen
        say_alive = self.loop.timer(0, 20, self.sayAlive)

        self.watchers.append(say_alive)

        # Der vierte Watcher schaut alle 20 Sekunden nach, ob eine Vorproduktion eingespielt werden soll
        lookup_prearranged = self.loop.timer(0, 20, self.lookup_prearranged)

        self.watchers.append(lookup_prearranged)

        # Der fünfte Watcher führt initiale Jobs durch
        on_start = self.loop.timer(0, 30, self.on_start)

        self.watchers.append(on_start)

        # Nun Watcher für alle Jobs aus der Config erstellen 
        for watcher_job in watcher_jobs:
            watcher = pyev.Scheduler(self.schedule_job, self.loop, self.exec_job, watcher_job)
            # Jeder watcher wird von der Scheduler Funktion schedule_job schedult und vom Callback exec_job ausgeführt
            # watcher_job wird an watcher.data übergeben 
            # schedule_job meldet an den Loop den nächsten Zeitpunkt von watcher_job['time']
            # exec_job führt die Funktion dieser Klasse aus, die von watcher_job['job'] bezeichnet wird
            self.watchers.append(watcher)

        # Es kann losgehen        
        self.ready = True
        return True

    def getJobs(self):
        error_type = 'fatal' if self.initial else 'error'
        try:
            # Das scheduler.xml laden
            self.config = CombaSchedulerConfig(self.config_path)
        except:
            # Das scheint kein gültiges XML zu sein
            self.messenger.send('Config is broken', '0301', error_type, 'loadConfig', None, 'config')
            # Wenn das beim Start passiert können wir nix tun
            if self.initial:
                self.ready = False
            return False
        jobs = self.config.getJobs()
        
        for job in jobs:
            if job['job'] == 'start_recording' or job['job'] == 'play_playlist':
                stopjob = self._getStopJob(job)
                jobs.append(stopjob)
                
        return jobs   
            
    # -----------------------------------------------------------------------#
    def _getStopJob(self, startjob):
         job = {}
         job['job'] = 'stop_playlist' if startjob['job'] == 'play_playlist' else 'stop_recording'
         if startjob['day'] == 'all':
             job['day'] = startjob['day']
         else:
             
             if startjob['time'] < startjob['until']:
                 job['day'] = startjob['day']
             else:
                try:
                     day = int(startjob['day'])
                     stopday = 0 if  day > 5 else day+1
                     job['day'] = str(stopday)
                except:
                    job['day'] = 'all'
                
         job['time'] = startjob['until']  
         return job

    #------------------------------------------------------------------------------------------#
    def start(self):
        """
        Event Loop starten
        """
        # Alle watcher starten
        for watcher in self.watchers:
            watcher.start()

        logging.debug("{0}: started".format(self))
        try:
            self.loop.start()
        except:
            self.messenger.send("Loop did'nt start", '0302', 'fatal', 'appstart', None, 'appinternal')
        else:
            self.messenger.send("Scheduler started", '0100', 'success', 'appstart', None, 'appinternal')

    #------------------------------------------------------------------------------------------#
    def stop(self):
        """
        Event Loop stoppen
        """
        self.loop.stop(pyev.EVBREAK_ALL)
        # alle watchers stoppen und entfernen
        while self.watchers:
            self.watchers.pop().stop()
        self.messenger.send("Loop stopped", '0400', 'success', 'appstart', None, 'appinternal')

    #------------------------------------------------------------------------------------------#
    def sayAlive(self, watcher, revents):
        """
        Alle 20 Sekunden ein Lebenssignal senden
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  revents: object
        @param revents: Event Callbacks    
        """
        self.messenger.sayAlive()

    #------------------------------------------------------------------------------------------#
    def signal_cb(self, loop, revents):
        """
        Signalverarbeitung bei Abbruch
        @type  loop: object
        @param loop: Das py_ev loop Objekt
        @type  revents: object
        @param revents: Event Callbacks
        """
        self.messenger.send("Received stop signal", '1100', 'success', 'appstop', None, 'appinternal')
        self.stop()

    #------------------------------------------------------------------------------------------#
    def signal_reload(self, loop, revents):
        """
        Lädt Scheduling-Konfiguration neu bei Signal SIGUSR1
        @type  loop: object
        @param loop: Das py_ev loop Objekt
        @type  revents: object
        @param revents: Event Callbacks        
        """
        self.messenger.send("Comba Scheduler gracefull restarted", '1200', 'success', 'appreload', None, 'appinternal')
        self.reload()

    #------------------------------------------------------------------------------------------#
    def schedule_job(self, watcher, now):
        """
        Callback zum Scheduling eines Jobs
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  now:      float 
        @param now:      Aktuelle Zeit in Sekunden        
        @rtype:          float
        @return:         Die Zeit zu der der Job ausgeführt werden soll in Sekunden
        """
        # nächstes Ereignis dieses Watchers aus den watcher data
        data = watcher.data.copy()
        next_schedule = data['time']

        # Minuten und Stunden
        (next_hour, next_minute) = next_schedule.split(':')

        # Zum Vergleich die aktuelle und die auszuführende Unhrzeit in Integer wandeln
        today_time = int(datetime.datetime.now().strftime('%H%M'))
        next_time = int(next_hour + next_minute)

        # Wenn der Job erst morgen ausgeführt werden soll ist day_offset 1 
        day_offset = 1 if (today_time >= next_time) else 0

        # Ist ein Tag angegeben
        if data.has_key('day'):
            try:
                #Montag ist 0 
                dayofweek = int(data['day'])
                delta = relativedelta(hour=int(next_hour), minute=int(next_minute), second=0, microsecond=0,
                                      weekday=dayofweek)
            except:
                #Fallback -  day ist vermutlich ein String
                delta = relativedelta(hour=int(next_hour), minute=int(next_minute), second=0, microsecond=0)
        else:
            delta = relativedelta(hour=int(next_hour), minute=int(next_minute), second=0, microsecond=0)

        # Ermittle das Datumsobjekt 
        schedule_result = datetime.datetime.now() + timedelta(day_offset) + delta

        # In Sekunden umrechnen
        result = time.mktime(schedule_result.timetuple())

        schedule_time_human = datetime.datetime.fromtimestamp(int(result)).strftime('%Y-%m-%d %H:%M:%S')
        time_now = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H:%M:%S')
        date_human = datetime.datetime.fromtimestamp(int(result)).strftime('%Y-%m-%d')
        time_human = datetime.datetime.fromtimestamp(int(result)).strftime('%H:%M')
        # Events feuern, zum stoppen und starten einer Playlist
        # TODO: Diese events müssen bei einem Reset gelöscht werden       
        # Es sollte sicher sein, einfach alle keys mit  playerevent_*_playliststart unc playerevent_*_playliststop zu löschen
        if data.has_key('job'):
            if data['job'] == 'play_playlist':
                event = {'job': 'play_playlist', 'date': date_human, 'time': time_human}
                self.messenger.queueAddEvent('playliststart', str(schedule_time_human).replace(' ', 'T'), event,
                                             'player')
            if data['job'] == 'stop_playlist':
                event = {'job': 'stop_playlist', 'date': date_human, 'time': time_human}
                self.messenger.queueAddEvent('playliststop', str(schedule_time_human).replace(' ', 'T'), event,
                                             'player')

        data['scheduled_at'] = time_now
        data['scheduled_for'] = schedule_time_human

        self.info('schedule_job', data, '00', simplejson.dumps(data), 'schedulejob')

        # das nächste mal starten wir diesen Job in result Sekunden 
        return result

    #------------------------------------------------------------------------------------------#
    def exec_job(self, watcher, revents):
        """
        Callback, um einen Job auszuführen
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  revents:  object
        @param revents:  Event Callbacks     
        """
        data = watcher.data.copy()

        # Welcher Job ausgeführt werden soll wird in watcher.data vermerkt
        job = data['job']

        # Job ausführen
        try:
            exec "a=self." + job + "(data)"
        except Exception, e:
            data['exec'] = 'exec"a=self.' + job + '(' + simplejson.dumps(data) + ')"'
            data['Exception'] = str(e)
            self.fatal('exec_job', data, '01', simplejson.dumps(data))
            watcher.stop()  #stop the watcher
        else:
示例#7
0
class CombaMonitor(CombaBase):
    # Constructor
    def __init__(self, CombaClient_instance):
        """
        Constructor
        @type    CombaClient_instance: object
        @param   CombaClient_instance: Der Client für Liquidsoap
        """        
        self.client = CombaClient_instance
        
        # Messenger für Systemzustände initieren
        self.messenger = CombaMessenger()
        self.messenger.setChannel('monitor')
        self.messenger.setSection('execjob')
        
        self.playlistwatchers = []
        self.watchers = []
        
        # das pyev Loop-Object
        self.loop = pyev.default_loop()
        self.playlistwatcher_loop = pyev.Loop()
        # Die Signale, die Abbruch signalisieren
        self.stopsignals = (signal.SIGTERM, signal.SIGINT)
        
        # Das ist kein Reload
        self.initial = True
        self.config = object
        self.config_path = ""
        self.stop_time = ''
        self.start_time = ''
        self.duration = ""

        # Der Monitor wartet noch auf den Start Befehl
        self.ready = False

        self.block_combine = False
        
        errors_file = os.path.dirname(os.path.realpath(__file__)) + '/error/combam_error.js'
        json_data = open(errors_file)
        self.errorData = simplejson.load(json_data)
        self.livetime = False

        self.messenger.send('Monitor started', '0000', 'success', 'initApp' , None, 'appinternal')
        
    #------------------------------------------------------------------------------------------#
    def _loadConfig(self):
        """
        Scheduler-Config importieren
        @rtype:   boolean
        @return:  True/False
        """        
        # Wenn das Scheduling bereits läuft, muss der Scheduler nicht unbedingt angehalten werden         
        error_type = 'fatal' if self.initial else 'error'
        try:
            # Das scheduler.xml laden
            watcher_jobs = self.config.getJobs()
        except:

            # Das scheint kein gültiges XML zu sein
            self.messenger.send('Config is broken', '0301', error_type, 'loadConfig' , None, 'config')
            # Wenn das beim Start passiert können wir nix tun
            if self.initial: 
                self.ready = False                                
            return False

        # Fehlermeldung senden, wenn keine Jobs gefunden worden sind
        if len(watcher_jobs) == 0:
            self.messenger.send('No Jobs found in Config', '0302', error_type, 'loadConfig' , None, 'config')
                 
        # Anhand der Jobs weitere Daten ermitteln, die für interne Zwecke benötigt werden
        self._get_jobs_infos(watcher_jobs)
        # Es kann losgehen        
        self.ready = True
        return True

    #------------------------------------------------------------------------------------------#
    def _get_jobs_infos(self, jobs):
        """
        Ermittelt aus der Start- und Stopzeit der Playlist Dauer der Automatisierung und die Startzeit
        @type    jobs: list
        @param   jobs: Liste mit den Jobs
        """

        self.livetime = True
        now = datetime.datetime.now()
        # Jobs nach Start und Stop-Zeit der Playlist durchsuchen

        for job in jobs:

            if job['job'] ==  'play_playlist':
                if self.config.in_timeperiod(now,job):
                    self.livetime   = False
                    self.start_time = job['time']
                    self.stop_time  = job['until']
                    self.duration   = int(job['duration'])

            elif job['job'] ==  'start_recording' and self.config.in_timeperiod(now,job):
                self.start_time = job['time']
                self.stop_time  =  job['until']
                self.duration = int(job['duration'])

    #------------------------------------------------------------------------------------------#
    def set(self, key, value):
        """
        Eine property setzen
        @type    key: string
        @param   key: Der Key
        @type    value: mixed
        @param   value: Beliebiger Wert
        """
        self.__dict__[key] = value        

    #------------------------------------------------------------------------------------------#
    def start(self):      
        """
        Monitor Loop starten
        """
        self.config = CombaSchedulerConfig(self.config_path)
        #TODO: Unterscheide bei den Funktionsnamen zwischen scheduler.xml und comba.ini
        ## die comba.ini laden
        self.loadConfig()
        self.messenger.setMailAddresses(self.get('frommail'), self.get('adminmail'))
        ## die scheduler.xml laden
        self._loadConfig()

        # Der erste Watcher ist ein Signal-Watcher, der den sauberen Abbruch ermöglicht
        self.watchers = [pyev.Signal(sig, self.loop, self.signal_cb)
                         for sig in self.stopsignals]
        
        self.watchers.append(self.loop.timer(0, 20, self.checkComponents))
        
        self.watchers.append(self.loop.timer(0, 60, self.checkPlaylistEvent))        
        
        # Der dritte Watcher sendet alle 20 Sekunden ein Lebenszeichen
        say_alive = self.loop.timer(0, 20, self.sayAlive) 

        #self.audiowatcher = self.loop.timer(0, 0,self.combine_audiofiles, self.audiowatcher_data)
        self.watchers.append(say_alive)
        
        # Alle watcher starten
        for watcher in self.watchers:
            watcher.start()        
        
        logging.debug("{0}: started".format(self))             
        try:
            self.loop.start()
        except:
            self.messenger.send("Loop did'nt start", '0101', 'fatal', 'appstart' , None, 'appinternal')
        else:
            self.messenger.send("Monitor started", '0100', 'success', 'appstart' , None, 'appinternal')    
    
    #------------------------------------------------------------------------------------------#
    def stop(self):
        """
        Event Loop stoppen
        """
        self.loop.stop(pyev.EVBREAK_ALL)
        # alle watchers stoppen und entfernen
        while self.watchers:
            self.watchers.pop().stop()
        self.messenger.send("Loop stopped", '0400', 'success', 'appstart' , None, 'appinternal')        

    #------------------------------------------------------------------------------------------#
    def sayAlive(self, watcher, revents):
        """
        Alle 20 Sekunden ein Lebenssignal senden
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  revents: object
        @param revents: Event Callbacks    
        """
        self.messenger.sayAlive()

    #------------------------------------------------------------------------------------------#
    def signal_cb(self, loop, revents):
        """
        Signalverarbeitung bei Abbruch
        @type  loop: object
        @param loop: Das py_ev loop Objekt
        @type  revents: object
        @param revents: Event Callbacks
        """
        self.messenger.send("Received stop signal", '1100', 'success', 'appstop' , None, 'appinternal')           
        self.stop()

    #------------------------------------------------------------------------------------------#
    def checkComponents(self, watcher, revents):
        """
        Alle 20 Sekunden Checken, ob Komponenten noch laufen
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  revents: object
        @param revents: Event Callbacks    
        """

        if not self.messenger.getAliveState('scheduler'):            
            self.messenger.send("Scheduler is down... try to start scheduler", '0201', 'error', 'checkComponents' , None, 'appinternal')
            self._restartScheduler()

        if not self.messenger.getAliveState('controller'):            
            self.messenger.send("Controller is down... try to start controller", '0202', 'error', 'checkComponents' , None, 'appinternal')
            self._restartController()
        
        if not self.messenger.getAliveState('record') or not self.messenger.getAliveState('altrecord') or not self.messenger.getAliveState('playd'):
            self.messenger.send("Liquidsoap components are down... try to start soundengine components", '0202', 'error', 'checkComponents' , None, 'appinternal')
            self._restartLiquidsoap()
            time.sleep(10);

            jobs = self.config.getJobs()
            self._get_jobs_infos(jobs)
            if self.livetime:
                for i in '123':                    
                    if self.messenger.getAliveState('record'):
                        self.messenger.send("Start recorder", '0204', 'info', 'checkComponents' , None, 'appinternal')
                        start_new_thread(self._restartRecord,())                                                                    
                        break;
                    time.sleep(20);
            else:
                for i in '123':                    
                    if self.messenger.getAliveState('playd'):

                        self.messenger.send("Start playlist", '0205', 'info', 'checkComponents' , None, 'appinternal')
                        start_new_thread(self._reloadPlaylist,())                        
                        break;
                    time.sleep(20);

        if not self.messenger.getAliveState('archive'):
            self.messenger.send("Archive is down... try to start archive", '0201', 'error', 'checkComponents' , None, 'appinternal')
            self._restartArchive()


    #------------------------------------------------------------------------------------------#
    def checktrack(self, watcher, revents):
        """
        Einen Track checken und ggf. den Player anhalten oder skippen
        @type  watcher:  object
        @param watcher:  Das watcher Objekt
        @type  revents: object
        @param revents: Event Callbacks
        """
        
        def playlist_stop(wait):
            """
            Interne Routine - stoppt den Player
            @type wait: string
            @param wait: Anz. Sekunden nach der der Player wieder gestartet wird
            """
            self.client.playlist_stop()
            time.sleep(int(wait))
            self.client.playlist_play()
        
        def playlist_skip(wait):
            """
            Interne Routine - skippt den Player
            @type wait: string
            @param wait: Anz. Sekunden nach der der Player geskippt wird
            """            
            time.sleep(int(wait))
            self.client.playlist_skip()            
        # Watcher stoppen
        watcher.stop()
        stopforDuration = 0
        skipafterDuration = 0         
        
        if not watcher.data.has_key('location'):
            return False    
        
        # Dauer des Tracks lt. Playlist
        duration = int(watcher.data['length'])  
        
        # Dateipfad
        fname = watcher.data['location'].replace('file://', '')
        
        # Wenn die Datei nicht existiert, muss der Player für die Dauer des Tracks angehalten werden
        if not os.path.isfile(fname):
            stopforDuration = str(duration)        
            start_new_thread(playlist_stop,(stopforDuration,))

        else:
            # Dauer der WAV-Datei ermitteln
            with contextlib.closing(wave.open(fname,'r')) as f:
                frames = f.getnframes()
                rate = f.getframerate()
                fduration = int(math.ceil(frames / float(rate)))
                
                # Ist die Dauer der WAV-Datei kleiner als die angegebene Dauer des Tracks,
                # muss  die Playlist um die Differenz angehalten werden  
                if fduration < duration:
                    stopforDuration = str(duration - fduration)
                    start_new_thread(playlist_stop,(stopforDuration,))

                # Ist die Dauer der WAV-Datei größer als die angegebene Dauer des Tracks,
                # muss der laufende Track nach der Diffenz geskippt
                elif fduration > duration:
                    skipafterDuration = str(fduration - duration)
                    start_new_thread(playlist_skip,(skipafterDuration,))

    #------------------------------------------------------------------------------------------#
    def checkPlaylistEvent(self, watcher, revents):
        """
        Prüft ob der LoaPlaylist event gefeurt wurde und reagiert ggf.
        """            
        eventFired = self.messenger.getEvent('loadplaylist','player')
        if eventFired:
            eventQueue = self.messenger.getEventQueue('playtrack', 'player')
            
               
            if not eventQueue or not isinstance(eventQueue, list):
                self.messenger.send('No event queue present', '1301', 'warning', 'checkPlaylistEvent' , None, 'events')

            else:
                
                # stop all playlist watchers
                for watcher in self.playlistwatchers:
                    watcher.stop()
                    self.playlistwatchers = []
                cnt = 0
                self.playlistwatcher_loop.stop()
                self.playlistwatcher_loop = pyev.Loop()
    
                for index, item in enumerate(eventQueue):
                    cnt = cnt + 10
                    if not item.has_key('date') or not item.has_key('time'):
                        # funny
                        continue
                    
                    # Sekunden berechnen nach der Timer gestartet wird
                    track_time = int(datetime.datetime.strptime(item['date'][0:10] + 'T' + item['time'],"%Y-%m-%dT%H:%M").strftime("%s")) - 1
                    self.playlistwatchers.append(self.playlistwatcher_loop.periodic(track_time, 0.0, self.checktrack, item))

                for watcher in self.playlistwatchers:
                    watcher.start()    
                       
    #------------------------------------------------------------------------------------------#
    def combine_audiofiles(self, watcher, revents):
        """
        Kombiniert Dateien, die in einem best. Zeitintervall entstanden sind
        @type watcher:  object
        @param watcher: der watcher
        @type revents:    object
        @param revents:  revents - nicht verwendet
        """
        self.block_combine = False
        self.messenger.send('Stop watcher', '0501', 'info', 'combine_audiofiles' , None, 'appinternal')
        
        from_time = int(watcher.data['from_time'])
        to_time = int(watcher.data['to_time'])
        
        watcher.stop()
        watcher.loop.stop()
        # Den Ordner  bestimmen, in dem die Dateien liegen
        cur_folder = self.record_dir + '/' + datetime.datetime.fromtimestamp(from_time).strftime("%Y-%m-%d") + "/"
        
        uid = os.stat(cur_folder).st_uid
        gid = os.stat(cur_folder).st_gid
        # Name der Audiodatei, die angelegt werden muss
        out_file = datetime.datetime.fromtimestamp(from_time).strftime("%Y-%m-%d-%H-%M") + ".wav"

        # Alle WAV-Dateien im Ordner
        files = glob.glob(cur_folder + "*.wav")
        
        combine = []
        if len(files) > 0:
            for file in files:            
                t = int(os.path.getmtime(file))            
                # Liegt die Mtime im definierten Intervall?
                if t > from_time and t <= to_time:
                    combine.append(file)

            if len(combine) > 0:

                audiotools = CombaAudiotools()
                audiotools.combine_audiofiles(combine, cur_folder, out_file, nice=19)
                os.chown(out_file, uid, gid);
                self.messenger.send("Combined  to file " + out_file, '0502', 'info', 'combine_audiofiles' , None, 'appinternal')

    #------------------------------------------------------------------------------------------#
    def _load_playlist(self):
        """
        Playlist laden und von dem Track und Zeitpunkt an starten, der aktuell laufen sollte
        """

        self.messenger.send("Try to load playlist", '0501', 'info', 'loadPlaylist' , None, 'appinternal')

        # Die Playlist holen
        store = CombaCalendarService()

        # start_date ist das Datum, an dem die Playlist beginnen soll - abrunden auf den Beginn der denierten Länge für einen Track
        start_date  = datetime.datetime.now() - datetime.timedelta(seconds=int(datetime.datetime.now().strftime('%s')) % int(self.secondspertrack))

        store.setDateFrom(start_date.strftime("%Y-%m-%dT%H:%M"))
        store.setUntilTime(self.stop_time)

        store.start()
        uri = store.getUri()

        # wait until childs thread returns
        store.join()

        result = self.client.playlist_load(uri)
            
        if not self._get_data(result):
            self.messenger.send('Could not get Data from controller', '0504', 'fatal', 'loadPlaylist' , None, 'appinternal')
        else:
            result = self.client.playlist_play()
            if not self._get_data(result):
                self.messenger.send('Could not get Data from controller', '0505', 'fatal', 'loadPlaylist' , None, 'appinternal')

            else:

                time.sleep(0.2)
                unix_time_now = int(datetime.datetime.now().strftime('%s'))
                # berechnen die Sekunden die wir noch weiterspulen müssen
                seek_time = unix_time_now - int(start_date.strftime('%s'))
                # ... und seek
                self.client.playlist_seek(str(seek_time))
                       
    #------------------------------------------------------------------------------------------#
    def _restartScheduler(self):
        """
        Scheduler neu starten
        """
        os.system("service combascheduler restart")

    #------------------------------------------------------------------------------------------#
    def _restartArchive(self):
        """
        Restart archive controller
        """
        os.system("service combaarchive restart")

    #------------------------------------------------------------------------------------------#
    def _restartController(self):
        """
        Controller neu starten
        """
        os.system("service comba restart")

    #------------------------------------------------------------------------------------------#
    def _restartLiquidsoap(self):
        """
        Player und recorder neu starten
        """
        os.system("service comba_liq restart")

    #------------------------------------------------------------------------------------------#
    def _restartRecord(self):
        """
        Recorder neu starten
        Da die Aufnahme vermutlich unterbrochen wurde, werden Audiodateien aus dem vorgesehenen Zeitraum zusammengefügt
        """
        result = self.client.recorder_start()
        if self.block_combine:
            return
        
        self.block_combine = True
        now = int(datetime.datetime.now().strftime("%s"))

        mod = now % int(self.secondspertrack)
        from_time = (now - mod)
        to_time = from_time + int(self.secondspertrack)
        # combine_audiofiles wird 1 Sekunde nach Ende der Aufnahme ausgeführt 
        time_start = float((to_time - now) +1) 
        
        data = {}
        data['from_time'] = from_time
        data['to_time'] = to_time 
        loop = pyev.Loop()
        #self.audiowatcher.set(0.0, time_start)
        
        watcher = loop.timer(time_start, 0, self.combine_audiofiles, data)
        #self.audiowatcher.set(10, 0.0)
        self.messenger.send("Audiofiles may be combined in " + str(watcher.remaining) + " seconds", '0601', 'info', 'restartRecord' , None, 'appinternal')
        
        watcher.start()
        loop.start()
        
    #------------------------------------------------------------------------------------------#
    def _reloadPlaylist(self):
        """
        Playliste neu laden und starten
        """
        self._load_playlist()

    #------------------------------------------------------------------------------------------#
    def _adminMessage(self,message):
        pass

    #------------------------------------------------------------------------------------------#
    def _get_data(self, result):
        """                
        @type     result: dict
        @param    result: Ein dict objekt
        """        
        if type(result) == type(str()):
            try:
                result = simplejson.loads(result)
            except:
                return False
        try:
            if result['success'] == 'success':
                if result.has_key('value') and result['value']:
                    return result['value']
                else:

                    return True
            else:
                return False
        except:

            return False