Esempio n. 1
0
    def __init__(self,
                 client,
                 user_list,
                 client_conversation,
                 client_events=[]):
        """Initialize a new Conversation."""
        self._client = client  # Client
        self._user_list = user_list  # UserList
        self._conversation = client_conversation  # ClientConversation
        self._events = []  # [ConversationEvent]
        self._events_dict = {}  # {event_id: ConversationEvent}
        self._send_message_lock = asyncio.Lock()
        for event_ in client_events:
            self.add_event(event_)

        # Event fired when a user starts or stops typing with arguments
        # (typing_message).
        self.on_typing = event.Event('Conversation.on_typing')
        # Event fired when a new ConversationEvent arrives with arguments
        # (ConversationEvent).
        self.on_event = event.Event('Conversation.on_event')
        # Event fired when a watermark (read timestamp) is updated with
        # arguments (WatermarkNotification).
        self.on_watermark_notification = event.Event(
            'Conversation.on_watermark_notification')
        self.on_watermark_notification.add_observer(
            self._on_watermark_notification)
Esempio n. 2
0
    def __init__(self, cookies, session, max_retries, retry_backoff_base):
        """Create a new channel."""

        # Event fired when channel connects with arguments ():
        self.on_connect = event.Event('Channel.on_connect')
        # Event fired when channel reconnects with arguments ():
        self.on_reconnect = event.Event('Channel.on_reconnect')
        # Event fired when channel disconnects with arguments ():
        self.on_disconnect = event.Event('Channel.on_disconnect')
        # Event fired when an array is received with arguments (array):
        self.on_receive_array = event.Event('Channel.on_receive_array')

        self._max_retries = max_retries
        self._retry_backoff_base = retry_backoff_base

        # True if the channel is currently connected:
        self._is_connected = False
        # True if the on_connect event has been called at least once:
        self._on_connect_called = False
        # Request cookies dictionary:
        self._cookies = cookies
        # Parser for assembling messages:
        self._chunk_parser = None
        # aiohttp session for keep-alive and cookies:
        self._session = session

        # Discovered parameters:
        self._sid_param = None
        self._gsessionid_param = None
Esempio n. 3
0
    def __init__(self, cookies, connector):
        """Create a new channel."""

        # Event fired when channel connects with arguments ():
        self.on_connect = event.Event('Channel.on_connect')
        # Event fired when channel reconnects with arguments ():
        self.on_reconnect = event.Event('Channel.on_reconnect')
        # Event fired when channel disconnects with arguments ():
        self.on_disconnect = event.Event('Channel.on_disconnect')
        # Event fired when a channel submission is received with arguments
        # (submission):
        self.on_message = event.Event('Channel.on_message')

        # True if the channel is currently connected:
        self._is_connected = False
        # True if the channel has been subscribed:
        self._is_subscribed = False
        # True if the on_connect event has been called at least once:
        self._on_connect_called = False
        # Request cookies dictionary:
        self._cookies = cookies
        # Parser for assembling messages:
        self._push_parser = None
        # aiohttp connector for keep-alive:
        self._connector = connector

        # Discovered parameters:
        self._sid_param = None
        self._gsessionid_param = None
    def __init__(self, client, user_list, conversation, events=[]):
        """Initialize a new Conversation."""
        # pylint: disable=dangerous-default-value
        self._client = client  # Client
        self._user_list = user_list  # UserList
        self._conversation = conversation  # hangouts_pb2.Conversation
        self._events = []  # [hangouts_pb2.Event]
        self._events_dict = {}  # {event_id: ConversationEvent}
        self._send_message_lock = asyncio.Lock()
        for event_ in events:
            # Workaround to ignore observed events returned from
            # syncrecentconversations.
            if event_.event_type != hangouts_pb2.EVENT_TYPE_OBSERVED_EVENT:
                self.add_event(event_)

        # Event fired when a user starts or stops typing with arguments
        # (typing_message).
        self.on_typing = event.Event('Conversation.on_typing')
        # Event fired when a new ConversationEvent arrives with arguments
        # (ConversationEvent).
        self.on_event = event.Event('Conversation.on_event')
        # Event fired when a watermark (read timestamp) is updated with
        # arguments (WatermarkNotification).
        self.on_watermark_notification = event.Event(
            'Conversation.on_watermark_notification')
        self.on_watermark_notification.add_observer(
            self._on_watermark_notification)
Esempio n. 5
0
    def __init__(self, session, max_retries, retry_backoff_base):
        """Create a new channel.

        Args:
            session (http_utils.Session): Request session.
            max_retries (int): Number of retries for long-polling request.
            retry_backoff_base (int): The base term for the long-polling
                exponential backoff.
        """

        # Event fired when channel connects with arguments ():
        self.on_connect = event.Event('Channel.on_connect')
        # Event fired when channel reconnects with arguments ():
        self.on_reconnect = event.Event('Channel.on_reconnect')
        # Event fired when channel disconnects with arguments ():
        self.on_disconnect = event.Event('Channel.on_disconnect')
        # Event fired when an array is received with arguments (array):
        self.on_receive_array = event.Event('Channel.on_receive_array')

        self._max_retries = max_retries
        self._retry_backoff_base = retry_backoff_base

        # True if the channel is currently connected:
        self._is_connected = False
        # True if the on_connect event has been called at least once:
        self._on_connect_called = False
        # Parser for assembling messages:
        self._chunk_parser = None
        # Session for HTTP requests:
        self._session = session

        # Discovered parameters:
        self._sid_param = None
        self._gsessionid_param = None
Esempio n. 6
0
    def __init__(self, client, conv_states, user_list, sync_timestamp):
        self._client = client  # Client
        self._conv_dict = {}  # {conv_id: Conversation}
        self._sync_timestamp = sync_timestamp  # datetime
        self._user_list = user_list  # UserList

        # Initialize the list of conversations from Client's list of
        # ClientConversationStates.
        for conv_state in conv_states:
            self.add_conversation(conv_state.conversation, conv_state.event)

        self._client.on_state_update.add_observer(self._on_state_update)
        self._client.on_connect.add_observer(self._sync)
        self._client.on_reconnect.add_observer(self._sync)

        # Event fired when a new ConversationEvent arrives with arguments
        # (ConversationEvent).
        self.on_event = event.Event('ConversationList.on_event')
        # Event fired when a user starts or stops typing with arguments
        # (typing_message).
        self.on_typing = event.Event('ConversationList.on_typing')
        # Event fired when a watermark (read timestamp) is updated with
        # arguments (WatermarkNotification).
        self.on_watermark_notification = event.Event(
            'ConversationList.on_watermark_notification')
Esempio n. 7
0
    def __init__(self,
                 client,
                 user_list,
                 conversation,
                 events=[],
                 event_cont_token=None):
        # pylint: disable=dangerous-default-value
        self._client = client  # Client
        self._user_list = user_list  # UserList
        self._conversation = conversation  # hangouts_pb2.Conversation
        self._events = []  # [hangouts_pb2.Event]
        self._events_dict = {}  # {event_id: ConversationEvent}
        self._send_message_lock = asyncio.Lock()
        self._watermarks = {}  # {UserID: datetime.datetime}
        self._event_cont_token = event_cont_token
        for event_ in events:
            # Workaround to ignore observed events returned from
            # syncrecentconversations.
            if event_.event_type != hangouts_pb2.EVENT_TYPE_OBSERVED_EVENT:
                self.add_event(event_)

        self.on_event = event.Event('Conversation.on_event')
        """
        :class:`.Event` fired when an event occurs in this conversation.

        Args:
            conv_event: :class:`.ConversationEvent` that occurred.
        """

        self.on_typing = event.Event('Conversation.on_typing')
        """
        :class:`.Event` fired when a users starts or stops typing in this
        conversation.

        Args:
            typing_message: :class:`~hangups.parsers.TypingStatusMessage` that
                occurred.
        """

        self.on_watermark_notification = event.Event(
            'Conversation.on_watermark_notification')
        """
        :class:`.Event` fired when a watermark (read timestamp) is updated for
        this conversation.

        Args:
            watermark_notification:
                :class:`~hangups.parsers.WatermarkNotification` that occurred.
        """

        self.on_watermark_notification.add_observer(
            self._on_watermark_notification)
Esempio n. 8
0
    def __init__(self, cookies):
        """Create new client.

        cookies is a dictionary of authentication cookies.
        """

        # Event fired when the client connects for the first time with
        # arguments ().
        self.on_connect = event.Event('Client.on_connect')
        # Event fired when the client reconnects after being disconnected with
        # arguments ().
        self.on_reconnect = event.Event('Client.on_reconnect')
        # Event fired when the client is disconnected with arguments ().
        self.on_disconnect = event.Event('Client.on_disconnect')
        # Event fired when a StateUpdate arrives with arguments (state_update).
        self.on_state_update = event.Event('Client.on_state_update')

        self._cookies = cookies
        proxy = os.environ.get('HTTP_PROXY')
        if proxy:
            self._connector = aiohttp.ProxyConnector(proxy)
        else:
            self._connector = aiohttp.TCPConnector()

        self._channel = channel.Channel(self._cookies, self._connector)
        # Future for Channel.listen
        self._listen_future = None

        self._request_header = hangouts_pb2.RequestHeader(
            # Ignore most of the RequestHeader fields since they aren't
            # required. Sending a recognized client_id is important because it
            # changes the behaviour of some APIs (eg. get_conversation will
            # filter out EVENT_TYPE_GROUP_LINK_SHARING_MODIFICATION without
            # it).
            client_version=hangouts_pb2.ClientVersion(
                client_id=hangouts_pb2.CLIENT_ID_WEB_HANGOUTS,
                major_version='hangups-{}'.format(version.__version__),
            ),
            language_code='en',
        )

        # String identifying this client (populated later):
        self._client_id = None

        # String email address for this account (populated later):
        self._email = None

        # Active client management parameters:
        # Time in seconds that the client as last set as active:
        self._last_active_secs = 0.0
        # ActiveClientState enum int value or None:
        self._active_client_state = None
Esempio n. 9
0
    def __init__(self, cookies):
        """Create new client.

        cookies is a dictionary of authentication cookies.
        """

        # Event fired when the client connects for the first time with
        # arguments ().
        self.on_connect = event.Event('Client.on_connect')
        # Event fired when the client reconnects after being disconnected with
        # arguments ().
        self.on_reconnect = event.Event('Client.on_reconnect')
        # Event fired when the client is disconnected with arguments ().
        self.on_disconnect = event.Event('Client.on_disconnect')
        # Event fired when a StateUpdate arrives with arguments (state_update).
        self.on_state_update = event.Event('Client.on_state_update')

        self._cookies = cookies
        proxy = os.environ.get('HTTP_PROXY')
        if proxy:
            self._connector = aiohttp.ProxyConnector(proxy)
        else:
            self._connector = aiohttp.TCPConnector()

        self._channel = channel.Channel(self._cookies, self._connector)
        # Future for Channel.listen
        self._listen_future = None

        self._request_header = hangouts_pb2.RequestHeader(
            # Ignore most of the RequestHeader fields since they aren't
            # required.
            client_version=hangouts_pb2.ClientVersion(
                major_version='hangups-{}'.format(__version__),
            ),
            language_code='en',
        )

        # String identifying this client (populated later):
        self._client_id = None

        # String email address for this account (populated later):
        self._email = None

        # Active client management parameters:
        # Time in seconds that the client as last set as active:
        self._last_active_secs = 0.0
        # ActiveClientState enum int value or None:
        self._active_client_state = None
Esempio n. 10
0
def test_function_observer():
    e = event.Event('MyEvent')
    res = []
    a = lambda arg: res.append('a' + arg)
    e.add_observer(a)
    yield from e.fire('1')
    assert res == ['a1']
Esempio n. 11
0
def test_already_added():
    def a(arg):
        print('A: got {}'.format(arg))
    e = event.Event('MyEvent')
    e.add_observer(a)
    with pytest.raises(ValueError):
        e.add_observer(a)
Esempio n. 12
0
def test_coroutine_observer():
    e = event.Event('MyEvent')
    res = []
    a = asyncio.coroutine(lambda arg: res.append('a' + arg))
    e.add_observer(a)
    yield from e.fire('1')
    assert res == ['a1']
Esempio n. 13
0
async def test_coroutine_observer():
    e = event.Event('MyEvent')
    res = []

    async def a(arg):
        res.append('a' + arg)

    e.add_observer(a)
    await e.fire('1')
    assert res == ['a1']
Esempio n. 14
0
    def __init__(self, cookies):
        """Create new client.

        cookies is a dictionary of authentication cookies.
        """

        # Event fired when the client connects for the first time with
        # arguments (initial_data).
        self.on_connect = event.Event('Client.on_connect')
        # Event fired when the client reconnects after being disconnected with
        # arguments ().
        self.on_reconnect = event.Event('Client.on_reconnect')
        # Event fired when the client is disconnected with arguments ().
        self.on_disconnect = event.Event('Client.on_disconnect')
        # Event fired when a ClientStateUpdate arrives with arguments
        # (state_update).
        self.on_state_update = event.Event('Client.on_state_update')

        self._cookies = cookies
        proxy = os.environ.get('HTTP_PROXY')
        if proxy:
            self._connector = aiohttp.ProxyConnector(proxy)
        else:
            self._connector = aiohttp.TCPConnector()

        # hangups.channel.Channel instantiated in connect()
        self._channel = None
        # API key sent with every request:
        self._api_key = None
        # Parameters sent in request headers:
        self._header_date = None
        self._header_version = None
        self._header_id = None
        # String identifying this client:
        self._client_id = None
        # Account email address:
        self._email = None
        # Time in seconds that the client as last set as active:
        self._last_active_secs = 0.0
        # ActiveClientState enum value or None:
        self._active_client_state = None
        # Future for Channel.listen
        self._listen_future = None
Esempio n. 15
0
    def __init__(self,
                 client,
                 user_list,
                 client_conversation,
                 client_events=[]):
        """Initialize a new Conversation."""
        self._client = client  # Client
        self._user_list = user_list  # UserList
        self._conversation = client_conversation  # ClientConversation
        self._events = []  # [ConversationEvent]
        for event_ in client_events:
            self.add_event(event_)

        # Event fired when a user starts or stops typing with arguments
        # (typing_message).
        self.on_typing = event.Event('Conversation.on_typing')
        # Event fired when a new ConversationEvent arrives with arguments
        # (ConversationEvent).
        self.on_event = event.Event('Conversation.on_event')
Esempio n. 16
0
    def __init__(self, cookies):
        """Create new client.

        cookies is a dictionary of authentication cookies.
        """

        # Event fired when the client connects for the first time with
        # arguments (initial_data).
        self.on_connect = event.Event('Client.on_connect')
        # Event fired when the client reconnects after being disconnected with
        # arguments ().
        self.on_reconnect = event.Event('Client.on_reconnect')
        # Event fired when the client is disconnected with arguments ().
        self.on_disconnect = event.Event('Client.on_disconnect')
        # Event fired when a ClientStateUpdate arrives with arguments
        # (state_update).
        self.on_state_update = event.Event('Client.on_state_update')

        self._cookies = cookies
        self._connector = aiohttp.TCPConnector()

        # hangups.channel.Channel instantiated in connect()
        self._channel = None
        # API key sent with every request:
        self._api_key = None
        # Parameters sent in request headers:
        self._header_date = None
        self._header_version = None
        self._header_id = None
        # Like the jabber client ID
        self._header_client = None
        # Parameters needed to create the Channel:
        self._channel_path = None
        self._clid = None
        self._channel_ec_param = None
        self._channel_prop_param = None
        # Time in seconds that the client as last set as active:
        self._last_active_secs = 0.0
        # ActiveClientState enum value or None:
        self._active_client_state = None
        # Future for Channel.listen
        self._listen_future = None
Esempio n. 17
0
    def __init__(self, cookies, path, clid, ec, prop, connector):
        """Create a new channel."""

        # Event fired when channel connects with arguments ():
        self.on_connect = event.Event('Channel.on_connect')
        # Event fired when channel reconnects with arguments ():
        self.on_reconnect = event.Event('Channel.on_reconnect')
        # Event fired when channel disconnects with arguments ():
        self.on_disconnect = event.Event('Channel.on_disconnect')
        # Event fired when a channel submission is received with arguments
        # (submission):
        self.on_message = event.Event('Channel.on_message')

        # True if the channel is currently connected:
        self._is_connected = False
        # True if the on_connect event has been called at least once:
        self._on_connect_called = False
        # Request cookies dictionary:
        self._cookies = cookies
        # Parser for assembling messages:
        self._push_parser = None
        # aiohttp connector for keep-alive:
        self._connector = connector

        # Static channel parameters:
        # '/u/0/talkgadget/_/channel/'
        self._channel_path = path
        # 'A672C650270E1674'
        self._clid_param = clid
        # '["ci:ec",1,1,0,"chat_wcs_20140813.110045_RC2"]\n'
        self._ec_param = ec
        # 'aChromeExtension'
        self._prop_param = prop

        # Discovered parameters:
        self._sid_param = None
        self._gsessionid_param = None

        self._email = None
        self._header_client = None
Esempio n. 18
0
    def __init__(self, cookies):
        """Create new client.

        cookies is a dictionary of authentication cookies.
        """

        # Event fired when the client connects for the first time with
        # arguments (initial_data).
        self.on_connect = event.Event('Client.on_connect')
        self.__on_pre_connect = event.Event('Client.on_pre_connect')
        self.__on_pre_connect.add_observer(self._on_pre_connect)

        # Event fired when the client reconnects after being disconnected with
        # arguments ().
        self.on_reconnect = event.Event('Client.on_reconnect')
        # Event fired when the client is disconnected with arguments ().
        self.on_disconnect = event.Event('Client.on_disconnect')
        # Event fired when a ClientStateUpdate arrives with arguments
        # (state_update).
        self.on_state_update = event.Event('Client.on_state_update')

        self._cookies = cookies
        self._connector = aiohttp.TCPConnector()

        # hangups.channel.Channel instantiated in connect()
        self._channel = None
        # API key sent with every request:
        self._api_key = None
        # Parameters sent in request headers:
        self._header_date = None
        self._header_version = None
        self._header_id = None
        # Like the jabber client ID
        self._header_client = None
        self._email = None
        # Parameters needed to create the Channel:
        self._channel_path = None
        self._clid = None
        self._channel_ec_param = None
        self._channel_prop_param = None
Esempio n. 19
0
    def __init__(self, client, conv_states, user_list, sync_timestamp):
        self._client = client  # Client
        self._conv_dict = {}  # {conv_id: Conversation}
        self._sync_timestamp = sync_timestamp  # datetime
        self._user_list = user_list  # UserList

        # Initialize the list of conversations from Client's list of
        # hangouts_pb2.ConversationState.
        for conv_state in conv_states:
            self._add_conversation(conv_state.conversation, conv_state.event)

        self._client.on_state_update.add_observer(self._on_state_update)
        self._client.on_connect.add_observer(self._sync)
        self._client.on_reconnect.add_observer(self._sync)

        self.on_event = event.Event('ConversationList.on_event')
        """
        :class:`~hangups.event.Event` fired when an event occurs in any
        conversation.

        Args:
            conv_event: :class:`ConversationEvent` that occurred.
        """

        self.on_typing = event.Event('ConversationList.on_typing')
        """
        :class:`~hangups.event.Event` fired when a users starts or stops typing
        in any conversation.

        Args:
            typing_message: :class:`~hangups.parsers.TypingStatusMessage` that
                occurred.
        """

        self.on_watermark_notification = event.Event(
            'ConversationList.on_watermark_notification'
        )
        """
Esempio n. 20
0
def test_event():
    e = event.Event('MyEvent')
    res = []
    a = asyncio.coroutine(lambda arg: res.append('a' + arg))
    b = asyncio.coroutine(lambda arg: res.append('b' + arg))
    e.add_observer(a)
    yield from e.fire('1')
    e.add_observer(b)
    yield from e.fire('2')
    e.remove_observer(a)
    yield from e.fire('3')
    e.remove_observer(b)
    yield from e.fire('4')
    assert res == ['a1', 'a2', 'b2', 'b3']
Esempio n. 21
0
    def __init__(self, client, conv_states, user_list, sync_timestamp):
        self._client = client  # Client
        self._conv_dict = {}  # {conv_id: Conversation}
        self._sync_timestamp = sync_timestamp  # datetime
        self._user_list = user_list  # UserList

        # Initialize the list of conversations from Client's list of
        # ClientConversationStates.
        for conv_state in conv_states:
            self.add_conversation(conv_state.conversation, conv_state.event)

        self._client.on_state_update.add_observer(self._on_state_update)
        # TODO: Make event support coroutines so we don't have to do this:
        sync_f = lambda initial_data=None: asyncio.async(self._sync()) \
                .add_done_callback(lambda f: f.result())
        self._client.on_connect.add_observer(sync_f)
        self._client.on_reconnect.add_observer(sync_f)

        # Event fired when a new ConversationEvent arrives with arguments
        # (ConversationEvent).
        self.on_event = event.Event('ConversationList.on_event')
        # Event fired when a user starts or stops typing with arguments
        # (typing_message).
        self.on_typing = event.Event('ConversationList.on_typing')
Esempio n. 22
0
async def test_event():
    e = event.Event('MyEvent')
    res = []

    async def a(arg):
        res.append('a' + arg)

    async def b(arg):
        res.append('b' + arg)

    e.add_observer(a)
    await e.fire('1')
    e.add_observer(b)
    await e.fire('2')
    e.remove_observer(a)
    await e.fire('3')
    e.remove_observer(b)
    await e.fire('4')
    assert res == ['a1', 'a2', 'b2', 'b3']
Esempio n. 23
0
async def test_function_observer():
    e = event.Event('MyEvent')
    res = []
    e.add_observer(lambda arg: res.append('a' + arg))
    await e.fire('1')
    assert res == ['a1']
Esempio n. 24
0
def test_remove_nonexistant():
    e = event.Event('MyEvent')
    with pytest.raises(ValueError):
        e.remove_observer(lambda a: print('A: got {}'.format(a)))
Esempio n. 25
0
    def __init__(self, cookies, max_retries=5, retry_backoff_base=2):
        self._max_retries = max_retries
        self._retry_backoff_base = retry_backoff_base

        self.on_connect = event.Event('Client.on_connect')
        """
        :class:`~hangups.event.Event` fired when the client connects for the
        first time.
        """

        self.on_reconnect = event.Event('Client.on_reconnect')
        """
        :class:`~hangups.event.Event` fired when the client reconnects after
        being disconnected.
        """

        self.on_disconnect = event.Event('Client.on_disconnect')
        """
        :class:`~hangups.event.Event` fired when the client is disconnected.
        """

        self.on_state_update = event.Event('Client.on_state_update')
        """
        :class:`~hangups.event.Event` fired when an update arrives from the
        server.

        Args:
            state_update: A ``StateUpdate`` message.
        """
        # Google session cookies:
        self._cookies = cookies

        # aiohttp.ClientSession instance (populated by connect method):
        self._session = None

        # Channel instance (populated by connect method):
        self._channel = None

        # Future for Channel.listen (populated by connect method):
        self._listen_future = None

        self._request_header = hangouts_pb2.RequestHeader(
            # Ignore most of the RequestHeader fields since they aren't
            # required. Sending a recognized client_id is important because it
            # changes the behaviour of some APIs (eg. get_conversation will
            # filter out EVENT_TYPE_GROUP_LINK_SHARING_MODIFICATION without
            # it).
            client_version=hangouts_pb2.ClientVersion(
                client_id=hangouts_pb2.CLIENT_ID_WEB_HANGOUTS,
                major_version='hangups-{}'.format(version.__version__),
            ),
            language_code='en',
        )

        # String identifying this client (populated later):
        self._client_id = None

        # String email address for this account (populated later):
        self._email = None

        # Active client management parameters:
        # Time in seconds that the client as last set as active:
        self._last_active_secs = 0.0
        # ActiveClientState enum int value or None:
        self._active_client_state = None
Esempio n. 26
0
 def create_event(self, *event_name: str) -> None:
     for event_ in event_name:
         self.events[event_] = event.Event('hanger.{}'.format(event_name))