diff --git a/synapse/handlers/sync.py b/synapse/handlers/sync.py index fef81f5f9b..b47fefc13f 100644 --- a/synapse/handlers/sync.py +++ b/synapse/handlers/sync.py @@ -130,6 +130,7 @@ class SyncResult(collections.namedtuple("SyncResult", [ "joined", # JoinedSyncResult for each joined room. "invited", # InvitedSyncResult for each invited room. "archived", # ArchivedSyncResult for each archived room. + "pagination_info", ])): __slots__ = [] @@ -549,7 +550,8 @@ class SyncHandler(object): next_batch=SyncNextBatchToken( stream_token=sync_result_builder.now_token, pagination_state=sync_result_builder.pagination_state, - ) + ), + pagination_info=sync_result_builder.pagination_info, )) @defer.inlineCallbacks @@ -707,13 +709,16 @@ class SyncHandler(object): if sync_config.pagination_config: pagination_config = sync_config.pagination_config + old_pagination_value = 0 elif sync_result_builder.pagination_state: pagination_config = SyncPaginationConfig( order=sync_result_builder.pagination_state.order, limit=sync_result_builder.pagination_state.limit, ) + old_pagination_value = sync_result_builder.pagination_state.value else: pagination_config = None + old_pagination_value = 0 include_map = extras.get("peek", {}) if extras else {} @@ -743,17 +748,20 @@ class SyncHandler(object): room_map = yield self._get_room_timestamps_at_token( room_ids, sync_result_builder.now_token, sync_config, - pagination_limit + extra_limit, + pagination_limit + extra_limit + 1, ) + limited = False if room_map: sorted_list = sorted( room_map.items(), key=lambda item: -item[1] - )[:pagination_limit + extra_limit] + ) - if sorted_list[pagination_limit:]: - new_room_ids = set(r[0] for r in sorted_list[pagination_limit:]) + cutoff_list = sorted_list[:pagination_limit + extra_limit] + + if cutoff_list[pagination_limit:]: + new_room_ids = set(r[0] for r in cutoff_list[pagination_limit:]) for r in room_entries: if r.room_id in new_room_ids: r.full_state = True @@ -762,14 +770,21 @@ class SyncHandler(object): r.upto_token = now_token r.events = None - _, bottom_ts = sorted_list[-1] + _, bottom_ts = cutoff_list[-1] value = bottom_ts + limited = any( + old_pagination_value < r[1] < value + for r in sorted_list[pagination_limit + extra_limit:] + ) + sync_result_builder.pagination_state = SyncPaginationState( order=pagination_config.order, value=value, limit=pagination_limit + extra_limit, ) + sync_result_builder.pagination_info["limited"] = limited + if len(room_map) == len(room_entries): sync_result_builder.pagination_state = None @@ -1257,6 +1272,7 @@ class SyncResultBuilder(object): __slots__ = ( "sync_config", "full_state", "batch_token", "since_token", "pagination_state", "now_token", "presence", "account_data", "joined", "invited", "archived", + "pagination_info", ) def __init__(self, sync_config, full_state, batch_token, now_token): @@ -1280,6 +1296,8 @@ class SyncResultBuilder(object): self.invited = [] self.archived = [] + self.pagination_info = {} + class RoomSyncResultBuilder(object): """Stores information needed to create either a `JoinedSyncResult` or diff --git a/synapse/rest/client/v2_alpha/sync.py b/synapse/rest/client/v2_alpha/sync.py index da94220f1e..24587cbc61 100644 --- a/synapse/rest/client/v2_alpha/sync.py +++ b/synapse/rest/client/v2_alpha/sync.py @@ -286,6 +286,9 @@ class SyncRestServlet(RestServlet): "next_batch": sync_result.next_batch.to_string(), } + if sync_result.pagination_info: + response_content["pagination_info"] = sync_result.pagination_info + defer.returnValue((200, response_content)) def encode_presence(self, events, time_now):