1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-12-01 04:43:29 +03:00

make /notification pagination actually work

This commit is contained in:
Matthew Hodgson
2016-09-09 02:08:39 +01:00
parent f959e1a134
commit 2e4c362ccd
3 changed files with 66 additions and 11 deletions

View File

@@ -1793,6 +1793,38 @@ MatrixClient.prototype.paginateEventTimeline = function(eventTimeline, opts) {
return promise;
};
/**
* Reset the notifTimelineSet entirely, paginating in some historical notifs as
* a starting point for subsequent pagination.
*/
MatrixClient.prototype.resetNotifTimelineSet = function() {
if (!this._notifTimelineSet) {
return;
}
// FIXME: This thing is a total hack, and results in duplicate events being
// added to the timeline both from /sync and /notifications, and lots of
// slow and wasteful processing and pagination. The correct solution is to
// extend /messages or /search or something to filter on notifications.
// use the fictitious token 'end'. in practice we would ideally give it
// the oldest backwards pagination token from /sync, but /sync doesn't
// know about /notifications, so we have no choice but to start paginating
// from the current point in time. This may well overlap with historical
// notifs which are then inserted into the timeline by /sync responses.
this._notifTimelineSet.resetLiveTimeline('end', true);
// we could try to paginate a single event at this point in order to get
// a more valid pagination token, but it just ends up with an out of order
// timeline. given what a mess this is and given we're going to have duplicate
// events anyway, just leave it with the dummy token for now.
/*
this.paginateNotifTimeline(this._notifTimelineSet.getLiveTimeline(), {
backwards: true,
limit: 1
});
*/
};
/**
* Take an EventTimeline, and backfill results from the notifications API.
@@ -1853,11 +1885,14 @@ MatrixClient.prototype.paginateNotifTimeline = function(eventTimeline, opts) {
for (var i = 0; i < res.notifications.length; i++) {
var notification = res.notifications[i];
var event = self.getEventMapper()(notification.event);
event.setPushActions(notification.actions);
event.setPushActions(
PushProcessor.actionListToActionsObject(notification.actions)
);
event.event.room_id = notification.room_id; // XXX: gutwrenching
matrixEvents[i] = event;
}
eventTimeline.getEventTimelineSet()
eventTimeline.getTimelineSet()
.addEventsToTimeline(matrixEvents, backwards, eventTimeline, token);
// if we've hit the end of the timeline, we need to stop trying to

View File

@@ -149,11 +149,12 @@ EventTimelineSet.prototype.replaceEventId = function(oldEventId, newEventId) {
* <p>This is used when /sync returns a 'limited' timeline.
*
* @param {string=} backPaginationToken token for back-paginating the new timeline
* @param {?bool} flush Whether to flush the non-live timelines too.
*/
EventTimelineSet.prototype.resetLiveTimeline = function(backPaginationToken) {
EventTimelineSet.prototype.resetLiveTimeline = function(backPaginationToken, flush) {
var newTimeline;
if (!this._timelineSupport) {
if (!this._timelineSupport || flush) {
// if timeline support is disabled, forget about the old timelines
newTimeline = new EventTimeline(this);
this._timelines = [newTimeline];

View File

@@ -72,6 +72,7 @@ function SyncApi(client, opts) {
this._running = false;
this._keepAliveTimer = null;
this._connectionReturnedDefer = null;
this._notifEvents = []; // accumulator of sync events in the current sync response
}
/**
@@ -392,6 +393,16 @@ SyncApi.prototype.sync = function() {
client.getOrCreateFilter(
getFilterName(client.credentials.userId), filter
).done(function(filterId) {
// prepare the notif timeline for pagination before we receive
// sync responses. Technically there are two small races here:
// 1: the reset will execute async and may race with the /sync.
// 2: the reset may return before the sync, and the room may go
// so fast that in the gap before the sync returns we may miss some
// notifs. This is incredibly unlikely however.
// The right solution would be to tie /sync pagination tokens into
// notifications.
client.resetNotifTimelineSet();
self._sync({ filterId: filterId });
}, function(err) {
self._startKeepAlives().done(function() {
@@ -655,7 +666,7 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
}
}
this.notifEvents = [];
this._notifEvents = [];
// Handle invites
inviteRooms.forEach(function(inviteObj) {
@@ -742,6 +753,12 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
room.currentState.paginationToken = syncToken;
self._deregisterStateListeners(room);
room.resetLiveTimeline(joinObj.timeline.prev_batch);
// XXX: for now we have to assume any gap in any timeline is
// reason to stop incrementally tracking notifications and
// reset the timeline.
client.resetNotifTimelineSet();
self._registerStateListeners(room);
}
}
@@ -792,11 +809,11 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
});
// update the notification timeline, if appropriate
if (this.notifEvents.length) {
this.notifEvents.sort(function(a, b) {
if (this._notifEvents.length) {
this._notifEvents.sort(function(a, b) {
return a.getTs() - b.getTs();
});
this.notifEvents.forEach(function(event) {
this._notifEvents.forEach(function(event) {
client.getNotifTimelineSet().addLiveEvent(event);
});
}
@@ -988,12 +1005,14 @@ SyncApi.prototype._processRoomEvents = function(room, stateEventList,
// may make notifications appear which should have the right name.
room.recalculate(this.client.credentials.userId);
// gather our notifications into this.notifEvents
// gather our notifications into this._notifEvents
if (client.getNotifTimelineSet()) {
for (var i = 0; i < timelineEventList.length; i++) {
var pushActions = client.getPushActionsForEvent(timelineEventList[i]);
if (pushActions && pushActions.notify) {
this.notifEvents.push(timelineEventList[i]);
if (pushActions && pushActions.notify &&
pushActions.tweaks && pushActions.tweaks.highlight)
{
this._notifEvents.push(timelineEventList[i]);
}
}
}