2018-06-09 22:22:54 +03:00
|
|
|
import asyncio
|
2019-07-17 13:04:53 +03:00
|
|
|
import datetime
|
2018-06-09 22:22:54 +03:00
|
|
|
import itertools
|
2018-06-18 14:22:25 +03:00
|
|
|
import time
|
2019-05-03 22:37:27 +03:00
|
|
|
import typing
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2021-09-12 14:27:13 +03:00
|
|
|
from .. import errors, hints, _tl
|
|
|
|
from .._misc import helpers, utils
|
2018-08-24 19:25:58 +03:00
|
|
|
from ..errors import MultiError, RPCError
|
2018-06-12 21:05:05 +03:00
|
|
|
|
2019-02-06 21:41:45 +03:00
|
|
|
_NOT_A_REQUEST = lambda: TypeError('You can only invoke requests, not types!')
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2019-05-03 22:37:27 +03:00
|
|
|
if typing.TYPE_CHECKING:
|
|
|
|
from .telegramclient import TelegramClient
|
|
|
|
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2019-07-17 13:04:53 +03:00
|
|
|
def _fmt_flood(delay, request, *, early=False, td=datetime.timedelta):
|
|
|
|
return (
|
|
|
|
'Sleeping%s for %ds (%s) on %s flood wait',
|
|
|
|
' early' if early else '',
|
|
|
|
delay,
|
|
|
|
td(seconds=delay),
|
|
|
|
request.__class__.__name__
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-09-12 16:46:57 +03:00
|
|
|
async def call(self: 'TelegramClient', request, ordered=False, flood_sleep_threshold=None):
|
|
|
|
return await _call(self, self._sender, request, ordered=ordered)
|
|
|
|
|
|
|
|
|
|
|
|
async def _call(self: 'TelegramClient', sender, request, ordered=False, flood_sleep_threshold=None):
|
2021-09-11 14:33:27 +03:00
|
|
|
if flood_sleep_threshold is None:
|
|
|
|
flood_sleep_threshold = self.flood_sleep_threshold
|
|
|
|
requests = (request if utils.is_list_like(request) else (request,))
|
|
|
|
for r in requests:
|
2021-09-12 16:46:57 +03:00
|
|
|
if not isinstance(r, _tl.TLRequest):
|
2021-09-11 14:33:27 +03:00
|
|
|
raise _NOT_A_REQUEST()
|
|
|
|
await r.resolve(self, utils)
|
|
|
|
|
|
|
|
# Avoid making the request if it's already in a flood wait
|
|
|
|
if r.CONSTRUCTOR_ID in self._flood_waited_requests:
|
|
|
|
due = self._flood_waited_requests[r.CONSTRUCTOR_ID]
|
|
|
|
diff = round(due - time.time())
|
|
|
|
if diff <= 3: # Flood waits below 3 seconds are "ignored"
|
|
|
|
self._flood_waited_requests.pop(r.CONSTRUCTOR_ID, None)
|
|
|
|
elif diff <= flood_sleep_threshold:
|
|
|
|
self._log[__name__].info(*_fmt_flood(diff, r, early=True))
|
|
|
|
await asyncio.sleep(diff)
|
|
|
|
self._flood_waited_requests.pop(r.CONSTRUCTOR_ID, None)
|
|
|
|
else:
|
|
|
|
raise errors.FloodWaitError(request=r, capture=diff)
|
2018-07-21 13:25:20 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
if self._no_updates:
|
2021-09-12 13:16:02 +03:00
|
|
|
r = _tl.fn.InvokeWithoutUpdates(r)
|
2021-08-22 14:38:54 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
request_index = 0
|
|
|
|
last_error = None
|
|
|
|
self._last_request = time.time()
|
2020-10-01 12:53:17 +03:00
|
|
|
|
2021-09-12 14:27:13 +03:00
|
|
|
for attempt in helpers.retry_range(self._request_retries):
|
2021-09-11 14:33:27 +03:00
|
|
|
try:
|
|
|
|
future = sender.send(request, ordered=ordered)
|
|
|
|
if isinstance(future, list):
|
|
|
|
results = []
|
|
|
|
exceptions = []
|
|
|
|
for f in future:
|
|
|
|
try:
|
|
|
|
result = await f
|
|
|
|
except RPCError as e:
|
|
|
|
exceptions.append(e)
|
|
|
|
results.append(None)
|
|
|
|
continue
|
2018-10-12 23:00:02 +03:00
|
|
|
self.session.process_entities(result)
|
2019-03-26 13:27:21 +03:00
|
|
|
self._entity_cache.add(result)
|
2021-09-11 14:33:27 +03:00
|
|
|
exceptions.append(None)
|
|
|
|
results.append(result)
|
|
|
|
request_index += 1
|
|
|
|
if any(x is not None for x in exceptions):
|
|
|
|
raise MultiError(exceptions, results, requests)
|
2018-06-09 22:22:54 +03:00
|
|
|
else:
|
2021-09-11 14:33:27 +03:00
|
|
|
return results
|
2018-06-20 21:18:16 +03:00
|
|
|
else:
|
2021-09-11 14:33:27 +03:00
|
|
|
result = await future
|
|
|
|
self.session.process_entities(result)
|
|
|
|
self._entity_cache.add(result)
|
|
|
|
return result
|
|
|
|
except (errors.ServerError, errors.RpcCallFailError,
|
|
|
|
errors.RpcMcgetFailError, errors.InterdcCallErrorError,
|
|
|
|
errors.InterdcCallRichErrorError) as e:
|
|
|
|
last_error = e
|
|
|
|
self._log[__name__].warning(
|
|
|
|
'Telegram is having internal issues %s: %s',
|
|
|
|
e.__class__.__name__, e)
|
|
|
|
|
|
|
|
await asyncio.sleep(2)
|
|
|
|
except (errors.FloodWaitError, errors.SlowModeWaitError, errors.FloodTestPhoneWaitError) as e:
|
|
|
|
last_error = e
|
|
|
|
if utils.is_list_like(request):
|
|
|
|
request = request[request_index]
|
|
|
|
|
|
|
|
# SLOW_MODE_WAIT is chat-specific, not request-specific
|
|
|
|
if not isinstance(e, errors.SlowModeWaitError):
|
|
|
|
self._flood_waited_requests\
|
|
|
|
[request.CONSTRUCTOR_ID] = time.time() + e.seconds
|
|
|
|
|
|
|
|
# In test servers, FLOOD_WAIT_0 has been observed, and sleeping for
|
|
|
|
# such a short amount will cause retries very fast leading to issues.
|
|
|
|
if e.seconds == 0:
|
|
|
|
e.seconds = 1
|
|
|
|
|
|
|
|
if e.seconds <= self.flood_sleep_threshold:
|
|
|
|
self._log[__name__].info(*_fmt_flood(e.seconds, request))
|
|
|
|
await asyncio.sleep(e.seconds)
|
|
|
|
else:
|
|
|
|
raise
|
|
|
|
except (errors.PhoneMigrateError, errors.NetworkMigrateError,
|
|
|
|
errors.UserMigrateError) as e:
|
|
|
|
last_error = e
|
|
|
|
self._log[__name__].info('Phone migrated to %d', e.new_dc)
|
|
|
|
should_raise = isinstance(e, (
|
|
|
|
errors.PhoneMigrateError, errors.NetworkMigrateError
|
|
|
|
))
|
|
|
|
if should_raise and await self.is_user_authorized():
|
|
|
|
raise
|
|
|
|
await self._switch_dc(e.new_dc)
|
|
|
|
|
|
|
|
if self._raise_last_call_error and last_error is not None:
|
|
|
|
raise last_error
|
|
|
|
raise ValueError('Request was unsuccessful {} time(s)'
|
|
|
|
.format(attempt))
|
|
|
|
|
|
|
|
|
|
|
|
async def get_me(self: 'TelegramClient', input_peer: bool = False) \
|
2021-09-12 13:16:02 +03:00
|
|
|
-> 'typing.Union[_tl.User, _tl.InputPeerUser]':
|
2021-09-11 14:33:27 +03:00
|
|
|
if input_peer and self._self_input_peer:
|
|
|
|
return self._self_input_peer
|
|
|
|
|
|
|
|
try:
|
|
|
|
me = (await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.users.GetUsers([_tl.InputUserSelf()])))[0]
|
2021-09-11 14:33:27 +03:00
|
|
|
|
|
|
|
self._bot = me.bot
|
|
|
|
if not self._self_input_peer:
|
|
|
|
self._self_input_peer = utils.get_input_peer(
|
|
|
|
me, allow_self=False
|
|
|
|
)
|
|
|
|
|
|
|
|
return self._self_input_peer if input_peer else me
|
|
|
|
except errors.UnauthorizedError:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _self_id(self: 'TelegramClient') -> typing.Optional[int]:
|
|
|
|
"""
|
|
|
|
Returns the ID of the logged-in user, if known.
|
|
|
|
|
|
|
|
This property is used in every update, and some like `updateLoginToken`
|
|
|
|
occur prior to login, so it gracefully handles when no ID is known yet.
|
|
|
|
"""
|
|
|
|
return self._self_input_peer.user_id if self._self_input_peer else None
|
|
|
|
|
|
|
|
async def is_bot(self: 'TelegramClient') -> bool:
|
|
|
|
if self._bot is None:
|
|
|
|
self._bot = (await self.get_me()).bot
|
|
|
|
|
|
|
|
return self._bot
|
|
|
|
|
|
|
|
async def is_user_authorized(self: 'TelegramClient') -> bool:
|
|
|
|
if self._authorized is None:
|
2019-04-03 10:36:58 +03:00
|
|
|
try:
|
2021-09-11 14:33:27 +03:00
|
|
|
# Any request that requires authorization will work
|
2021-09-12 13:16:02 +03:00
|
|
|
await self(_tl.fn.updates.GetState())
|
2021-09-11 14:33:27 +03:00
|
|
|
self._authorized = True
|
|
|
|
except errors.RPCError:
|
|
|
|
self._authorized = False
|
|
|
|
|
|
|
|
return self._authorized
|
|
|
|
|
|
|
|
async def get_entity(
|
|
|
|
self: 'TelegramClient',
|
|
|
|
entity: 'hints.EntitiesLike') -> 'hints.Entity':
|
|
|
|
single = not utils.is_list_like(entity)
|
|
|
|
if single:
|
|
|
|
entity = (entity,)
|
|
|
|
|
|
|
|
# Group input entities by string (resolve username),
|
|
|
|
# input users (get users), input chat (get chats) and
|
|
|
|
# input channels (get channels) to get the most entities
|
|
|
|
# in the less amount of calls possible.
|
|
|
|
inputs = []
|
|
|
|
for x in entity:
|
|
|
|
if isinstance(x, str):
|
|
|
|
inputs.append(x)
|
|
|
|
else:
|
|
|
|
inputs.append(await self.get_input_entity(x))
|
|
|
|
|
|
|
|
lists = {
|
|
|
|
helpers._EntityType.USER: [],
|
|
|
|
helpers._EntityType.CHAT: [],
|
|
|
|
helpers._EntityType.CHANNEL: [],
|
|
|
|
}
|
|
|
|
for x in inputs:
|
2019-04-03 10:36:58 +03:00
|
|
|
try:
|
2021-09-11 14:33:27 +03:00
|
|
|
lists[helpers._entity_type(x)].append(x)
|
|
|
|
except TypeError:
|
2019-04-03 10:36:58 +03:00
|
|
|
pass
|
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
users = lists[helpers._EntityType.USER]
|
|
|
|
chats = lists[helpers._EntityType.CHAT]
|
|
|
|
channels = lists[helpers._EntityType.CHANNEL]
|
|
|
|
if users:
|
2021-09-13 22:00:31 +03:00
|
|
|
# GetUsers has a limit of 200 per call
|
2021-09-11 14:33:27 +03:00
|
|
|
tmp = []
|
|
|
|
while users:
|
|
|
|
curr, users = users[:200], users[200:]
|
2021-09-12 13:16:02 +03:00
|
|
|
tmp.extend(await self(_tl.fn.users.GetUsers(curr)))
|
2021-09-11 14:33:27 +03:00
|
|
|
users = tmp
|
|
|
|
if chats: # TODO Handle chats slice?
|
|
|
|
chats = (await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.messages.GetChats([x.chat_id for x in chats]))).chats
|
2021-09-11 14:33:27 +03:00
|
|
|
if channels:
|
|
|
|
channels = (await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.channels.GetChannels(channels))).chats
|
2021-09-11 14:33:27 +03:00
|
|
|
|
|
|
|
# Merge users, chats and channels into a single dictionary
|
|
|
|
id_entity = {
|
|
|
|
utils.get_peer_id(x): x
|
|
|
|
for x in itertools.chain(users, chats, channels)
|
|
|
|
}
|
|
|
|
|
|
|
|
# We could check saved usernames and put them into the users,
|
|
|
|
# chats and channels list from before. While this would reduce
|
|
|
|
# the amount of ResolveUsername calls, it would fail to catch
|
|
|
|
# username changes.
|
|
|
|
result = []
|
|
|
|
for x in inputs:
|
|
|
|
if isinstance(x, str):
|
2021-09-12 15:09:53 +03:00
|
|
|
result.append(await _get_entity_from_string(self, x))
|
2021-09-12 13:16:02 +03:00
|
|
|
elif not isinstance(x, _tl.InputPeerSelf):
|
2021-09-11 14:33:27 +03:00
|
|
|
result.append(id_entity[utils.get_peer_id(x)])
|
|
|
|
else:
|
|
|
|
result.append(next(
|
|
|
|
u for u in id_entity.values()
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(u, _tl.User) and u.is_self
|
2021-09-11 14:33:27 +03:00
|
|
|
))
|
|
|
|
|
|
|
|
return result[0] if single else result
|
|
|
|
|
|
|
|
async def get_input_entity(
|
|
|
|
self: 'TelegramClient',
|
2021-09-12 13:16:02 +03:00
|
|
|
peer: 'hints.EntityLike') -> '_tl.TypeInputPeer':
|
2021-09-11 14:33:27 +03:00
|
|
|
# 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'):
|
2021-09-12 13:16:02 +03:00
|
|
|
return _tl.InputPeerSelf()
|
2021-09-11 14:33:27 +03:00
|
|
|
|
|
|
|
# No InputPeer, cached peer, or known string. Fetch from disk cache
|
|
|
|
try:
|
|
|
|
return self.session.get_input_entity(peer)
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Only network left to try
|
|
|
|
if isinstance(peer, str):
|
|
|
|
return utils.get_input_peer(
|
2021-09-12 15:09:53 +03:00
|
|
|
await _get_entity_from_string(self, peer))
|
2021-09-11 14:33:27 +03:00
|
|
|
|
|
|
|
# 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)
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(peer, _tl.PeerUser):
|
|
|
|
users = await self(_tl.fn.users.GetUsers([
|
|
|
|
_tl.InputUser(peer.user_id, access_hash=0)]))
|
|
|
|
if users and not isinstance(users[0], _tl.UserEmpty):
|
2021-09-11 14:33:27 +03:00
|
|
|
# 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])
|
2021-09-12 13:16:02 +03:00
|
|
|
elif isinstance(peer, _tl.PeerChat):
|
|
|
|
return _tl.InputPeerChat(peer.chat_id)
|
|
|
|
elif isinstance(peer, _tl.PeerChannel):
|
2018-06-09 22:22:54 +03:00
|
|
|
try:
|
2021-09-12 13:16:02 +03:00
|
|
|
channels = await self(_tl.fn.channels.GetChannels([
|
|
|
|
_tl.InputChannel(peer.channel_id, access_hash=0)]))
|
2021-09-11 14:33:27 +03:00
|
|
|
return utils.get_input_peer(channels.chats[0])
|
|
|
|
except errors.ChannelInvalidError:
|
2018-06-09 22:22:54 +03:00
|
|
|
pass
|
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
raise ValueError(
|
|
|
|
'Could not find the input entity for {} ({}). Please read https://'
|
|
|
|
'docs.telethon.dev/en/latest/concepts/entities.html to'
|
|
|
|
' find out more details.'
|
|
|
|
.format(peer, type(peer).__name__)
|
|
|
|
)
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
async def _get_peer(self: 'TelegramClient', peer: 'hints.EntityLike'):
|
|
|
|
i, cls = utils.resolve_id(await self.get_peer_id(peer))
|
|
|
|
return cls(i)
|
2020-10-23 20:02:43 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
async def get_peer_id(
|
|
|
|
self: 'TelegramClient',
|
2021-09-18 17:29:45 +03:00
|
|
|
peer: 'hints.EntityLike') -> int:
|
2021-09-11 14:33:27 +03:00
|
|
|
if isinstance(peer, int):
|
2021-09-18 17:29:45 +03:00
|
|
|
return utils.get_peer_id(peer)
|
2018-07-07 13:45:50 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
try:
|
|
|
|
if peer.SUBCLASS_OF_ID not in (0x2d45687, 0xc91c90b6):
|
|
|
|
# 0x2d45687, 0xc91c90b6 == crc32(b'Peer') and b'InputPeer'
|
2019-02-11 12:40:35 +03:00
|
|
|
peer = await self.get_input_entity(peer)
|
2021-09-11 14:33:27 +03:00
|
|
|
except AttributeError:
|
|
|
|
peer = await self.get_input_entity(peer)
|
2018-07-07 13:45:50 +03:00
|
|
|
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(peer, _tl.InputPeerSelf):
|
2021-09-11 14:33:27 +03:00
|
|
|
peer = await self.get_me(input_peer=True)
|
2018-07-07 13:45:50 +03:00
|
|
|
|
2021-09-18 17:29:45 +03:00
|
|
|
return utils.get_peer_id(peer)
|
2018-06-09 22:22:54 +03:00
|
|
|
|
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
async def _get_entity_from_string(self: 'TelegramClient', string):
|
|
|
|
"""
|
|
|
|
Gets a full entity from the given string, which may be a phone or
|
|
|
|
a username, and processes all the found entities on the session.
|
|
|
|
The string may also be a user link, or a channel/chat invite link.
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
This method has the side effect of adding the found users to the
|
|
|
|
session database, so it can be queried later without API calls,
|
|
|
|
if this option is enabled on the session.
|
2018-06-09 22:22:54 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
Returns the found entity, or raises TypeError if not found.
|
|
|
|
"""
|
|
|
|
phone = utils.parse_phone(string)
|
|
|
|
if phone:
|
|
|
|
try:
|
|
|
|
for user in (await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.contacts.GetContacts(0))).users:
|
2021-09-11 14:33:27 +03:00
|
|
|
if user.phone == phone:
|
|
|
|
return user
|
|
|
|
except errors.BotMethodInvalidError:
|
|
|
|
raise ValueError('Cannot get entity by phone number as a '
|
|
|
|
'bot (try using integer IDs, not strings)')
|
|
|
|
elif string.lower() in ('me', 'self'):
|
|
|
|
return await self.get_me()
|
|
|
|
else:
|
|
|
|
username, is_join_chat = utils.parse_username(string)
|
|
|
|
if is_join_chat:
|
|
|
|
invite = await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.messages.CheckChatInvite(username))
|
2021-09-11 14:33:27 +03:00
|
|
|
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(invite, _tl.ChatInvite):
|
2021-09-11 14:33:27 +03:00
|
|
|
raise ValueError(
|
|
|
|
'Cannot get entity from a channel (or group) '
|
|
|
|
'that you are not part of. Join the group and retry'
|
|
|
|
)
|
2021-09-12 13:16:02 +03:00
|
|
|
elif isinstance(invite, _tl.ChatInviteAlready):
|
2021-09-11 14:33:27 +03:00
|
|
|
return invite.chat
|
|
|
|
elif username:
|
2018-10-15 19:42:35 +03:00
|
|
|
try:
|
2021-09-11 14:33:27 +03:00
|
|
|
result = await self(
|
2021-09-12 13:16:02 +03:00
|
|
|
_tl.fn.contacts.ResolveUsername(username))
|
2021-09-11 14:33:27 +03:00
|
|
|
except errors.UsernameNotOccupiedError as e:
|
|
|
|
raise ValueError('No user has "{}" as username'
|
|
|
|
.format(username)) from e
|
|
|
|
|
2018-06-09 22:22:54 +03:00
|
|
|
try:
|
2021-09-18 17:29:45 +03:00
|
|
|
pid = utils.get_peer_id(result.peer)
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(result.peer, _tl.PeerUser):
|
2021-09-11 14:33:27 +03:00
|
|
|
return next(x for x in result.users if x.id == pid)
|
|
|
|
else:
|
|
|
|
return next(x for x in result.chats if x.id == pid)
|
|
|
|
except StopIteration:
|
2018-06-09 22:22:54 +03:00
|
|
|
pass
|
2018-09-22 11:56:37 +03:00
|
|
|
try:
|
2021-09-11 14:33:27 +03:00
|
|
|
# Nobody with this username, maybe it's an exact name/title
|
|
|
|
return await self.get_entity(
|
|
|
|
self.session.get_input_entity(string))
|
|
|
|
except ValueError:
|
2021-03-13 21:06:19 +03:00
|
|
|
pass
|
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
raise ValueError(
|
|
|
|
'Cannot find any entity corresponding to "{}"'.format(string)
|
|
|
|
)
|
2018-07-07 13:14:03 +03:00
|
|
|
|
2021-09-11 14:33:27 +03:00
|
|
|
async def _get_input_dialog(self: 'TelegramClient', dialog):
|
|
|
|
"""
|
|
|
|
Returns a :tl:`InputDialogPeer`. This is a bit tricky because
|
|
|
|
it may or not need access to the client to convert what's given
|
|
|
|
into an input entity.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
if dialog.SUBCLASS_OF_ID == 0xa21c9795: # crc32(b'InputDialogPeer')
|
|
|
|
dialog.peer = await self.get_input_entity(dialog.peer)
|
|
|
|
return dialog
|
|
|
|
elif dialog.SUBCLASS_OF_ID == 0xc91c90b6: # crc32(b'InputPeer')
|
2021-09-12 13:16:02 +03:00
|
|
|
return _tl.InputDialogPeer(dialog)
|
2021-09-11 14:33:27 +03:00
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
2021-09-12 13:16:02 +03:00
|
|
|
return _tl.InputDialogPeer(await self.get_input_entity(dialog))
|
2021-09-11 14:33:27 +03:00
|
|
|
|
|
|
|
async def _get_input_notify(self: 'TelegramClient', notify):
|
|
|
|
"""
|
|
|
|
Returns a :tl:`InputNotifyPeer`. This is a bit tricky because
|
|
|
|
it may or not need access to the client to convert what's given
|
|
|
|
into an input entity.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
if notify.SUBCLASS_OF_ID == 0x58981615:
|
2021-09-12 13:16:02 +03:00
|
|
|
if isinstance(notify, _tl.InputNotifyPeer):
|
2021-09-11 14:33:27 +03:00
|
|
|
notify.peer = await self.get_input_entity(notify.peer)
|
|
|
|
return notify
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
|
|
|
|
2021-09-12 13:16:02 +03:00
|
|
|
return _tl.InputNotifyPeer(await self.get_input_entity(notify))
|