Пример #1
0
    def send_message_intercept(self, buddy, message):
        if not self.video_chat_buddies: return

        from contacts.buddyinfo import BuddyInfo
        binfo = BuddyInfo(buddy)

        if binfo in self.video_chat_buddies:
            log.debug('intercepted outgoing videochat message')
            video_chat = self.video_chat_buddies[binfo]
            video_chat.send_im(message)
Пример #2
0
    def __init__(self, buddy):
        self.buddy_info = BuddyInfo(buddy)
        self.http = VideoChatHttp(profile.username, profile.password)

        self._widget_jid = None
        self._stopped = False
        self.on_stop = Delegate()

        self.handle_buddy_state(buddy)

        # Video chat aliases
        my_alias = buddy.protocol.self_buddy.name
        friend_alias = buddy.name

        # fetch a video token on the threadpool
        create = threaded(self.http.create_video)
        create(my_alias,
               friend_alias,
               success=self.on_token,
               error=self.error_token)
Пример #3
0
    def __init__(self, buddy):
        self.buddy_info = BuddyInfo(buddy)
        self.http = VideoChatHttp(profile.username, profile.password)

        self._widget_jid = None
        self._stopped    = False
        self.on_stop = Delegate()

        self.handle_buddy_state(buddy)

        # Video chat aliases
        my_alias = buddy.protocol.self_buddy.name
        friend_alias = buddy.name

        # fetch a video token on the threadpool
        create = threaded(self.http.create_video)
        create(my_alias, friend_alias, success = self.on_token, error = self.error_token)
Пример #4
0
class VideoChat(object):
    '''
    Represents a link between a video widget and a buddy.

    - Uses VideoChatHttp to register video widget tokens with the server.
    - Creates and manages a video window
    - Maintains a link to a buddy, working with DigsbyProtocol to route
      messages to and from the correct IM window
    '''
    def __init__(self, buddy):
        self.buddy_info = BuddyInfo(buddy)
        self.http = VideoChatHttp(profile.username, profile.password)

        self._widget_jid = None
        self._stopped = False
        self.on_stop = Delegate()

        self.handle_buddy_state(buddy)

        # Video chat aliases
        my_alias = buddy.protocol.self_buddy.name
        friend_alias = buddy.name

        # fetch a video token on the threadpool
        create = threaded(self.http.create_video)
        create(my_alias,
               friend_alias,
               success=self.on_token,
               error=self.error_token)

    def handle_buddy_state(self, buddy):
        # when the protocol you're chatting from goes offline, close the video window
        proto = buddy.protocol

        def on_protocol_state(proto, attr, old, new):
            if not proto.connected:
                self.stop()

        proto.add_observer(on_protocol_state, 'state', obj=self)
        self.on_stop += lambda: proto.remove_observer(on_protocol_state,
                                                      'state')

    def __repr__(self):
        return '<VideoChat with %s>' % self.buddy_info

    def on_token(self):
        'Called back when VideoChatHttp successfully obtains tokens.'

        token = self.http.video_token
        log.info('received video token: %s', token)
        profile.connection.add_video_chat(token, self)
        gui_call_later(self.on_url, self.http.invite_url(),
                       self.http.widget_id)

    def on_url(self, invite_url, widget_id):
        'Called back when VideoChatHttp successfully creates a new video widget token.'

        # Send an invite message.
        buddy = self.buddy_info.buddy()
        if buddy is not None:
            message = _('Join me in an audio/video call: %s') % invite_url

            def send_and_echo_invite():
                convo = buddy.protocol.convo_for(buddy)
                convo.send_plaintext_message(message)
                convo.system_message(
                    _('You have invited {name} to an audio/video chat.').
                    format(name=buddy.name))

            netcall(send_and_echo_invite)

        # Show the video chat window.
        title = VIDEO_CHAT_TITLE.format(name=self.buddy_info.buddy_name)

        from gui.video.webvideo import VideoChatWindow
        frame = self.video_frame = VideoChatWindow(title,
                                                   widget_id,
                                                   on_close=self.stop)
        gui_call_later(frame.Show)

    def error_token(self):
        'Called when there is an error retreiving tokens from the server.'

        log.warning('error receiving token')
        self.system_message(_('Audio/Video chat is currently unavailable.'))

    def send_im(self, message):
        'Sends an unechoed IM to the video widget.'

        convo = self.widget_convo
        if convo is not None:
            netcall(lambda: convo.send_plaintext_message(message))

    @property
    def widget_convo(self):
        'Returns a conversation object with the video widget, if one can be found, or None.'

        if self.widget_jid is None:
            self.widget_jid = self.find_widget_jid()

            if self.widget_jid is None:
                return log.warning(
                    'no widget jid, cannot forward message to widget')

        conn = profile.connection
        if not conn:
            return log.warning(
                'no Digsby connection, cannot forward message to widget')

        return conn.convo_for(self.widget_jid)

    def set_widget_jid(self, jid):
        if jid != self._widget_jid:
            self._widget_jid = jid

            # if buddy signs off, stop
            if profile.connection:
                profile.connection.get_buddy(jid).add_observer(
                    self.buddy_status_change, 'status')

    widget_jid = property(attrgetter('_widget_jid'), set_widget_jid)

    def find_widget_jid(self):
        'Checks for a video widget JID on the Digsby connection.'

        conn = profile.connection
        if conn is None:
            return log.warning('cannot find widget jid: no digsby connection')

        # Search for a buddy on the Digsby connection with a matching resource
        # to the one the server told us about.
        #
        # TODO: for loops nested this deep are never a good idea. can have
        # the server tell us about this resource more specifically?
        resource = 'video.' + self.http.video_token

        for buddict in conn.buddy_dictionaries():
            for name, buddy in buddict.iteritems():
                if buddy.jid.domain == u'guest.digsby.org':
                    for jid, res in buddy.resources.iteritems():
                        if jid.resource == resource:
                            return jid

    def buddy_status_change(self, buddy, attr, old, new):
        'Invoked when the widget buddy changes status.'

        # we're looking for the buddy to go offline...
        if buddy.online: return

        log.info('buddy %r went offline...stopping', buddy)

        buddy.remove_observer(self.buddy_status_change, 'status')

        # ...if they do, show a message in the IM window
        if not self._stopped:
            self.system_message(_('Audio/Video call ended by other party.'))

        self.stop()

    def system_message(self, message, **opts):
        'Echoes a system message to the IM window.'

        with traceguard:
            im_buddy = self.buddy_info.buddy()
            if im_buddy is not None:
                convo = im_buddy.protocol.convo_for(im_buddy)
                convo.system_message(message, **opts)

    def stop(self):
        'End all communication with the video widget.'

        self.stop = lambda *a: None  # don't stop more than once
        self._stopped = True
        log.info('stopping video chat %r', self)

        # destroy the video window
        if self.video_frame: gui_call_later(self.video_frame.Destroy)

        # appear offline to the widget
        convo = self.widget_convo
        if convo is not None:
            netcall(self.widget_convo.buddy.appear_offline_to)

        # remove IM window link
        token = self.http.video_token
        if token is not None:
            conn = profile.connection
            if conn is not None:
                conn.remove_video_chat(token)

        # tell the server to kill the video info
        threaded(self.http.close_video)()

        self.on_stop()
Пример #5
0
class VideoChat(object):
    '''
    Represents a link between a video widget and a buddy.

    - Uses VideoChatHttp to register video widget tokens with the server.
    - Creates and manages a video window
    - Maintains a link to a buddy, working with DigsbyProtocol to route
      messages to and from the correct IM window
    '''

    def __init__(self, buddy):
        self.buddy_info = BuddyInfo(buddy)
        self.http = VideoChatHttp(profile.username, profile.password)

        self._widget_jid = None
        self._stopped    = False
        self.on_stop = Delegate()

        self.handle_buddy_state(buddy)

        # Video chat aliases
        my_alias = buddy.protocol.self_buddy.name
        friend_alias = buddy.name

        # fetch a video token on the threadpool
        create = threaded(self.http.create_video)
        create(my_alias, friend_alias, success = self.on_token, error = self.error_token)

    def handle_buddy_state(self, buddy):
        # when the protocol you're chatting from goes offline, close the video window
        proto = buddy.protocol

        def on_protocol_state(proto, attr, old, new):
            if not proto.connected:
                self.stop()

        proto.add_observer(on_protocol_state, 'state', obj = self)
        self.on_stop += lambda: proto.remove_observer(on_protocol_state, 'state')


    def __repr__(self):
        return '<VideoChat with %s>' % self.buddy_info

    def on_token(self):
        'Called back when VideoChatHttp successfully obtains tokens.'

        token = self.http.video_token
        log.info('received video token: %s', token)
        profile.connection.add_video_chat(token, self)
        gui_call_later(self.on_url, self.http.invite_url(), self.http.widget_id)

    def on_url(self, invite_url, widget_id):
        'Called back when VideoChatHttp successfully creates a new video widget token.'

        # Send an invite message.
        buddy = self.buddy_info.buddy()
        if buddy is not None:
            message = _('Join me in an audio/video call: %s') % invite_url

            def send_and_echo_invite():
                convo = buddy.protocol.convo_for(buddy)
                convo.send_plaintext_message(message)
                convo.system_message(_('You have invited {name} to an audio/video chat.').format(name=buddy.name))

            netcall(send_and_echo_invite)

        # Show the video chat window.
        title = VIDEO_CHAT_TITLE.format(name=self.buddy_info.buddy_name)

        from gui.video.webvideo import VideoChatWindow
        frame = self.video_frame = VideoChatWindow(title, widget_id, on_close = self.stop)
        gui_call_later(frame.Show)

    def error_token(self):
        'Called when there is an error retreiving tokens from the server.'

        log.warning('error receiving token')
        self.system_message(_('Audio/Video chat is currently unavailable.'))

    def send_im(self, message):
        'Sends an unechoed IM to the video widget.'

        convo = self.widget_convo
        if convo is not None:
            netcall(lambda: convo.send_plaintext_message(message))

    @property
    def widget_convo(self):
        'Returns a conversation object with the video widget, if one can be found, or None.'

        if self.widget_jid is None:
            self.widget_jid = self.find_widget_jid()

            if self.widget_jid is None:
                return log.warning('no widget jid, cannot forward message to widget')

        conn = profile.connection
        if not conn:
            return log.warning('no Digsby connection, cannot forward message to widget')

        return conn.convo_for(self.widget_jid)

    def set_widget_jid(self, jid):
        if jid != self._widget_jid:
            self._widget_jid = jid

            # if buddy signs off, stop
            if profile.connection:
                profile.connection.get_buddy(jid).add_observer(self.buddy_status_change, 'status')

    widget_jid = property(attrgetter('_widget_jid'), set_widget_jid)

    def find_widget_jid(self):
        'Checks for a video widget JID on the Digsby connection.'

        conn = profile.connection
        if conn is None:
            return log.warning('cannot find widget jid: no digsby connection')

        # Search for a buddy on the Digsby connection with a matching resource
        # to the one the server told us about.
        #
        # TODO: for loops nested this deep are never a good idea. can have
        # the server tell us about this resource more specifically?
        resource = 'video.' + self.http.video_token

        for buddict in conn.buddy_dictionaries():
            for name, buddy in buddict.iteritems():
                if buddy.jid.domain == u'guest.digsby.org':
                    for jid, res in buddy.resources.iteritems():
                        if jid.resource == resource:
                            return jid

    def buddy_status_change(self, buddy, attr, old, new):
        'Invoked when the widget buddy changes status.'

        # we're looking for the buddy to go offline...
        if buddy.online: return

        log.info('buddy %r went offline...stopping', buddy)

        buddy.remove_observer(self.buddy_status_change, 'status')

        # ...if they do, show a message in the IM window
        if not self._stopped:
            self.system_message(_('Audio/Video call ended by other party.'))

        self.stop()

    def system_message(self, message, **opts):
        'Echoes a system message to the IM window.'

        with traceguard:
            im_buddy = self.buddy_info.buddy()
            if im_buddy is not None:
                convo = im_buddy.protocol.convo_for(im_buddy)
                convo.system_message(message, **opts)

    def stop(self):
        'End all communication with the video widget.'

        self.stop = lambda *a: None # don't stop more than once
        self._stopped = True
        log.info('stopping video chat %r', self)

        # destroy the video window
        if self.video_frame: gui_call_later(self.video_frame.Destroy)

        # appear offline to the widget
        convo = self.widget_convo
        if convo is not None:
            netcall(self.widget_convo.buddy.appear_offline_to)

        # remove IM window link
        token = self.http.video_token
        if token is not None:
            conn = profile.connection
            if conn is not None:
                conn.remove_video_chat(token)

        # tell the server to kill the video info
        threaded(self.http.close_video)()

        self.on_stop()