mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-08 12:59:46 +00:00
Refactor code to fetch missing entities once again
This is another attempt at reducing CPU usage similar to:
1b6b4a57d9
In addition it simplifies some of the code and opens up new
ideas for the state cache as well.
This commit is contained in:
@@ -1,7 +1,57 @@
|
||||
import itertools
|
||||
|
||||
from . import utils
|
||||
from .tl import types
|
||||
|
||||
# Which updates have the following fields?
|
||||
_has_user_id = []
|
||||
_has_chat_id = []
|
||||
_has_channel_id = []
|
||||
_has_peer = []
|
||||
_has_dialog_peer = []
|
||||
_has_message = []
|
||||
|
||||
# Note: We don't bother checking for some rare:
|
||||
# * `UpdateChatParticipantAdd.inviter_id` integer.
|
||||
# * `UpdateNotifySettings.peer` dialog peer.
|
||||
# * `UpdatePinnedDialogs.order` list of dialog peers.
|
||||
# * `UpdateReadMessagesContents.messages` list of messages.
|
||||
# * `UpdateChatParticipants.participants` list of participants.
|
||||
#
|
||||
# There are also some uninteresting `update.message` of type string.
|
||||
|
||||
|
||||
def _fill():
|
||||
for name in dir(types):
|
||||
update = getattr(types, name)
|
||||
if getattr(update, 'SUBCLASS_OF_ID', None) == 0x9f89304e:
|
||||
cid = update.CONSTRUCTOR_ID
|
||||
doc = update.__init__.__doc__ or ''
|
||||
if ':param int user_id:' in doc:
|
||||
_has_user_id.append(cid)
|
||||
if ':param int chat_id:' in doc:
|
||||
_has_chat_id.append(cid)
|
||||
if ':param int channel_id:' in doc:
|
||||
_has_channel_id.append(cid)
|
||||
if ':param TypePeer peer:' in doc:
|
||||
_has_peer.append(cid)
|
||||
if ':param TypeDialogPeer peer:' in doc:
|
||||
_has_dialog_peer.append(cid)
|
||||
if ':param TypeMessage message:' in doc:
|
||||
_has_message.append(cid)
|
||||
|
||||
# Future-proof check: if the documentation format ever changes
|
||||
# then we won't be able to pick the update types we are interested
|
||||
# in, so we must make sure we have at least an update for each field
|
||||
# which likely means we are doing it right.
|
||||
if not all((_has_user_id, _has_chat_id, _has_channel_id,
|
||||
_has_peer, _has_dialog_peer)):
|
||||
raise RuntimeError('FIXME: Did the generated docs or updates change?')
|
||||
|
||||
|
||||
# We use a function to avoid cluttering the globals (with name/update/cid/doc)
|
||||
_fill()
|
||||
|
||||
|
||||
class EntityCache:
|
||||
"""
|
||||
@@ -46,3 +96,51 @@ class EntityCache:
|
||||
return result
|
||||
|
||||
raise KeyError('No cached entity for the given key')
|
||||
|
||||
def ensure_cached(
|
||||
self,
|
||||
update,
|
||||
has_user_id=frozenset(_has_user_id),
|
||||
has_channel_id=frozenset(_has_channel_id),
|
||||
has_peer=frozenset(_has_peer + _has_dialog_peer),
|
||||
has_message=frozenset(_has_message)
|
||||
):
|
||||
"""
|
||||
Ensures that all the relevant entities in the given update are cached.
|
||||
"""
|
||||
# This method is called pretty often and we want it to have the lowest
|
||||
# overhead possible. For that, we avoid `isinstance` and constantly
|
||||
# getting attributes out of `types.` by "caching" the constructor IDs
|
||||
# in sets inside the arguments, and using local variables.
|
||||
dct = self.__dict__
|
||||
cid = update.CONSTRUCTOR_ID
|
||||
if cid in has_user_id and \
|
||||
update.user_id not in dct:
|
||||
return False
|
||||
|
||||
if cid in _has_chat_id and \
|
||||
utils.get_peer_id(types.PeerChat(update.chat_id)) not in dct:
|
||||
return False
|
||||
|
||||
if cid in has_channel_id and \
|
||||
utils.get_peer_id(types.PeerChannel(update.channel_id)) not in dct:
|
||||
return False
|
||||
|
||||
if cid in has_peer and \
|
||||
utils.get_peer_id(update.peer) not in dct:
|
||||
return False
|
||||
|
||||
if cid in has_message:
|
||||
x = update.message
|
||||
y = getattr(x, 'to_id', None) # handle MessageEmpty
|
||||
if y and utils.get_peer_id(y) not in dct:
|
||||
return False
|
||||
|
||||
y = getattr(x, 'from_id', None)
|
||||
if y and y not in dct:
|
||||
return False
|
||||
|
||||
# We don't quite worry about entities anywhere else.
|
||||
# This is enough.
|
||||
|
||||
return True
|
||||
|
Reference in New Issue
Block a user