示例#1
0
    async def get_input_entity(self, key):
        try:
            if key.SUBCLASS_OF_ID in (0xc91c90b6, 0xe669bf46, 0x40f202fd):
                # hex(crc32(b'InputPeer', b'InputUser' and b'InputChannel'))
                # We already have an Input version, so nothing else required
                return key
            # Try to early return if this key can be casted as input peer
            return utils.get_input_peer(key)
        except (AttributeError, TypeError):
            # Not a TLObject or can't be cast into InputPeer
            if isinstance(key, types.TLObject):
                key = utils.get_peer_id(key)
                exact = True
            else:
                exact = not isinstance(key, int) or key < 0

        result = None
        if isinstance(key, str):
            phone = utils.parse_phone(key)
            if phone:
                result = await self.get_entity_rows_by_phone(phone)
            else:
                username, invite = utils.parse_username(key)
                if username and not invite:
                    result = await self.get_entity_rows_by_username(username)
                else:
                    tup = utils.resolve_invite_link(key)[1]
                    if tup:
                        result = await self.get_entity_rows_by_id(tup, exact=False)

        elif isinstance(key, int):
            result = await self.get_entity_rows_by_id(key, exact)

        if not result and isinstance(key, str):
            result = await self.get_entity_rows_by_name(key)

        if result:
            entity_id, entity_hash = result  # unpack resulting tuple
            entity_id, kind = utils.resolve_id(entity_id)
            # removes the mark and returns type of entity
            if kind == types.PeerUser:
                return types.InputPeerUser(entity_id, entity_hash)
            elif kind == types.PeerChat:
                return types.InputPeerChat(entity_id)
            elif kind == types.PeerChannel:
                return types.InputPeerChannel(entity_id, entity_hash)
        else:
            raise ValueError('Could not find input entity with key ', key)
示例#2
0
    def iter_resume_entities(self, context_id):
        """
        Returns an iterator over the entities that need resuming for the
        given context_id. Note that the entities are *removed* once the
        iterator is consumed completely.
        """
        c = self.conn.execute("SELECT ID, AccessHash FROM ResumeEntity "
                              "WHERE ContextID = ?", (context_id,))
        row = c.fetchone()
        while row:
            kind = resolve_id(row[0])[1]
            if kind == types.PeerUser:
                yield types.InputPeerUser(row[0], row[1])
            elif kind == types.PeerChat:
                yield types.InputPeerChat(row[0])
            elif kind == types.PeerChannel:
                yield types.InputPeerChannel(row[0], row[1])
            row = c.fetchone()

        c.execute("DELETE FROM ResumeEntity WHERE ContextID = ?",
                  (context_id,))
示例#3
0
 async def get_resume_entities(self, context_id):
     """
     Returns an iterator over the entities that need resuming for the
     given context_id. Note that the entities are *removed* once the
     iterator is consumed completely.
     """
     rows = db_resume_entity.find({'context_id': context_id})
     count = await db_resume_entity.count_documents(
         {'context_id': context_id})
     logger.info(f'加载了【{count}】条待恢复数据')
     result = []
     async for row in rows:
         kind = resolve_id(row['id'])[1]
         if kind == types.PeerUser:
             result.append(
                 types.InputPeerUser(row['id'], row['access_hash']))
         elif kind == types.PeerChat:
             result.append(types.InputPeerChat(row['id']))
         elif kind == types.PeerChannel:
             result.append(
                 types.InputPeerChannel(row['id'], row['access_hash']))
     await db_resume_entity.delete_many({'context_id': context_id})
     return result
示例#4
0
    async def get_input_entity(
            self: 'TelegramClient',
            peer: 'hints.EntityLike') -> 'types.TypeInputPeer':
        """
        Turns the given entity into its input entity version.

        Most requests use this kind of :tl:`InputPeer`, so this is the most
        suitable call to make for those cases. **Generally you should let the
        library do its job** and don't worry about getting the input entity
        first, but if you're going to use an entity often, consider making the
        call:

        Arguments
            entity (`str` | `int` | :tl:`Peer` | :tl:`InputPeer`):
                If a username or invite link is given, **the library will
                use the cache**. This means that it's possible to be using
                a username that *changed* or an old invite link (this only
                happens if an invite link for a small group chat is used
                after it was upgraded to a mega-group).

                If the username or ID from the invite link is not found in
                the cache, it will be fetched. The same rules apply to phone
                numbers (``'+34 123456789'``) from people in your contact list.

                If an exact name is given, it must be in the cache too. This
                is not reliable as different people can share the same name
                and which entity is returned is arbitrary, and should be used
                only for quick tests.

                If a positive integer ID is given, the entity will be searched
                in cached users, chats or channels, without making any call.

                If a negative integer ID is given, the entity will be searched
                exactly as either a chat (prefixed with ``-``) or as a channel
                (prefixed with ``-100``).

                If a :tl:`Peer` is given, it will be searched exactly in the
                cache as either a user, chat or channel.

                If the given object can be turned into an input entity directly,
                said operation will be done.

                Unsupported types will raise ``TypeError``.

                If the entity can't be found, ``ValueError`` will be raised.

        Returns
            :tl:`InputPeerUser`, :tl:`InputPeerChat` or :tl:`InputPeerChannel`
            or :tl:`InputPeerSelf` if the parameter is ``'me'`` or ``'self'``.

            If you need to get the ID of yourself, you should use
            `get_me` with ``input_peer=True``) instead.

        Example
            .. code-block:: python

                # If you're going to use "username" often in your code
                # (make a lot of calls), consider getting its input entity
                # once, and then using the "user" everywhere instead.
                user = await client.get_input_entity('username')

                # The same applies to IDs, chats or channels.
                chat = await client.get_input_entity(-123456789)
        """
        # Short-circuit if the input parameter directly maps to an InputPeer
        try:
            return utils.get_input_peer(peer)
        except TypeError:
            pass

        # Next in priority is having a peer (or its ID) cached in-memory
        try:
            # 0x2d45687 == crc32(b'Peer')
            if isinstance(peer, int) or peer.SUBCLASS_OF_ID == 0x2d45687:
                return self._entity_cache[peer]
        except (AttributeError, KeyError):
            pass

        # Then come known strings that take precedence
        if peer in ('me', 'self'):
            return types.InputPeerSelf()

        # No InputPeer, cached peer, or known string. Fetch from disk cache
        try:
            return await self.session.get_input_entity(peer)
        except ValueError:
            pass

        # Only network left to try
        if isinstance(peer, str):
            return utils.get_input_peer(await
                                        self._get_entity_from_string(peer))

        # If we're a bot and the user has messaged us privately users.getUsers
        # will work with access_hash = 0. Similar for channels.getChannels.
        # If we're not a bot but the user is in our contacts, it seems to work
        # regardless. These are the only two special-cased requests.
        peer = utils.get_peer(peer)
        if isinstance(peer, types.PeerUser):
            users = await self(
                functions.users.GetUsersRequest(
                    [types.InputUser(peer.user_id, access_hash=0)]))
            if users and not isinstance(users[0], types.UserEmpty):
                # If the user passed a valid ID they expect to work for
                # channels but would be valid for users, we get UserEmpty.
                # Avoid returning the invalid empty input peer for that.
                #
                # We *could* try to guess if it's a channel first, and if
                # it's not, work as a chat and try to validate it through
                # another request, but that becomes too much work.
                return utils.get_input_peer(users[0])
        elif isinstance(peer, types.PeerChat):
            return types.InputPeerChat(peer.chat_id)
        elif isinstance(peer, types.PeerChannel):
            try:
                channels = await self(
                    functions.channels.GetChannelsRequest(
                        [types.InputChannel(peer.channel_id, access_hash=0)]))
                return utils.get_input_peer(channels.chats[0])
            except errors.ChannelInvalidError:
                pass

        raise ValueError(
            'Could not find the input entity for {!r}. Please read https://'
            'docs.telethon.dev/en/latest/concepts/entities.html to'
            ' find out more details.'.format(peer))