Пример #1
0
 def get_time(self):
     self._last_hb_ts = time.time() * MICROSECONDS
     content = utils.unserialize_response(request.get_data())
     command_epoch = content['command_epoch']
     if "term" in content and int(content["term"]) > self._master_term:
         self._master_term = int(content["term"])
     if "ip" in content and (self._master_ip == None
                             or self._master_ip != content["ip"]):
         self._master_ip = content["ip"]
     curr_time = time.time() * MICROSECONDS
     curr_micros = int(round(curr_time))
     if self._in_recovery:
         failover_resp = utils.format_rpc_response(False, HB, {}, \
                                              msg='Replica in recovery mode', \
                                              command_epoch=command_epoch)
         return utils.serialize_response(failover_resp)
     with self._pygame_lock:
         replica_playing = pygame.mixer.music.get_busy()
     # Song has finished playing
     if not replica_playing:
         self._current_song = None
     resp = utils.format_rpc_response(True, HB, \
                                      {'time' : curr_micros, \
                                       'replica_playing': replica_playing},
                                       command_epoch = command_epoch)
     return utils.serialize_response(resp)
Пример #2
0
    def pause(self):
        self._last_hb_ts = time.time() * MICROSECONDS
        content = utils.unserialize_response(request.get_data())
        command_epoch = content['command_epoch']
        master_stop_micros = content['stop_time']
        if self._in_recovery:
            failover_resp = utils.format_rpc_response(False, PAUSE, {}, \
                                                 msg='Replica in recovery mode', \
                                                 command_epoch=command_epoch)
            return utils.serialize_response(failover_resp)

        # Wait till appointed stop time, allowed to be less precise than play
        # (if vs while loop)
        curr_replica_micros = int(round(time.time() * MICROSECONDS))
        if (curr_replica_micros < master_stop_micros):
            time.sleep((master_stop_micros - curr_replica_micros) /
                       float(MICROSECONDS))

        with self._pygame_lock:
            pygame.mixer.music.pause()

            # return offset from start of song
            replica_offset = int(round(pygame.mixer.music.get_pos()))
            replica_micros = int(round(time.time() * MICROSECONDS))
            resp = \
                utils.format_rpc_response(True, PAUSE, \
                                          {'time': replica_micros, \
                                           'offset': replica_offset}, \
                                           command_epoch=command_epoch)
            return utils.serialize_response(resp)
Пример #3
0
    def recover_replica(self):
        data = utils.unserialize_response(request.get_data())
        replica_song_hashes = data['song_hashes']
        with open(PLAYLIST_STATE_FILE, 'r') as f:
            data = utils.unserialize_response(f.read())
            print data
            master_queue = data['playlist']
            current_song = data['current_song']
        missing_songs = {}

        print master_queue
        for song_hash in master_queue:
            print 'song_hash ' + str(song_hash)
            music_path = utils.get_music_path(song_hash)
            if (os.path.exists(music_path)) and (
                    replica_song_hashes.count(song_hash + EXT) == 0):
                with open(music_path, 'r') as f:
                    song_bytes = f.read()
                missing_songs[song_hash + EXT] = song_bytes
        if current_song != None:
            music_path = utils.get_music_path(current_song)
            if (os.path.exists(current_song + EXT)) and (
                    replica_song_hashes.count(current_song + EXT) == 0):
                with open(music_path, 'r') as f:
                    song_bytes = f.read()
                missing_songs[current_song + EXT] = song_bytes

        resp = utils.format_rpc_response(
            True, RECOVER, {
                'songs': missing_songs,
                'master_queue': master_queue,
                'current_song': current_song
            })
        return utils.serialize_response(resp)
    def recover_replica(self):
        data = utils.unserialize_response(request.get_data())
        replica_song_hashes = data['song_hashes']
        with open(PLAYLIST_STATE_FILE, 'r') as f:
            data = utils.unserialize_response(f.read())
            print data
            master_queue = data['playlist']
            current_song = data['current_song']
        missing_songs = {}

        print master_queue
        for song_hash in master_queue:
            print 'song_hash ' + str(song_hash)
            music_path = utils.get_music_path(song_hash)
            if (os.path.exists(music_path)) and (replica_song_hashes.count(song_hash + EXT) == 0):
                with open(music_path, 'r') as f:
                    song_bytes = f.read()
                missing_songs[song_hash + EXT] = song_bytes
        if current_song != None:
            music_path = utils.get_music_path(current_song)
            if (os.path.exists(current_song + EXT)) and (replica_song_hashes.count(current_song + EXT) == 0):
                with open(music_path, 'r') as f:
                    song_bytes = f.read()
                missing_songs[current_song + EXT] = song_bytes

        resp = utils.format_rpc_response(True, RECOVER, {'songs': missing_songs, 'master_queue': master_queue, 'current_song': current_song})
        return utils.serialize_response(resp)
Пример #5
0
 def check_song(self, song_hash):
     self._last_hb_ts = time.time() * MICROSECONDS
     content = utils.unserialize_response(request.get_data())
     command_epoch = content['command_epoch']
     if self._in_recovery:
         failover_resp = utils.format_rpc_response(False, CHECK, {}, \
                                              msg='Replica in recovery mode', \
                                              command_epoch=command_epoch)
         return utils.serialize_response(failover_resp)
     if song_hash in self._song_hashes:
         resp = utils.format_rpc_response(True, CHECK, \
                                          {'has_song': True, 'ip': self._ip}, \
                                          command_epoch = command_epoch)
     else:
         resp = utils.format_rpc_response(True, CHECK, {'ip': self._ip}, \
                                          command_epoch = command_epoch)
     return utils.serialize_response(resp)
Пример #6
0
    def enqueue_song(self, song_hash):
        self._last_hb_ts = time.time() * MICROSECONDS
        content = utils.unserialize_response(request.get_data())
        command_epoch = content['command_epoch']
        master_post_hash = content['hashed_post_playlist']
        master_current_song = content['current_song']
        failover_resp = utils.format_rpc_response(False, ENQUEUE, {}, \
                                             msg='Replica in recovery mode', \
                                             command_epoch=command_epoch)
        if self._in_recovery:
            return utils.serialize_response(failover_resp)
        print "In Enqueue"
        print "Enqueue: " + str(self._current_song)

        replica_pre_hash = utils.hash_string(pickle.dumps(
            self._playlist_queue))
        if replica_pre_hash == master_post_hash and self._current_song == master_current_song:
            print "Already Performed Operation in Enqueue"
            repeat_resp = utils.format_rpc_response(False, ENQUEUE, {}, \
                                                 msg='Already performed operation', \
                                                 command_epoch=command_epoch)
            return utils.serialize_response(repeat_resp)

        # Do enqueue, check for failover mode
        song_not_exist = not os.path.exists(utils.get_music_path(song_hash))
        self._playlist_queue.append(song_hash)
        replica_post_hash = utils.hash_string(
            pickle.dumps(self._playlist_queue))
        inconsistent_queue = master_post_hash != replica_post_hash or \
                             master_current_song != self._current_song
        print "queue hashes match: " + str(
            master_post_hash == replica_post_hash)
        print "current song matches: " + str(
            master_current_song) + " == " + str(self._current_song)
        replica_failover = song_not_exist or inconsistent_queue
        if replica_failover:
            self._in_recovery = True
            return utils.serialize_response(failover_resp)
        master_time = content['time']
        self._master_timestamp = master_time
        resp = utils.format_rpc_response(True, ENQUEUE, {'enqueued': True}, \
                                         command_epoch=command_epoch)
        print str(resp)
        return utils.serialize_response(resp)
Пример #7
0
    def dequeue_song(self):
        self._last_hb_ts = time.time() * MICROSECONDS
        content = utils.unserialize_response(request.get_data())
        command_epoch = content['command_epoch']
        master_post_hash = content['hashed_post_playlist']
        master_current_song = content['current_song']
        failover_resp = utils.format_rpc_response(False, DEQUEUE, {}, \
                                             msg='Replica in recovery mode', \
                                             command_epoch=command_epoch)
        if self._in_recovery:
            return utils.serialize_response(failover_resp)
        print "In Dequeue"

        replica_pre_hash = utils.hash_string(pickle.dumps(
            self._playlist_queue))
        if replica_pre_hash == master_post_hash and self._current_song == master_current_song and self._current_song != None:
            repeat_resp = utils.format_rpc_response(False, DEQUEUE, {}, \
                                                 msg='Already performed operation', \
                                                 command_epoch=command_epoch)
            return utils.serialize_response(repeat_resp)

        # Check for length 0 queue
        if len(self._playlist_queue) == 0:
            self._current_song = None
        else:
            self._current_song = self._playlist_queue.popleft()
        replica_post_hash = utils.hash_string(
            pickle.dumps(self._playlist_queue))

        if (replica_post_hash != master_post_hash
                or self._current_song != master_current_song):
            self._in_recovery = True
            return utils.serialize_response(failover_resp)
        master_time = content['time']
        self._master_timestamp = master_time
        resp = utils.format_rpc_response(True, DEQUEUE, {}, \
                                         msg='Successfully dequeued', \
                                         command_epoch=command_epoch)
        print "end of dequeue: current song for replica: " + str(
            self._current_song)
        return utils.serialize_response(resp)
Пример #8
0
 def load_song(self, song_hash):
     content = utils.unserialize_response(request.get_data())
     command_epoch = content['command_epoch']
     song_bytes = content['song_bytes']
     if self._in_recovery:
         failover_resp = utils.format_rpc_response(False, LOAD, {}, \
                                              msg='Replica in recovery mode', \
                                              command_epoch=command_epoch)
         self._last_hb_ts = time.time() * MICROSECONDS
         return utils.serialize_response(failover_resp)
     try:
         with open(utils.get_music_path(song_hash), 'w') as f:
             f.write(song_bytes)
     except Exception:
         resp = utils.format_rpc_response(False, LOAD, {}, \
                                          msg='Error occured in writing to replica', \
                                          command_epoch=command_epoch)
     else:
         self._song_hashes.add(song_hash)
         resp = utils.format_rpc_response(True, LOAD, \
                                          {'has_song': True, 'ip':self._ip}, \
                                          command_epoch=command_epoch)
     self._last_hb_ts = time.time() * MICROSECONDS
     return utils.serialize_response(resp)
Пример #9
0
    def play(self):
        self._last_hb_ts = time.time() * MICROSECONDS
        # Parse payload
        content = utils.unserialize_response(request.get_data())
        command_epoch = content['command_epoch']
        start_time_microsec = content['start_time']
        # Not sure when it would be -1 but double check
        assert (start_time_microsec >= 0)
        master_offset = 0
        if 'offset' in content:
            master_offset = int(content['offset'])
        # May be None, need to call .stop() then
        song_hash = content['song_hash']

        failover_mode_resp = utils.format_rpc_response(\
                            False, PLAY, {}, \
                            msg='Replica in recovery mode', \
                            command_epoch=command_epoch)

        # Case 1: Failover Mode already
        # Short circuit crucial to not starve failover_service process on
        # pygame_mixer object
        # Case 2: Song hash doesn't exist
        if self._in_recovery or (song_hash != None and not \
        os.path.exists(utils.get_music_path(song_hash))):
            self._in_recovery = True
            return utils.serialize_response(failover_mode_resp)

        # Could be in recovery mode at this point, wait for it to finish
        # before moving on (True)
        with self._pygame_lock:
            replica_offset = int(round(pygame.mixer.music.get_pos()))
            offset_diff = master_offset - replica_offset
            # Ideally if pygame.mixer.music.play(offset) works then these would not be
            # errors but alas such is life and we must go into recovery
            if master_offset > 0:
                # Case 3: Unpause command, but songs do not match
                # Case 4: Unpause command, but master's offset is way in future
                #         This should not happen since master determines
                #         offset as max of replica offsets
                if self._current_song != song_hash or \
                   abs(offset_diff) > MAX_OFFSET_DIF:
                    self._in_recovery = True
                    return utils.serialize_response(failover_mode_resp)
            elif song_hash != None:
                print "Loaded song"
                pygame.mixer.music.stop()
                pygame.mixer.music.load(utils.get_music_path(song_hash))

            # Adjust start_time_microsec to account for offset difference
            if master_offset > 0:
                start_time_microsec = \
                    start_time_microsec - (offset_diff*MILLISECONDS)

            # wait until start time, then play
            curr_replica_microsec = int(round(time.time() * MICROSECONDS))
            print song_hash
            print master_offset
            while (curr_replica_microsec + ALLOWED_REPLICA_BUFFER <
                   start_time_microsec):
                curr_replica_microsec = int(round(time.time() * MICROSECONDS))
            print "Song hash: " + str(song_hash)
            if song_hash == None:
                pygame.mixer.music.stop()
            elif master_offset == 0:
                pygame.mixer.music.play(1)
            else:
                pygame.mixer.music.unpause()
            time.sleep(2)  # necessary to allow mp3 thread to start?
            self._current_song = song_hash
            curr_replica_microsec = int(round(time.time() * MICROSECONDS))
            resp = utils.format_rpc_response(True, PLAY, \
                                             {'time': curr_replica_microsec }, \
                                             command_epoch='command_epoch')
            print "Play: " + str(self._current_song)
            return utils.serialize_response(resp)
Пример #10
0
 def postload_song(self):
     self._loading_song = False
     resp = utils.format_rpc_response(True, POSTLOAD, {})
     return utils.serialize_response(resp)
Пример #11
0
 def preload_song(self):
     self._loading_song = True
     resp = utils.format_rpc_response(True, PRELOAD, {})
     return utils.serialize_response(resp)