1
0
mirror of https://gitlab.com/MoonTestUse1/AdministrationItDepartmens.git synced 2025-08-14 00:25:46 +02:00

Все подряд

This commit is contained in:
MoonTestUse1
2024-12-31 02:37:57 +06:00
parent 8e53bb6cb2
commit d5780b2eab
3258 changed files with 1087440 additions and 268 deletions

View File

@@ -0,0 +1,26 @@
"""
This module holds core "special" types, which are more convenient ways
to do stuff in a `telethon.network.mtprotosender.MTProtoSender` instance.
Only special cases are gzip-packed data, the response message (not a
client message), the message container which references these messages
and would otherwise conflict with the rest, and finally the RpcResult:
rpc_result#f35c6d01 req_msg_id:long result:bytes = RpcResult;
Three things to note with this definition:
1. The constructor ID is actually ``42d36c2c``.
2. Those bytes are not read like the rest of bytes (length + payload).
They are actually the raw bytes of another object, which can't be
read directly because it depends on per-request information (since
some can return ``Vector<int>`` and ``Vector<long>``).
3. Those bytes may be gzipped data, which needs to be treated early.
"""
from .tlmessage import TLMessage
from .gzippacked import GzipPacked
from .messagecontainer import MessageContainer
from .rpcresult import RpcResult
core_objects = {x.CONSTRUCTOR_ID: x for x in (
GzipPacked, MessageContainer, RpcResult
)}

View File

@@ -0,0 +1,45 @@
import gzip
import struct
from .. import TLObject
class GzipPacked(TLObject):
CONSTRUCTOR_ID = 0x3072cfa1
def __init__(self, data):
self.data = data
@staticmethod
def gzip_if_smaller(content_related, data):
"""Calls bytes(request), and based on a certain threshold,
optionally gzips the resulting data. If the gzipped data is
smaller than the original byte array, this is returned instead.
Note that this only applies to content related requests.
"""
if content_related and len(data) > 512:
gzipped = bytes(GzipPacked(data))
return gzipped if len(gzipped) < len(data) else data
else:
return data
def __bytes__(self):
return struct.pack('<I', GzipPacked.CONSTRUCTOR_ID) + \
TLObject.serialize_bytes(gzip.compress(self.data))
@staticmethod
def read(reader):
constructor = reader.read_int(signed=False)
assert constructor == GzipPacked.CONSTRUCTOR_ID
return gzip.decompress(reader.tgread_bytes())
@classmethod
def from_reader(cls, reader):
return GzipPacked(gzip.decompress(reader.tgread_bytes()))
def to_dict(self):
return {
'_': 'GzipPacked',
'data': self.data
}

View File

@@ -0,0 +1,47 @@
from .tlmessage import TLMessage
from ..tlobject import TLObject
class MessageContainer(TLObject):
CONSTRUCTOR_ID = 0x73f1f8dc
# Maximum size in bytes for the inner payload of the container.
# Telegram will close the connection if the payload is bigger.
# The overhead of the container itself is subtracted.
MAXIMUM_SIZE = 1044456 - 8
# Maximum amount of messages that can't be sent inside a single
# container, inclusive. Beyond this limit Telegram will respond
# with BAD_MESSAGE 64 (invalid container).
#
# This limit is not 100% accurate and may in some cases be higher.
# However, sending up to 100 requests at once in a single container
# is a reasonable conservative value, since it could also depend on
# other factors like size per request, but we cannot know this.
MAXIMUM_LENGTH = 100
def __init__(self, messages):
self.messages = messages
def to_dict(self):
return {
'_': 'MessageContainer',
'messages':
[] if self.messages is None else [
None if x is None else x.to_dict() for x in self.messages
],
}
@classmethod
def from_reader(cls, reader):
# This assumes that .read_* calls are done in the order they appear
messages = []
for _ in range(reader.read_int()):
msg_id = reader.read_long()
seq_no = reader.read_int()
length = reader.read_int()
before = reader.tell_position()
obj = reader.tgread_object() # May over-read e.g. RpcResult
reader.set_position(before + length)
messages.append(TLMessage(msg_id, seq_no, obj))
return MessageContainer(messages)

View File

@@ -0,0 +1,35 @@
from .gzippacked import GzipPacked
from .. import TLObject
from ..types import RpcError
class RpcResult(TLObject):
CONSTRUCTOR_ID = 0xf35c6d01
def __init__(self, req_msg_id, body, error):
self.req_msg_id = req_msg_id
self.body = body
self.error = error
@classmethod
def from_reader(cls, reader):
msg_id = reader.read_long()
inner_code = reader.read_int(signed=False)
if inner_code == RpcError.CONSTRUCTOR_ID:
return RpcResult(msg_id, None, RpcError.from_reader(reader))
if inner_code == GzipPacked.CONSTRUCTOR_ID:
return RpcResult(msg_id, GzipPacked.from_reader(reader).data, None)
reader.seek(-4)
# This reader.read() will read more than necessary, but it's okay.
# We could make use of MessageContainer's length here, but since
# it's not necessary we don't need to care about it.
return RpcResult(msg_id, reader.read(), None)
def to_dict(self):
return {
'_': 'RpcResult',
'req_msg_id': self.req_msg_id,
'body': self.body,
'error': self.error
}

View File

@@ -0,0 +1,34 @@
from .. import TLObject
class TLMessage(TLObject):
"""
https://core.telegram.org/mtproto/service_messages#simple-container.
Messages are what's ultimately sent to Telegram:
message msg_id:long seqno:int bytes:int body:bytes = Message;
Each message has its own unique identifier, and the body is simply
the serialized request that should be executed on the server, or
the response object from Telegram. Since the body is always a valid
object, it makes sense to store the object and not the bytes to
ease working with them.
There is no need to add serializing logic here since that can be
inlined and is unlikely to change. Thus these are only needed to
encapsulate responses.
"""
SIZE_OVERHEAD = 12
def __init__(self, msg_id, seq_no, obj):
self.msg_id = msg_id
self.seq_no = seq_no
self.obj = obj
def to_dict(self):
return {
'_': 'TLMessage',
'msg_id': self.msg_id,
'seq_no': self.seq_no,
'obj': self.obj
}