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)
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,))
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
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))