async def _new_connection(self) -> Connection: if not self.dc: self.dc = await self.client._get_dc(self.dc_id) sender = MTProtoSender(self.auth_key, self.loop, loggers=self.client._log) index = len(self.connections) + 1 conn = Connection(sender=sender, log=self.log.getChild(f"conn{index}"), lock=asyncio.Lock()) self.connections.append(conn) async with conn.lock: conn.log.info("Connecting...") connection_info = self.client._connection( self.dc.ip_address, self.dc.port, self.dc.id, loop=self.loop, loggers=self.client._log, proxy=self.client._proxy, ) await sender.connect(connection_info) if not self.auth_key: await self._export_auth_key(conn) return conn
async def _create_sender(self) -> MTProtoSender: # Check if we're connecting to the same DC we're connected to if self.dc_id == self.client.session.dc_id: return self.client._sender dc = await self.client._get_dc(self.dc_id) sender = MTProtoSender(self.auth_key, self.loop, loggers=self.client._log) await sender.connect( self.client._connection( dc.ip_address, dc.port, dc.id, loop=self.loop, loggers=self.client._log, proxy=self.client._proxy, )) if not self.auth_key: log.debug(f"Exporting auth to DC {self.dc_id}") auth = await self.client(ExportAuthorizationRequest(self.dc_id)) req = self.client._init_with( ImportAuthorizationRequest(id=auth.id, bytes=auth.bytes)) await sender.send(req) self.auth_key = sender.auth_key return sender
async def _create_exported_sender(self: 'TelegramClient', dc_id): """ Creates a new exported `MTProtoSender` for the given `dc_id` and returns it. This method should be used by `_borrow_exported_sender`. """ # Thanks badoualy/kotlogram on /telegram/api/DefaultTelegramClient.kt # for clearly showing how to export the authorization dc = await self._get_dc(dc_id) # Can't reuse self._sender._connection as it has its own seqno. # # If one were to do that, Telegram would reset the connection # with no further clues. sender = MTProtoSender(None, self._loop, loggers=self._log) await sender.connect( self._connection(dc.ip_address, dc.port, dc.id, loop=self._loop, loggers=self._log, proxy=self._proxy)) self._log[__name__].info( 'Exporting auth for new borrowed sender in %s', dc) auth = await self(functions.auth.ExportAuthorizationRequest(dc_id)) req = self._init_with( functions.auth.ImportAuthorizationRequest(id=auth.id, bytes=auth.bytes)) await sender.send(req) return sender
async def _create_sender(self) -> MTProtoSender: dc = await self.client._get_dc(self.dc_id) sender = MTProtoSender(self.auth_key, loggers=self.client._log) await sender.connect(self.client._connection(dc.ip_address, dc.port, dc.id, loggers=self.client._log, proxy=self.client._proxy)) if not self.auth_key: log.debug(f"Exporting auth to DC {self.dc_id}") auth = await self.client(ExportAuthorizationRequest(self.dc_id)) self.client._init_request.query = ImportAuthorizationRequest( id=auth.id, bytes=auth.bytes) await sender.send(InvokeWithLayerRequest(LAYER, self.client._init_request)) self.auth_key = sender.auth_key return sender
async def _create_sender(self) -> MTProtoSender: dc = await self.client._get_dc(self.dc_id) sender = MTProtoSender(self.auth_key, loggers=self.client._log) await sender.connect( self.client._connection(dc.ip_address, dc.port, dc.id, loggers=self.client._log, proxy=self.client._proxy)) if not self.auth_key: log.debug(f"Kimlik doğrulama DC'ye aktarılıyor {self.dc_id}") auth = await self.client(ExportAuthorizationRequest(self.dc_id)) req = self.client._init_with( ImportAuthorizationRequest(id=auth.id, bytes=auth.bytes)) await sender.send(req) self.auth_key = sender.auth_key return sender
def __init__(self: 'TelegramClient', session: 'AbstractAsyncSession', api_id: int, api_hash: str, *, connection: 'typing.Type[Connection]' = ConnectionTcpFull, use_ipv6: bool = False, proxy: typing.Union[tuple, dict] = None, timeout: int = 10, request_retries: int = 5, connection_retries: int = 5, retry_delay: int = 1, auto_reconnect: bool = True, sequential_updates: bool = False, flood_sleep_threshold: int = 60, device_model: str = None, system_version: str = None, app_version: str = None, lang_code: str = 'en', system_lang_code: str = 'en', loop: asyncio.AbstractEventLoop = None, base_logger: typing.Union[str, logging.Logger] = None): if not api_id or not api_hash: raise ValueError("Your API ID or Hash cannot be empty or None. " "Refer to telethon.rtfd.io for more information.") self._use_ipv6 = use_ipv6 self._loop = loop or asyncio.get_event_loop() if isinstance(base_logger, str): base_logger = logging.getLogger(base_logger) elif not isinstance(base_logger, logging.Logger): base_logger = __default_log__ class _Loggers(dict): def __missing__(self, key): if key.startswith("telethon."): key = key.split('.', maxsplit=1)[1] return base_logger.getChild(key) self._log = _Loggers() # Determine what session object we have if not isinstance(session, AbstractAsyncSession): raise TypeError( 'The given session must be a str or a Session instance.') self.session_settings = settings = dict() # type: ignore # ':' in session.server_address is True if it's an IPv6 address if (not session.server_address or (':' in session.server_address) != use_ipv6): settings[session.set_dc] = ( DEFAULT_DC_ID, DEFAULT_IPV6_IP if self._use_ipv6 else DEFAULT_IPV4_IP, DEFAULT_PORT, ), {} self.flood_sleep_threshold = flood_sleep_threshold self.session = session self._entity_cache = EntityCache() self.api_id = int(api_id) self.api_hash = api_hash # Current proxy implementation requires `sock_connect`, and some # event loops lack this method. If the current loop is missing it, # bail out early and suggest an alternative. # # TODO A better fix is obviously avoiding the use of `sock_connect` # # See https://github.com/LonamiWebs/Telethon/issues/1337 for details. if not callable(getattr(self._loop, 'sock_connect', None)): raise TypeError( 'Event loop of type {} lacks `sock_connect`, which is needed to use proxies.\n\n' 'Change the event loop in use to use proxies:\n' '# https://github.com/LonamiWebs/Telethon/issues/1337\n' 'import asyncio\n' 'asyncio.set_event_loop(asyncio.SelectorEventLoop())'.format( self._loop.__class__.__name__)) self._request_retries = request_retries self._connection_retries = connection_retries self._retry_delay = retry_delay or 0 self._proxy = proxy self._timeout = timeout self._auto_reconnect = auto_reconnect assert isinstance(connection, type) self._connection = connection init_proxy = None if not issubclass(connection, TcpMTProxy) else \ types.InputClientProxy(*connection.address_info(proxy)) # Used on connection. Capture the variables in a lambda since # exporting clients need to create this InvokeWithLayerRequest. system = platform.uname() self._init_with = lambda x: functions.InvokeWithLayerRequest( LAYER, functions.InitConnectionRequest( api_id=self.api_id, device_model=device_model or system.system or 'Unknown', system_version=system_version or system.release or '1.0', app_version=app_version or self.__version__, lang_code=lang_code, system_lang_code=system_lang_code, lang_pack='', # "langPacks are for official apps only" query=x, proxy=init_proxy)) self._sender = MTProtoSender( self.session.auth_key, self._loop, loggers=self._log, retries=self._connection_retries, delay=self._retry_delay, auto_reconnect=self._auto_reconnect, connect_timeout=self._timeout, auth_key_callback=self._auth_key_callback, update_callback=self._handle_update, auto_reconnect_callback=self._handle_auto_reconnect) # Remember flood-waited requests to avoid making them again self._flood_waited_requests = {} # Cache ``{dc_id: (_ExportState, MTProtoSender)}`` for all borrowed senders self._borrowed_senders = {} self._borrow_sender_lock = asyncio.Lock(loop=self._loop) self._updates_handle = None self._last_request = time.time() self._channel_pts = {} if sequential_updates: self._updates_queue = asyncio.Queue(loop=self._loop) self._dispatching_updates_queue = asyncio.Event(loop=self._loop) else: # Use a set of pending instead of a queue so we can properly # terminate all pending updates on disconnect. self._updates_queue = set() self._dispatching_updates_queue = None self._authorized = None # None = unknown, False = no, True = yes # Update state (for catching up after a disconnection) # TODO Get state from channels too async def __set_state_cache(*args, **kwargs): # hack :C setattr( self, "_state_cache", StateCache(await self.session.get_update_state(0), self._log)) settings[__set_state_cache] = (), {} # Some further state for subclasses self._event_builders = [] # Default parse mode self._parse_mode = markdown # Some fields to easy signing in. Let {phone: hash} be # a dictionary because the user may change their mind. self._phone_code_hash = {} self._phone = None self._tos = None # Sometimes we need to know who we are, cache the self peer self._self_input_peer = None self._bot = None # A place to store if channels are a megagroup or not (see `edit_admin`) self._megagroup_cache = {}