mirror of
				https://github.com/LonamiWebs/Telethon.git
				synced 2025-10-31 07:57:38 +03:00 
			
		
		
		
	Document the network/ module
This commit is contained in:
		
							parent
							
								
									7509ba9067
								
							
						
					
					
						commit
						9046b46fcd
					
				|  | @ -1,3 +1,7 @@ | |||
| """ | ||||
| This module contains several classes regarding network, low level connection | ||||
| with Telegram's servers and the protocol used (TCP full, abridged, etc.). | ||||
| """ | ||||
| from .mtproto_plain_sender import MtProtoPlainSender | ||||
| from .authenticator import do_authentication | ||||
| from .mtproto_sender import MtProtoSender | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| """ | ||||
| This module contains several functions that authenticate the client machine | ||||
| with Telegram's servers, effectively creating an authorization key. | ||||
| """ | ||||
| import os | ||||
| import time | ||||
| from hashlib import sha1 | ||||
|  | @ -18,6 +22,14 @@ from ..tl.functions import ( | |||
| 
 | ||||
| 
 | ||||
| def do_authentication(connection, retries=5): | ||||
|     """ | ||||
|     Performs the authentication steps on the given connection. | ||||
|     Raises an error if all attempts fail. | ||||
| 
 | ||||
|     :param connection: the connection to be used (must be connected). | ||||
|     :param retries: how many times should we retry on failure. | ||||
|     :return: | ||||
|     """ | ||||
|     if not retries or retries < 0: | ||||
|         retries = 1 | ||||
| 
 | ||||
|  | @ -32,9 +44,11 @@ def do_authentication(connection, retries=5): | |||
| 
 | ||||
| 
 | ||||
| def _do_authentication(connection): | ||||
|     """Executes the authentication process with the Telegram servers. | ||||
|        If no error is raised, returns both the authorization key and the | ||||
|        time offset. | ||||
|     """ | ||||
|     Executes the authentication process with the Telegram servers. | ||||
| 
 | ||||
|     :param connection: the connection to be used (must be connected). | ||||
|     :return: returns a (authorization key, time offset) tuple. | ||||
|     """ | ||||
|     sender = MtProtoPlainSender(connection) | ||||
| 
 | ||||
|  | @ -195,8 +209,12 @@ def _do_authentication(connection): | |||
| 
 | ||||
| 
 | ||||
| def get_int(byte_array, signed=True): | ||||
|     """Gets the specified integer from its byte array. | ||||
|        This should be used by the authenticator, | ||||
|        who requires the data to be in big endian | ||||
|     """ | ||||
|     Gets the specified integer from its byte array. | ||||
|     This should be used by this module alone, as it works with big endian. | ||||
| 
 | ||||
|     :param byte_array: the byte array representing th integer. | ||||
|     :param signed: whether the number is signed or not. | ||||
|     :return: the integer representing the given byte array. | ||||
|     """ | ||||
|     return int.from_bytes(byte_array, byteorder='big', signed=signed) | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| """ | ||||
| This module holds both the Connection class and the ConnectionMode enum, | ||||
| which specifies the protocol to be used by the Connection. | ||||
| """ | ||||
| import os | ||||
| import struct | ||||
| from datetime import timedelta | ||||
|  | @ -35,16 +39,24 @@ class ConnectionMode(Enum): | |||
| 
 | ||||
| 
 | ||||
| class Connection: | ||||
|     """Represents an abstract connection (TCP, TCP abridged...). | ||||
|        'mode' must be any of the ConnectionMode enumeration. | ||||
|     """ | ||||
|     Represents an abstract connection (TCP, TCP abridged...). | ||||
|     'mode' must be any of the ConnectionMode enumeration. | ||||
| 
 | ||||
|        Note that '.send()' and '.recv()' refer to messages, which | ||||
|        will be packed accordingly, whereas '.write()' and '.read()' | ||||
|        work on plain bytes, with no further additions. | ||||
|     Note that '.send()' and '.recv()' refer to messages, which | ||||
|     will be packed accordingly, whereas '.write()' and '.read()' | ||||
|     work on plain bytes, with no further additions. | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, mode=ConnectionMode.TCP_FULL, | ||||
|                  proxy=None, timeout=timedelta(seconds=5)): | ||||
|         """ | ||||
|         Initializes a new connection. | ||||
| 
 | ||||
|         :param mode: the ConnectionMode to be used. | ||||
|         :param proxy: whether to use a proxy or not. | ||||
|         :param timeout: timeout to be used for all operations. | ||||
|         """ | ||||
|         self._mode = mode | ||||
|         self._send_counter = 0 | ||||
|         self._aes_encrypt, self._aes_decrypt = None, None | ||||
|  | @ -75,6 +87,12 @@ class Connection: | |||
|             setattr(self, 'read', self._read_plain) | ||||
| 
 | ||||
|     def connect(self, ip, port): | ||||
|         """ | ||||
|         Estabilishes a connection to IP:port. | ||||
| 
 | ||||
|         :param ip: the IP to connect to. | ||||
|         :param port: the port to connect to. | ||||
|         """ | ||||
|         try: | ||||
|             self.conn.connect(ip, port) | ||||
|         except OSError as e: | ||||
|  | @ -92,9 +110,13 @@ class Connection: | |||
|             self._setup_obfuscation() | ||||
| 
 | ||||
|     def get_timeout(self): | ||||
|         """Returns the timeout used by the connection.""" | ||||
|         return self.conn.timeout | ||||
| 
 | ||||
|     def _setup_obfuscation(self): | ||||
|         """ | ||||
|         Sets up the obfuscated protocol. | ||||
|         """ | ||||
|         # Obfuscated messages secrets cannot start with any of these | ||||
|         keywords = (b'PVrG', b'GET ', b'POST', b'\xee' * 4) | ||||
|         while True: | ||||
|  | @ -122,13 +144,19 @@ class Connection: | |||
|         self.conn.write(bytes(random)) | ||||
| 
 | ||||
|     def is_connected(self): | ||||
|         """ | ||||
|         Determines whether the connection is alive or not. | ||||
| 
 | ||||
|         :return: true if it's connected. | ||||
|         """ | ||||
|         return self.conn.connected | ||||
| 
 | ||||
|     def close(self): | ||||
|         """Closes the connection.""" | ||||
|         self.conn.close() | ||||
| 
 | ||||
|     def clone(self): | ||||
|         """Creates a copy of this Connection""" | ||||
|         """Creates a copy of this Connection.""" | ||||
|         return Connection( | ||||
|             mode=self._mode, proxy=self.conn.proxy, timeout=self.conn.timeout | ||||
|         ) | ||||
|  | @ -141,6 +169,15 @@ class Connection: | |||
|         raise ValueError('Invalid connection mode specified: ' + str(self._mode)) | ||||
| 
 | ||||
|     def _recv_tcp_full(self): | ||||
|         """ | ||||
|         Receives a message from the network, | ||||
|         internally encoded using the TCP full protocol. | ||||
| 
 | ||||
|         May raise InvalidChecksumError if the received data doesn't | ||||
|         match its valid checksum. | ||||
| 
 | ||||
|         :return: the read message payload. | ||||
|         """ | ||||
|         packet_len_seq = self.read(8)  # 4 and 4 | ||||
|         packet_len, seq = struct.unpack('<ii', packet_len_seq) | ||||
| 
 | ||||
|  | @ -154,9 +191,21 @@ class Connection: | |||
|         return body | ||||
| 
 | ||||
|     def _recv_intermediate(self): | ||||
|         """ | ||||
|         Receives a message from the network, | ||||
|         internally encoded using the TCP intermediate protocol. | ||||
| 
 | ||||
|         :return: the read message payload. | ||||
|         """ | ||||
|         return self.read(struct.unpack('<i', self.read(4))[0]) | ||||
| 
 | ||||
|     def _recv_abridged(self): | ||||
|         """ | ||||
|         Receives a message from the network, | ||||
|         internally encoded using the TCP abridged protocol. | ||||
| 
 | ||||
|         :return: the read message payload. | ||||
|         """ | ||||
|         length = struct.unpack('<B', self.read(1))[0] | ||||
|         if length >= 127: | ||||
|             length = struct.unpack('<i', self.read(3) + b'\0')[0] | ||||
|  | @ -173,6 +222,12 @@ class Connection: | |||
|         raise ValueError('Invalid connection mode specified: ' + str(self._mode)) | ||||
| 
 | ||||
|     def _send_tcp_full(self, message): | ||||
|         """ | ||||
|         Encapsulates and sends the given message payload | ||||
|         using the TCP full mode (length, sequence, message, crc32). | ||||
| 
 | ||||
|         :param message: the message to be sent. | ||||
|         """ | ||||
|         # https://core.telegram.org/mtproto#tcp-transport | ||||
|         # total length, sequence number, packet and checksum (CRC32) | ||||
|         length = len(message) + 12 | ||||
|  | @ -182,9 +237,21 @@ class Connection: | |||
|         self.write(data + crc) | ||||
| 
 | ||||
|     def _send_intermediate(self, message): | ||||
|         """ | ||||
|         Encapsulates and sends the given message payload | ||||
|         using the TCP intermediate mode (length, message). | ||||
| 
 | ||||
|         :param message: the message to be sent. | ||||
|         """ | ||||
|         self.write(struct.pack('<i', len(message)) + message) | ||||
| 
 | ||||
|     def _send_abridged(self, message): | ||||
|         """ | ||||
|         Encapsulates and sends the given message payload | ||||
|         using the TCP abridged mode (short length, message). | ||||
| 
 | ||||
|         :param message: the message to be sent. | ||||
|         """ | ||||
|         length = len(message) >> 2 | ||||
|         if length < 127: | ||||
|             length = struct.pack('B', length) | ||||
|  | @ -201,9 +268,21 @@ class Connection: | |||
|         raise ValueError('Invalid connection mode specified: ' + str(self._mode)) | ||||
| 
 | ||||
|     def _read_plain(self, length): | ||||
|         """ | ||||
|         Reads data from the socket connection. | ||||
| 
 | ||||
|         :param length: how many bytes should be read. | ||||
|         :return: a byte sequence with len(data) == length | ||||
|         """ | ||||
|         return self.conn.read(length) | ||||
| 
 | ||||
|     def _read_obfuscated(self, length): | ||||
|         """ | ||||
|         Reads data and decrypts from the socket connection. | ||||
| 
 | ||||
|         :param length: how many bytes should be read. | ||||
|         :return: the decrypted byte sequence with len(data) == length | ||||
|         """ | ||||
|         return self._aes_decrypt.encrypt( | ||||
|             self.conn.read(length) | ||||
|         ) | ||||
|  | @ -216,9 +295,20 @@ class Connection: | |||
|         raise ValueError('Invalid connection mode specified: ' + str(self._mode)) | ||||
| 
 | ||||
|     def _write_plain(self, data): | ||||
|         """ | ||||
|         Writes the given data through the socket connection. | ||||
| 
 | ||||
|         :param data: the data in bytes to be written. | ||||
|         """ | ||||
|         self.conn.write(data) | ||||
| 
 | ||||
|     def _write_obfuscated(self, data): | ||||
|         """ | ||||
|         Writes the given data through the socket connection, | ||||
|         using the obfuscated mode (AES encryption is applied on top). | ||||
| 
 | ||||
|         :param data: the data in bytes to be written. | ||||
|         """ | ||||
|         self.conn.write(self._aes_encrypt.encrypt(data)) | ||||
| 
 | ||||
|     # endregion | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| """ | ||||
| This module contains the class used to communicate with Telegram's servers | ||||
| in plain text, when no authorization key has been created yet. | ||||
| """ | ||||
| import struct | ||||
| import time | ||||
| 
 | ||||
|  | @ -6,32 +10,47 @@ from ..extensions import BinaryReader | |||
| 
 | ||||
| 
 | ||||
| class MtProtoPlainSender: | ||||
|     """MTProto Mobile Protocol plain sender | ||||
|        (https://core.telegram.org/mtproto/description#unencrypted-messages) | ||||
|     """ | ||||
|     MTProto Mobile Protocol plain sender | ||||
|     (https://core.telegram.org/mtproto/description#unencrypted-messages) | ||||
|     """ | ||||
| 
 | ||||
|     def __init__(self, connection): | ||||
|         """ | ||||
|         Initializes the MTProto plain sender. | ||||
| 
 | ||||
|         :param connection: the Connection to be used. | ||||
|         """ | ||||
|         self._sequence = 0 | ||||
|         self._time_offset = 0 | ||||
|         self._last_msg_id = 0 | ||||
|         self._connection = connection | ||||
| 
 | ||||
|     def connect(self): | ||||
|         """Connects to Telegram's servers.""" | ||||
|         self._connection.connect() | ||||
| 
 | ||||
|     def disconnect(self): | ||||
|         """Disconnects from Telegram's servers.""" | ||||
|         self._connection.close() | ||||
| 
 | ||||
|     def send(self, data): | ||||
|         """Sends a plain packet (auth_key_id = 0) containing the | ||||
|            given message body (data) | ||||
|         """ | ||||
|         Sends a plain packet (auth_key_id = 0) containing the | ||||
|         given message body (data). | ||||
| 
 | ||||
|         :param data: the data to be sent. | ||||
|         """ | ||||
|         self._connection.send( | ||||
|             struct.pack('<QQi', 0, self._get_new_msg_id(), len(data)) + data | ||||
|         ) | ||||
| 
 | ||||
|     def receive(self): | ||||
|         """Receives a plain packet, returning the body of the response""" | ||||
|         """ | ||||
|         Receives a plain packet from the network. | ||||
| 
 | ||||
|         :return: the response body. | ||||
|         """ | ||||
|         body = self._connection.recv() | ||||
|         if body == b'l\xfe\xff\xff':  # -404 little endian signed | ||||
|             # Broken authorization, must reset the auth key | ||||
|  | @ -46,7 +65,7 @@ class MtProtoPlainSender: | |||
|             return response | ||||
| 
 | ||||
|     def _get_new_msg_id(self): | ||||
|         """Generates a new message ID based on the current time since epoch""" | ||||
|         """Generates a new message ID based on the current time since epoch.""" | ||||
|         # See core.telegram.org/mtproto/description#message-identifier-msg-id | ||||
|         now = time.time() | ||||
|         nanoseconds = int((now - int(now)) * 1e+9) | ||||
|  |  | |||
|  | @ -1,3 +1,7 @@ | |||
| """ | ||||
| This module contains the class used to communicate with Telegram's servers | ||||
| encrypting every packet, and relies on a valid AuthKey in the used Session. | ||||
| """ | ||||
| import gzip | ||||
| import logging | ||||
| import struct | ||||
|  | @ -31,8 +35,14 @@ class MtProtoSender: | |||
|     """ | ||||
| 
 | ||||
|     def __init__(self, session, connection): | ||||
|         """Creates a new MtProtoSender configured to send messages through | ||||
|            'connection' and using the parameters from 'session'. | ||||
|         """ | ||||
|         Initializes a new MTProto sender. | ||||
| 
 | ||||
|         :param session: | ||||
|             the Session to be used with this sender. Must contain the IP and | ||||
|             port of the server, salt, ID, and AuthKey, | ||||
|         :param connection: | ||||
|             the Connection to be used. | ||||
|         """ | ||||
|         self.session = session | ||||
|         self.connection = connection | ||||
|  | @ -45,28 +55,36 @@ class MtProtoSender: | |||
|         self._pending_receive = {} | ||||
| 
 | ||||
|     def connect(self): | ||||
|         """Connects to the server""" | ||||
|         """Connects to the server.""" | ||||
|         self.connection.connect(self.session.server_address, self.session.port) | ||||
| 
 | ||||
|     def is_connected(self): | ||||
|         """ | ||||
|         Determines whether the sender is connected or not. | ||||
| 
 | ||||
|         :return: true if the sender is connected. | ||||
|         """ | ||||
|         return self.connection.is_connected() | ||||
| 
 | ||||
|     def disconnect(self): | ||||
|         """Disconnects from the server""" | ||||
|         """Disconnects from the server.""" | ||||
|         self.connection.close() | ||||
|         self._need_confirmation.clear() | ||||
|         self._clear_all_pending() | ||||
| 
 | ||||
|     def clone(self): | ||||
|         """Creates a copy of this MtProtoSender as a new connection""" | ||||
|         """Creates a copy of this MtProtoSender as a new connection.""" | ||||
|         return MtProtoSender(self.session, self.connection.clone()) | ||||
| 
 | ||||
|     # region Send and receive | ||||
| 
 | ||||
|     def send(self, *requests): | ||||
|         """Sends the specified MTProtoRequest, previously sending any message | ||||
|            which needed confirmation.""" | ||||
|         """ | ||||
|         Sends the specified TLObject(s) (which must be requests), | ||||
|         and acknowledging any message which needed confirmation. | ||||
| 
 | ||||
|         :param requests: the requests to be sent. | ||||
|         """ | ||||
|         # Finally send our packed request(s) | ||||
|         messages = [TLMessage(self.session, r) for r in requests] | ||||
|         self._pending_receive.update({m.msg_id: m for m in messages}) | ||||
|  | @ -91,18 +109,23 @@ class MtProtoSender: | |||
|         self._send_message(message) | ||||
| 
 | ||||
|     def _send_acknowledge(self, msg_id): | ||||
|         """Sends a message acknowledge for the given msg_id""" | ||||
|         """Sends a message acknowledge for the given msg_id.""" | ||||
|         self._send_message(TLMessage(self.session, MsgsAck([msg_id]))) | ||||
| 
 | ||||
|     def receive(self, update_state): | ||||
|         """Receives a single message from the connected endpoint. | ||||
|         """ | ||||
|         Receives a single message from the connected endpoint. | ||||
| 
 | ||||
|            This method returns nothing, and will only affect other parts | ||||
|            of the MtProtoSender such as the updates callback being fired | ||||
|            or a pending request being confirmed. | ||||
|         This method returns nothing, and will only affect other parts | ||||
|         of the MtProtoSender such as the updates callback being fired | ||||
|         or a pending request being confirmed. | ||||
| 
 | ||||
|            Any unhandled object (likely updates) will be passed to | ||||
|            update_state.process(TLObject). | ||||
|         Any unhandled object (likely updates) will be passed to | ||||
|         update_state.process(TLObject). | ||||
| 
 | ||||
|         :param update_state: | ||||
|             the UpdateState that will process all the received | ||||
|             Update and Updates objects. | ||||
|         """ | ||||
|         try: | ||||
|             body = self.connection.recv() | ||||
|  | @ -126,8 +149,11 @@ class MtProtoSender: | |||
|     # region Low level processing | ||||
| 
 | ||||
|     def _send_message(self, message): | ||||
|         """Sends the given Message(TLObject) encrypted through the network""" | ||||
|         """ | ||||
|         Sends the given encrypted through the network. | ||||
| 
 | ||||
|         :param message: the TLMessage to be sent. | ||||
|         """ | ||||
|         plain_text = \ | ||||
|             struct.pack('<QQ', self.session.salt, self.session.id) \ | ||||
|             + bytes(message) | ||||
|  | @ -141,7 +167,12 @@ class MtProtoSender: | |||
|         self.connection.send(result) | ||||
| 
 | ||||
|     def _decode_msg(self, body): | ||||
|         """Decodes an received encrypted message body bytes""" | ||||
|         """ | ||||
|         Decodes the body of the payload received from the network. | ||||
| 
 | ||||
|         :param body: the body to be decoded. | ||||
|         :return: a tuple of (decoded message, remote message id, remote seq). | ||||
|         """ | ||||
|         message = None | ||||
|         remote_msg_id = None | ||||
|         remote_sequence = None | ||||
|  | @ -172,12 +203,15 @@ class MtProtoSender: | |||
|         return message, remote_msg_id, remote_sequence | ||||
| 
 | ||||
|     def _process_msg(self, msg_id, sequence, reader, state): | ||||
|         """Processes and handles a Telegram message. | ||||
| 
 | ||||
|            Returns True if the message was handled correctly and doesn't | ||||
|            need to be skipped. Returns False otherwise. | ||||
|         """ | ||||
|         Processes the message read from the network inside reader. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the BinaryReader that contains the message. | ||||
|         :param state: the current UpdateState. | ||||
|         :return: true if the message was handled correctly, false otherwise. | ||||
|         """ | ||||
|         # TODO Check salt, session_id and sequence_number | ||||
|         self._need_confirmation.add(msg_id) | ||||
| 
 | ||||
|  | @ -249,24 +283,34 @@ class MtProtoSender: | |||
|     # region Message handling | ||||
| 
 | ||||
|     def _pop_request(self, msg_id): | ||||
|         """Pops a pending REQUEST from self._pending_receive, or | ||||
|            returns None if it's not found. | ||||
|         """ | ||||
|         Pops a pending **request** from self._pending_receive. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message that belongs to the request. | ||||
|         :return: the request, or None if it wasn't found. | ||||
|         """ | ||||
|         message = self._pending_receive.pop(msg_id, None) | ||||
|         if message: | ||||
|             return message.request | ||||
| 
 | ||||
|     def _pop_request_of_type(self, msg_id, t): | ||||
|         """Pops a pending REQUEST from self._pending_receive if it matches | ||||
|            the given type, or returns None if it's not found/doesn't match. | ||||
|         """ | ||||
|         Pops a pending **request** from self._pending_receive. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message that belongs to the request. | ||||
|         :param t: the type of the desired request. | ||||
|         :return: the request matching the type t, or None if it wasn't found. | ||||
|         """ | ||||
|         message = self._pending_receive.get(msg_id, None) | ||||
|         if message and isinstance(message.request, t): | ||||
|             return self._pending_receive.pop(msg_id).request | ||||
| 
 | ||||
|     def _pop_requests_of_container(self, container_msg_id): | ||||
|         """Pops the pending requests (plural) from self._pending_receive if | ||||
|            they were sent on a container that matches container_msg_id. | ||||
|         """ | ||||
|         Pops pending **requests** from self._pending_receive. | ||||
| 
 | ||||
|         :param container_msg_id: the ID of the container. | ||||
|         :return: the requests that belong to the given container. May be empty. | ||||
|         """ | ||||
|         msgs = [msg for msg in self._pending_receive.values() | ||||
|                 if msg.container_msg_id == container_msg_id] | ||||
|  | @ -277,13 +321,19 @@ class MtProtoSender: | |||
|         return requests | ||||
| 
 | ||||
|     def _clear_all_pending(self): | ||||
|         """ | ||||
|         Clears all pending requests, and flags them all as received. | ||||
|         """ | ||||
|         for r in self._pending_receive.values(): | ||||
|             r.request.confirm_received.set() | ||||
|         self._pending_receive.clear() | ||||
| 
 | ||||
|     def _resend_request(self, msg_id): | ||||
|         """Re-sends the request that belongs to a certain msg_id. This may | ||||
|            also be the msg_id of a container if they were sent in one. | ||||
|         """ | ||||
|         Re-sends the request that belongs to a certain msg_id. This may | ||||
|         also be the msg_id of a container if they were sent in one. | ||||
| 
 | ||||
|         :param msg_id: the ID of the request to be resent. | ||||
|         """ | ||||
|         request = self._pop_request(msg_id) | ||||
|         if request: | ||||
|  | @ -293,6 +343,14 @@ class MtProtoSender: | |||
|             return self.send(*requests) | ||||
| 
 | ||||
|     def _handle_pong(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a Pong response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the Pong. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         self._logger.debug('Handling pong') | ||||
|         pong = reader.tgread_object() | ||||
|         assert isinstance(pong, Pong) | ||||
|  | @ -306,6 +364,14 @@ class MtProtoSender: | |||
|         return True | ||||
| 
 | ||||
|     def _handle_container(self, msg_id, sequence, reader, state): | ||||
|         """ | ||||
|         Handles a MessageContainer response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the MessageContainer. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         self._logger.debug('Handling container') | ||||
|         for inner_msg_id, _, inner_len in MessageContainer.iter_read(reader): | ||||
|             begin_position = reader.tell_position() | ||||
|  | @ -323,6 +389,14 @@ class MtProtoSender: | |||
|         return True | ||||
| 
 | ||||
|     def _handle_bad_server_salt(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a BadServerSalt response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the BadServerSalt. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         self._logger.debug('Handling bad server salt') | ||||
|         bad_salt = reader.tgread_object() | ||||
|         assert isinstance(bad_salt, BadServerSalt) | ||||
|  | @ -339,6 +413,14 @@ class MtProtoSender: | |||
|         return True | ||||
| 
 | ||||
|     def _handle_bad_msg_notification(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a BadMessageError response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the BadMessageError. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         self._logger.debug('Handling bad message notification') | ||||
|         bad_msg = reader.tgread_object() | ||||
|         assert isinstance(bad_msg, BadMsgNotification) | ||||
|  | @ -367,6 +449,14 @@ class MtProtoSender: | |||
|             raise error | ||||
| 
 | ||||
|     def _handle_msg_detailed_info(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a MsgDetailedInfo response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the MsgDetailedInfo. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         msg_new = reader.tgread_object() | ||||
|         assert isinstance(msg_new, MsgDetailedInfo) | ||||
| 
 | ||||
|  | @ -376,6 +466,14 @@ class MtProtoSender: | |||
|         return True | ||||
| 
 | ||||
|     def _handle_msg_new_detailed_info(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a MsgNewDetailedInfo response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the MsgNewDetailedInfo. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         msg_new = reader.tgread_object() | ||||
|         assert isinstance(msg_new, MsgNewDetailedInfo) | ||||
| 
 | ||||
|  | @ -385,12 +483,29 @@ class MtProtoSender: | |||
|         return True | ||||
| 
 | ||||
|     def _handle_new_session_created(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a NewSessionCreated response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the NewSessionCreated. | ||||
|         :return: true, as it always succeeds. | ||||
|         """ | ||||
|         new_session = reader.tgread_object() | ||||
|         assert isinstance(new_session, NewSessionCreated) | ||||
|         # TODO https://goo.gl/LMyN7A | ||||
|         return True | ||||
| 
 | ||||
|     def _handle_rpc_result(self, msg_id, sequence, reader): | ||||
|         """ | ||||
|         Handles a RPCResult response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the RPCResult. | ||||
|         :return: true if the request ID to which this result belongs is found, | ||||
|                  false otherwise (meaning nothing was read). | ||||
|         """ | ||||
|         self._logger.debug('Handling RPC result') | ||||
|         reader.read_int(signed=False)  # code | ||||
|         request_id = reader.read_long() | ||||
|  | @ -440,6 +555,14 @@ class MtProtoSender: | |||
|         return False | ||||
| 
 | ||||
|     def _handle_gzip_packed(self, msg_id, sequence, reader, state): | ||||
|         """ | ||||
|         Handles a GzipPacked response. | ||||
| 
 | ||||
|         :param msg_id: the ID of the message. | ||||
|         :param sequence: the sequence of the message. | ||||
|         :param reader: the reader containing the GzipPacked. | ||||
|         :return: the result of processing the packed message. | ||||
|         """ | ||||
|         self._logger.debug('Handling gzip packed data') | ||||
|         with BinaryReader(GzipPacked.read(reader)) as compressed_reader: | ||||
|             # We are reentering process_msg, which seemingly the same msg_id | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user