From b2809e0b576ff9a1fa7355e2fca0414b09f82474 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Wed, 23 Apr 2025 18:25:22 +0200 Subject: [PATCH 1/2] Apply seq if all updates were applied Instead of only checking if *any* update *with pts* was applied. Should fix #4602. --- telethon/_updates/messagebox.py | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/telethon/_updates/messagebox.py b/telethon/_updates/messagebox.py index f8d4ae96..88c1e713 100644 --- a/telethon/_updates/messagebox.py +++ b/telethon/_updates/messagebox.py @@ -460,30 +460,14 @@ class MessageBox: return pts.pts - pts.pts_count if pts else 0 reset_deadlines = set() # temporary buffer - any_pts_applied = [False] # using a list to pass "by reference" result.extend(filter(None, ( - self.apply_pts_info(u, reset_deadlines=reset_deadlines, any_pts_applied=any_pts_applied) + self.apply_pts_info(u, reset_deadlines=reset_deadlines) # Telegram can send updates out of order (e.g. ReadChannelInbox first # and then NewChannelMessage, both with the same pts, but the count is # 0 and 1 respectively), so we sort them first. for u in sorted(updates, key=_sort_gaps)))) - # > If the updates were applied, local *Updates* state must be updated - # > with `seq` (unless it's 0) and `date` from the constructor. - # - # By "were applied", we assume it means "some other pts was applied". - # Updates which can be applied in any order, such as `UpdateChat`, - # should not cause `seq` to be updated (or upcoming updates such as - # `UpdateChatParticipant` could be missed). - if any_pts_applied[0]: - if __debug__: - self._trace('Updating seq as local pts was updated too') - if date != epoch(): - self.date = date - if seq != NO_SEQ: - self.seq = seq - self.reset_deadlines(reset_deadlines, next_updates_deadline()) if self.possible_gaps: @@ -510,6 +494,16 @@ class MessageBox: real_result.extend(u for u in result if not u._self_outgoing) + if result and not self.possible_gaps: + # > If the updates were applied, local *Updates* state must be updated + # > with `seq` (unless it's 0) and `date` from the constructor. + if __debug__: + self._trace('Updating seq as all updates were applied') + if date != epoch(): + self.date = date + if seq != NO_SEQ: + self.seq = seq + return (users, chats) # Tries to apply the input update if its `PtsInfo` follows the correct order. @@ -522,7 +516,6 @@ class MessageBox: update, *, reset_deadlines, - any_pts_applied=[True], # mutable default is fine as it's write-only ): # This update means we need to call getChannelDifference to get the updates from the channel if isinstance(update, tl.UpdateChannelTooLong): @@ -574,7 +567,6 @@ class MessageBox: return None else: # Apply - any_pts_applied[0] = True if __debug__: self._trace('Applying update pts since local pts %r = %r: %s', local_pts, pts, update) From 04922fee3cebccd1bf3b99b367db119f7e129680 Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Wed, 23 Apr 2025 19:21:36 +0200 Subject: [PATCH 2/2] Stop re-saving input peers on disconnect This was overwriting actual information on the cache. --- telethon/_updates/entitycache.py | 3 --- telethon/client/telegrambaseclient.py | 8 ++------ 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/telethon/_updates/entitycache.py b/telethon/_updates/entitycache.py index fd56c3e1..6973599e 100644 --- a/telethon/_updates/entitycache.py +++ b/telethon/_updates/entitycache.py @@ -49,9 +49,6 @@ class EntityCache: if getattr(c, 'access_hash', None) and not getattr(c, 'min', None) ) - def get_all_entities(self): - return [Entity(ty, id, hash) for id, (hash, ty) in self.hash_map.items()] - def put(self, entity): self.hash_map[entity.id] = (entity.hash, entity.ty) diff --git a/telethon/client/telegrambaseclient.py b/telethon/client/telegrambaseclient.py index 95c28532..77768b78 100644 --- a/telethon/client/telegrambaseclient.py +++ b/telethon/client/telegrambaseclient.py @@ -687,14 +687,10 @@ class TelegramBaseClient(abc.ABC): connection._proxy = proxy def _save_states_and_entities(self: 'TelegramClient'): - entities = self._mb_entity_cache.get_all_entities() - - # Piggy-back on an arbitrary TL type with users and chats so the session can understand to read the entities. - # It doesn't matter if we put users in the list of chats. - self.session.process_entities(types.contacts.ResolvedPeer(None, [e._as_input_peer() for e in entities], [])) - # As a hack to not need to change the session files, save ourselves with ``id=0`` and ``access_hash`` of our ``id``. # This way it is possible to determine our own ID by querying for 0. However, whether we're a bot is not saved. + # Piggy-back on an arbitrary TL type with users and chats so the session can understand to read the entities. + # It doesn't matter if we put users in the list of chats. if self._mb_entity_cache.self_id: self.session.process_entities(types.contacts.ResolvedPeer(None, [types.InputPeerUser(0, self._mb_entity_cache.self_id)], []))