Exemplo n.º 1
0
 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
Exemplo n.º 2
0
 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
Exemplo n.º 3
0
 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
Exemplo n.º 4
0
 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
Exemplo n.º 5
0
 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
Exemplo n.º 6
0
    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 = {}