diff --git a/telethon/_updates/__init__.py b/telethon/_updates/__init__.py index 42afce1d..f9cc2492 100644 --- a/telethon/_updates/__init__.py +++ b/telethon/_updates/__init__.py @@ -1,3 +1,3 @@ from .entitycache import EntityCache -from .messagebox import MessageBox, GapError +from .messagebox import MessageBox, GapError, PrematureEndReason from .session import SessionState, ChannelState, Entity, EntityType diff --git a/telethon/_updates/messagebox.py b/telethon/_updates/messagebox.py index afb9a1c9..cbb7a9cd 100644 --- a/telethon/_updates/messagebox.py +++ b/telethon/_updates/messagebox.py @@ -19,6 +19,7 @@ to get the difference. import asyncio import datetime import time +from enum import Enum from .session import SessionState, ChannelState from ..tl import types as tl, functions as fn @@ -60,6 +61,11 @@ class GapError(ValueError): return 'GapError()' +class PrematureEndReason(Enum): + TEMPORARY_SERVER_ISSUES = 'tmp' + BANNED = 'ban' + + # Represents the information needed to correctly handle a specific `tl::enums::Update`. class PtsInfo: __slots__ = ('pts', 'pts_count', 'entry') @@ -635,4 +641,19 @@ class MessageBox: return diff.other_updates, diff.users, diff.chats + def end_channel_difference(self, request, reason: PrematureEndReason, chat_hashes): + entry = request.channel.channel_id + + if reason == PrematureEndReason.TEMPORARY_SERVER_ISSUES: + # Temporary issues. End getting difference without updating the pts so we can retry later. + self.possible_gaps.pop(entry, None) + self.end_get_diff(entry) + elif reason == PrematureEndReason.BANNED: + # Banned in the channel. Forget its state since we can no longer fetch updates from it. + self.possible_gaps.pop(entry, None) + self.end_get_diff(entry) + del self.map[entry] + else: + raise RuntimeError('Unknown reason to end channel difference') + # endregion Getting and applying channel difference. diff --git a/telethon/client/updates.py b/telethon/client/updates.py index ebfa8d6a..6d516c39 100644 --- a/telethon/client/updates.py +++ b/telethon/client/updates.py @@ -12,7 +12,7 @@ from collections import deque from .. import events, utils, errors from ..events.common import EventBuilder, EventCommon from ..tl import types, functions -from .._updates import GapError +from .._updates import GapError, PrematureEndReason if typing.TYPE_CHECKING: from .telegramclient import TelegramClient @@ -290,11 +290,27 @@ class UpdateMethods: 'Getting difference for channel updates caused PersistentTimestampOutdated;' ' ending getting difference prematurely until server issues are resolved' ) - diff = types.updates.ChannelDifferenceEmpty( - pts=self._message_box.map[get_diff.channel.channel_id].pts, - final=True, - timeout=30 + self._message_box.end_channel_difference( + get_diff, + PrematureEndReason.TEMPORARY_SERVER_ISSUES, + self._mb_entity_cache ) + continue + except errors.ChannelPrivateError: + # Timeout triggered a get difference, but we have been banned in the channel since then. + # Because we can no longer fetch updates from this channel, we should stop keeping track + # of it entirely. + self._log[__name__].info( + 'Account is now banned in %d so we can no longer fetch updates from it', + get_diff.channel.channel_id + ) + self._message_box.end_channel_difference( + get_diff, + PrematureEndReason.BANNED, + self._mb_entity_cache + ) + continue + updates, users, chats = self._message_box.apply_channel_difference(get_diff, diff, self._mb_entity_cache) updates_to_dispatch.extend(self._preprocess_updates(updates, users, chats)) continue