mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 09:26:37 +03:00
65 lines
2.4 KiB
Python
65 lines
2.4 KiB
Python
# This file is based on TLSharp
|
|
# https://github.com/sochix/TLSharp/blob/master/TLSharp.Core/Network/TcpMessage.cs
|
|
from zlib import crc32
|
|
|
|
from utils.binary_writer import BinaryWriter
|
|
from utils.binary_reader import BinaryReader
|
|
|
|
|
|
class TcpMessage:
|
|
def __init__(self, seq_number, body):
|
|
"""
|
|
:param seq_number: Sequence number
|
|
:param body: Message body byte array
|
|
"""
|
|
if body is None:
|
|
raise ValueError('body cannot be None')
|
|
|
|
self.sequence_number = seq_number
|
|
self.body = body
|
|
|
|
def encode(self):
|
|
"""Returns the bytes of the this message encoded, following Telegram's guidelines"""
|
|
with BinaryWriter() as writer:
|
|
''' https://core.telegram.org/mtproto#tcp-transport
|
|
|
|
4 length bytes are added at the front
|
|
(to include the length, the sequence number, and CRC32; always divisible by 4)
|
|
and 4 bytes with the packet sequence number within this TCP connection
|
|
(the first packet sent is numbered 0, the next one 1, etc.),
|
|
and 4 CRC32 bytes at the end (length, sequence number, and payload together).
|
|
'''
|
|
writer.write_int(len(self.body) + 12)
|
|
writer.write_int(self.sequence_number)
|
|
writer.write(self.body)
|
|
writer.flush() # Flush so we can get the buffer in the CRC
|
|
|
|
crc = crc32(writer.get_bytes()[0:8 + len(self.body)])
|
|
writer.write_int(crc, signed=False)
|
|
|
|
return writer.get_bytes()
|
|
|
|
@staticmethod
|
|
def decode(body):
|
|
"""Returns a TcpMessage from the given encoded bytes, decoding them previously"""
|
|
if body is None:
|
|
raise ValueError('body cannot be None')
|
|
|
|
if len(body) < 12:
|
|
raise ValueError('Wrong size of input packet')
|
|
|
|
with BinaryReader(body) as reader:
|
|
packet_len = int.from_bytes(reader.read(4), byteorder='big')
|
|
if packet_len < 12:
|
|
raise ValueError('Invalid packet length: {}'.format(packet_len))
|
|
|
|
seq = reader.read_int()
|
|
packet = reader.read(packet_len - 12)
|
|
checksum = reader.read_int()
|
|
|
|
valid_checksum = crc32(body[:packet_len - 4])
|
|
if checksum != valid_checksum:
|
|
raise ValueError('Invalid checksum, skip')
|
|
|
|
return TcpMessage(seq, packet)
|