196 lines
6.0 KiB
Python
196 lines
6.0 KiB
Python
from typing import Optional, Tuple
|
|
from enum import IntEnum
|
|
from ..tl.types import InputPeerUser, InputPeerChat, InputPeerChannel
|
|
|
|
|
|
class SessionState:
|
|
"""
|
|
Stores the information needed to fetch updates and about the current user.
|
|
|
|
* user_id: 64-bit number representing the user identifier.
|
|
* dc_id: 32-bit number relating to the datacenter identifier where the user is.
|
|
* bot: is the logged-in user a bot?
|
|
* pts: 64-bit number holding the state needed to fetch updates.
|
|
* qts: alternative 64-bit number holding the state needed to fetch updates.
|
|
* date: 64-bit number holding the date needed to fetch updates.
|
|
* seq: 64-bit-number holding the sequence number needed to fetch updates.
|
|
* takeout_id: 64-bit-number holding the identifier of the current takeout session.
|
|
|
|
Note that some of the numbers will only use 32 out of the 64 available bits.
|
|
However, for future-proofing reasons, we recommend you pretend they are 64-bit long.
|
|
"""
|
|
__slots__ = ('user_id', 'dc_id', 'bot', 'pts', 'qts', 'date', 'seq', 'takeout_id')
|
|
|
|
def __init__(
|
|
self,
|
|
user_id: int,
|
|
dc_id: int,
|
|
bot: bool,
|
|
pts: int,
|
|
qts: int,
|
|
date: int,
|
|
seq: int,
|
|
takeout_id: Optional[int]
|
|
):
|
|
self.user_id = user_id
|
|
self.dc_id = dc_id
|
|
self.bot = bot
|
|
self.pts = pts
|
|
self.qts = qts
|
|
self.date = date
|
|
self.seq = seq
|
|
self.takeout_id = takeout_id
|
|
|
|
def __repr__(self):
|
|
return repr({k: getattr(self, k) for k in self.__slots__})
|
|
|
|
|
|
class ChannelState:
|
|
"""
|
|
Stores the information needed to fetch updates from a channel.
|
|
|
|
* channel_id: 64-bit number representing the channel identifier.
|
|
* pts: 64-bit number holding the state needed to fetch updates.
|
|
"""
|
|
__slots__ = ('channel_id', 'pts')
|
|
|
|
def __init__(
|
|
self,
|
|
channel_id: int,
|
|
pts: int,
|
|
):
|
|
self.channel_id = channel_id
|
|
self.pts = pts
|
|
|
|
def __repr__(self):
|
|
return repr({k: getattr(self, k) for k in self.__slots__})
|
|
|
|
|
|
class EntityType(IntEnum):
|
|
"""
|
|
You can rely on the type value to be equal to the ASCII character one of:
|
|
|
|
* 'U' (85): this entity belongs to a :tl:`User` who is not a ``bot``.
|
|
* 'B' (66): this entity belongs to a :tl:`User` who is a ``bot``.
|
|
* 'G' (71): this entity belongs to a small group :tl:`Chat`.
|
|
* 'C' (67): this entity belongs to a standard broadcast :tl:`Channel`.
|
|
* 'M' (77): this entity belongs to a megagroup :tl:`Channel`.
|
|
* 'E' (69): this entity belongs to an "enormous" "gigagroup" :tl:`Channel`.
|
|
"""
|
|
USER = ord('U')
|
|
BOT = ord('B')
|
|
GROUP = ord('G')
|
|
CHANNEL = ord('C')
|
|
MEGAGROUP = ord('M')
|
|
GIGAGROUP = ord('E')
|
|
|
|
def canonical(self):
|
|
"""
|
|
Return the canonical version of this type.
|
|
"""
|
|
return _canon_entity_types[self]
|
|
|
|
|
|
_canon_entity_types = {
|
|
EntityType.USER: EntityType.USER,
|
|
EntityType.BOT: EntityType.USER,
|
|
EntityType.GROUP: EntityType.GROUP,
|
|
EntityType.CHANNEL: EntityType.CHANNEL,
|
|
EntityType.MEGAGROUP: EntityType.CHANNEL,
|
|
EntityType.GIGAGROUP: EntityType.CHANNEL,
|
|
}
|
|
|
|
|
|
class Entity:
|
|
"""
|
|
Stores the information needed to use a certain user, chat or channel with the API.
|
|
|
|
* ty: 8-bit number indicating the type of the entity (of type `EntityType`).
|
|
* id: 64-bit number uniquely identifying the entity among those of the same type.
|
|
* hash: 64-bit signed number needed to use this entity with the API.
|
|
|
|
The string representation of this class is considered to be stable, for as long as
|
|
Telegram doesn't need to add more fields to the entities. It can also be converted
|
|
to bytes with ``bytes(entity)``, for a more compact representation.
|
|
"""
|
|
__slots__ = ('ty', 'id', 'hash')
|
|
|
|
def __init__(
|
|
self,
|
|
ty: EntityType,
|
|
id: int,
|
|
hash: int
|
|
):
|
|
self.ty = ty
|
|
self.id = id
|
|
self.hash = hash
|
|
|
|
@property
|
|
def is_user(self):
|
|
"""
|
|
``True`` if the entity is either a user or a bot.
|
|
"""
|
|
return self.ty in (EntityType.USER, EntityType.BOT)
|
|
|
|
@property
|
|
def is_group(self):
|
|
"""
|
|
``True`` if the entity is a small group chat or `megagroup`_.
|
|
|
|
.. _megagroup: https://telegram.org/blog/supergroups5k
|
|
"""
|
|
return self.ty in (EntityType.GROUP, EntityType.MEGAGROUP)
|
|
|
|
@property
|
|
def is_broadcast(self):
|
|
"""
|
|
``True`` if the entity is a broadcast channel or `broadcast group`_.
|
|
|
|
.. _broadcast group: https://telegram.org/blog/autodelete-inv2#groups-with-unlimited-members
|
|
"""
|
|
return self.ty in (EntityType.CHANNEL, EntityType.GIGAGROUP)
|
|
|
|
@classmethod
|
|
def from_str(cls, string: str):
|
|
"""
|
|
Convert the string into an `Entity`.
|
|
"""
|
|
try:
|
|
ty, id, hash = string.split('.')
|
|
ty, id, hash = ord(ty), int(id), int(hash)
|
|
except AttributeError:
|
|
raise TypeError(f'expected str, got {string!r}') from None
|
|
except (TypeError, ValueError):
|
|
raise ValueError(f'malformed entity str (must be T.id.hash), got {string!r}') from None
|
|
|
|
return cls(EntityType(ty), id, hash)
|
|
|
|
@classmethod
|
|
def from_bytes(cls, blob):
|
|
"""
|
|
Convert the bytes into an `Entity`.
|
|
"""
|
|
try:
|
|
ty, id, hash = struct.unpack('<Bqq', blob)
|
|
except struct.error:
|
|
raise ValueError(f'malformed entity data, got {string!r}') from None
|
|
|
|
return cls(EntityType(ty), id, hash)
|
|
|
|
def __str__(self):
|
|
return f'{chr(self.ty)}.{self.id}.{self.hash}'
|
|
|
|
def __bytes__(self):
|
|
return struct.pack('<Bqq', self.ty, self.id, self.hash)
|
|
|
|
def _as_input_peer(self):
|
|
if self.is_user:
|
|
return InputPeerUser(self.id, self.hash)
|
|
elif self.ty == EntityType.GROUP:
|
|
return InputPeerChat(self.id)
|
|
else:
|
|
return InputPeerChannel(self.id, self.hash)
|
|
|
|
def __repr__(self):
|
|
return repr({k: getattr(self, k) for k in self.__slots__})
|