Create RpcResult class and generalise core special cases

This results in a cleaner MTProtoSender, which now can always
read a TLObject with a guaranteed item, if the message is OK.
This commit is contained in:
Lonami Exo
2018-06-09 13:11:49 +02:00
parent 1e66cea9b7
commit f7e8907c6f
11 changed files with 132 additions and 84 deletions

View File

@@ -1,4 +1 @@
from .tlobject import TLObject
from .gzip_packed import GzipPacked
from .tl_message import TLMessage
from .message_container import MessageContainer

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

@@ -1,7 +1,7 @@
import gzip
import struct
from . import TLObject
from .. import TLObject
class GzipPacked(TLObject):
@@ -36,3 +36,7 @@ class GzipPacked(TLObject):
def read(reader):
assert reader.read_int(signed=False) == GzipPacked.CONSTRUCTOR_ID
return gzip.decompress(reader.tgread_bytes())
@classmethod
def from_reader(cls, reader):
return GzipPacked(gzip.decompress(reader.tgread_bytes()))

View File

@@ -1,7 +1,7 @@
import struct
from . import TLObject
from .tl_message import TLMessage
from ..tlobject import TLObject
from .tlmessage import TLMessage
class MessageContainer(TLObject):
@@ -42,3 +42,12 @@ class MessageContainer(TLObject):
def stringify(self):
return TLObject.pretty_format(self, indent=0)
@classmethod
def from_reader(cls, reader):
# This assumes that .read_* calls are done in the order they appear
return MessageContainer([TLMessage(
msg_id=reader.read_long(),
seq_no=reader.read_int(),
body=reader.read(reader.read_int())
) for _ in range(reader.read_int())])

View File

@@ -0,0 +1,23 @@
from .gzippacked import GzipPacked
from ..types import RpcError
class RpcResult:
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)
return RpcResult(msg_id, reader.read(), None)

View File

@@ -1,8 +1,9 @@
import asyncio
import struct
from . import TLObject, GzipPacked
from ..tl.functions import InvokeAfterMsgRequest
from .gzippacked import GzipPacked
from .. import TLObject
from ..functions import InvokeAfterMsgRequest
class TLMessage(TLObject):