Beispiel #1
0
    def apply_state_change(self, data, callback=None):
        # TODO: This code is intertwined untestable rubbish. Need to pull out
        #   steps into seperate methods to allow testing...
        '''Will take the provided data and propegate out the necessary changes
        to the sessions Remote Player.

        On return, the remote player, if present, has been asked to sync up.
        The callback is called once the remote player has confirmed it is in sync.
        Callback is always called after this function has returned.'''

        logger.debug('Got state change request on session {}, new state {}'.format(self.id, data))

        # if we're changing player
        new_url = data.get('player_url')
        if isinstance(new_url, basestring) and (self.player == None or new_url != self.model.player_url):

            # aquire the new one, do first in case of failure
            if new_url == '':
                new_player = None
            else:
                new_player = self.player_set.acquire_player(self.name, new_url)

            # push out a request to clear the old one, retry apply with new player :)
            if self.player:
                self.clear_player()
                self.player_set.release_player(self.name, self.model.player_url)

            # save this stuff
            self.player = new_player
            self.model.player_url = new_url
            self.model.save()

            # it's a new player, we want to resend everything, not just a delta
            full_data = extract_attrs(self.model, SessionProxy.DEFAULTS.iterkeys())
            full_data.update(data)
            data = full_data

        if self.player is None:
            # persist changes
            update_attributes(self.model, data, SessionProxy.DEFAULTS.keys(), False)
            self.model.save()

            if callback is not None:
                # done this way to make sure the function is called after we've returned
                IOLoop.instance().add_callback(partial(callback, 204, None))
            return

        def player_callback(status, body):
            if 200 <= status < 300:
                # make sure to save the new state
                update_attributes(self.model, data, SessionProxy.DEFAULTS.keys(), False)
                self.model.save()
            else:
                logger.error('Non 2xx response, {}, from Remote Player: {}'.format(status, body))

            if callback:
                callback(status, body)

        # send of the request to the player
        self.player.send_request('PATCH', '/playback', data, callback=player_callback)
Beispiel #2
0
        def player_callback(status, body):
            if 200 <= status < 300:
                # make sure to save the new state
                update_attributes(self.model, data, SessionProxy.DEFAULTS.keys(), False)
                self.model.save()
            else:
                logger.error('Non 2xx response, {}, from Remote Player: {}'.format(status, body))

            if callback:
                callback(status, body)
Beispiel #3
0
    def __init__(self, player_set, data={}, gen_url=None, callback=None):
        '''This guy maintains the state of a Playback session. Interleaving both
        the requests from clients via process_request and events that come back
        from the Remote Player itself via process_event.

        On return, the session is persisted to SQL.
        The callback is called once the remote players state is up-to-date. It will
        always be called after this method has returned.'''

        super(SessionProxy, self).__init__()

        # Precondition: There isn't an active session with this name
        # Note: There might be a saved session with this name

        # it must have a name
        name = data.get('name') or ''
        if name == '' or not isinstance(name, basestring):
            # TODO: This should be a Session Error or such, not HTTP specific
            raise HTTPError(400, 'Sessions must have a string name of at least 1 character')

        # check we can get the remote player
        if 'player_url' in data:
            player = player_set.acquire_player(name, data['player_url'])
        else:
            player = None

        # ensure the model exists, and update it's properties
        try:
            model = m.Session.objects.get(name=name)
        except m.Session.DoesNotExist:
            model = m.Session(name=name)

            # update it with the defaults
            update_attributes(model, SessionProxy.DEFAULTS, SessionProxy.DEFAULTS.viewkeys())

        # apply the changes in the payload
        update_attributes(model, data, SessionProxy.DEFAULTS.viewkeys())

        # save the boring stuff
        self.player_set = player_set
        self.url = gen_url and gen_url(model.id)
        self.name = name
        self.model = model
        self.player = None
        self.duration = None # will recieve in playback events

        # now apply our state, by setting player to None, we force a full aquire cycle of the new player
        self.apply_state_change({}, callback)