You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-12-23 22:42:10 +03:00
Set the back-pagination token before raising Room.timelineReset
This fixes another race condition on gappy syncs, wherein we weren't back-paginating back from the start of the gappy sync.
This commit is contained in:
@@ -168,9 +168,11 @@ Room.prototype.getLiveTimeline = function() {
|
||||
*
|
||||
* <p>This is used when /sync returns a 'limited' timeline.
|
||||
*
|
||||
* @param {string=} backPaginationToken token for back-paginating the new timeline
|
||||
*
|
||||
* @fires module:client~MatrixClient#event:"Room.timelineReset"
|
||||
*/
|
||||
Room.prototype.resetLiveTimeline = function() {
|
||||
Room.prototype.resetLiveTimeline = function(backPaginationToken) {
|
||||
var newTimeline;
|
||||
|
||||
if (!this._timelineSupport) {
|
||||
@@ -194,6 +196,11 @@ Room.prototype.resetLiveTimeline = function() {
|
||||
}
|
||||
newTimeline.initialiseState(events);
|
||||
|
||||
// make sure we set the pagination token before firing timelineReset,
|
||||
// otherwise clients which start back-paginating will fail, and then get
|
||||
// stuck without realising that they *can* back-paginate.
|
||||
newTimeline.setPaginationToken(backPaginationToken, EventTimeline.BACKWARDS);
|
||||
|
||||
this._liveTimeline = newTimeline;
|
||||
this._fixUpLegacyTimelineFields();
|
||||
this.emit("Room.timelineReset", this);
|
||||
|
||||
51
lib/sync.js
51
lib/sync.js
@@ -28,6 +28,7 @@ var User = require("./models/user");
|
||||
var Room = require("./models/room");
|
||||
var utils = require("./utils");
|
||||
var Filter = require("./filter");
|
||||
var EventTimeline = require("./models/event-timeline");
|
||||
|
||||
var DEBUG = true;
|
||||
|
||||
@@ -175,12 +176,14 @@ SyncApi.prototype.syncLeftRooms = function() {
|
||||
var timelineEvents =
|
||||
self._mapSyncEventsFormat(leaveObj.timeline, room);
|
||||
var stateEvents = self._mapSyncEventsFormat(leaveObj.state, room);
|
||||
var paginationToken = (
|
||||
leaveObj.timeline.limited ? leaveObj.timeline.prev_batch : null
|
||||
);
|
||||
self._processRoomEvents(
|
||||
room, stateEvents, timelineEvents, paginationToken
|
||||
);
|
||||
|
||||
// set the back-pagination token. Do this *before* adding any
|
||||
// events so that clients can start back-paginating.
|
||||
room.getLiveTimeline().setPaginationToken(leaveObj.timeline.prev_batch,
|
||||
EventTimeline.BACKWARDS);
|
||||
|
||||
self._processRoomEvents(room, stateEvents, timelineEvents);
|
||||
|
||||
room.recalculate(client.credentials.userId);
|
||||
client.store.storeRoom(room);
|
||||
client.emit("Room", room);
|
||||
@@ -593,9 +596,14 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
|
||||
joinObj.timeline = joinObj.timeline || {};
|
||||
|
||||
var limited = false;
|
||||
if (joinObj.timeline.limited) {
|
||||
limited = true;
|
||||
if (joinObj.isBrandNewRoom) {
|
||||
// set the back-pagination token. Do this *before* adding any
|
||||
// events so that clients can start back-paginating.
|
||||
room.getLiveTimeline().setPaginationToken(
|
||||
joinObj.timeline.prev_batch, EventTimeline.BACKWARDS);
|
||||
}
|
||||
else if (joinObj.timeline.limited) {
|
||||
var limited = true;
|
||||
|
||||
// we've got a limited sync, so we *probably* have a gap in the
|
||||
// timeline, so should reset. But we might have been peeking or
|
||||
@@ -638,21 +646,12 @@ SyncApi.prototype._processSyncResponse = function(syncToken, data) {
|
||||
// timeline.
|
||||
room.currentState.paginationToken = syncToken;
|
||||
self._deregisterStateListeners(room);
|
||||
room.resetLiveTimeline();
|
||||
room.resetLiveTimeline(joinObj.timeline.prev_batch);
|
||||
self._registerStateListeners(room);
|
||||
}
|
||||
}
|
||||
|
||||
// we want to set a new pagination token if this is the first time
|
||||
// we've made this room or if we're nuking the timeline
|
||||
var paginationToken = null;
|
||||
if (joinObj.isBrandNewRoom || limited) {
|
||||
paginationToken = joinObj.timeline.prev_batch;
|
||||
}
|
||||
|
||||
self._processRoomEvents(
|
||||
room, stateEvents, timelineEvents, paginationToken
|
||||
);
|
||||
self._processRoomEvents(room, stateEvents, timelineEvents);
|
||||
|
||||
// XXX: should we be adding ephemeralEvents to the timeline?
|
||||
// It feels like that for symmetry with room.addAccountData()
|
||||
@@ -873,11 +872,9 @@ SyncApi.prototype._resolveInvites = function(room) {
|
||||
* at the *START* of the timeline list if it is supplied.
|
||||
* @param {?MatrixEvent[]} timelineEventList A list of timeline events. Lower index
|
||||
* is earlier in time. Higher index is later.
|
||||
* @param {string=} paginationToken pagination token for going backwards in time.
|
||||
* This should only be set if this is a new room/timeline.
|
||||
*/
|
||||
SyncApi.prototype._processRoomEvents = function(room, stateEventList,
|
||||
timelineEventList, paginationToken) {
|
||||
timelineEventList) {
|
||||
timelineEventList = timelineEventList || [];
|
||||
var client = this.client;
|
||||
// "old" and "current" state are the same initially; they
|
||||
@@ -891,14 +888,6 @@ SyncApi.prototype._processRoomEvents = function(room, stateEventList,
|
||||
);
|
||||
var stateEvents = stateEventList;
|
||||
|
||||
// Set the pagination token BEFORE adding events to the timeline: it's not
|
||||
// unreasonable for clients to call scrollback() in response to Room.timeline
|
||||
// events which addEventsToTimeline will emit-- we want to make sure they use
|
||||
// the right token if and when they do.
|
||||
if (paginationToken) {
|
||||
room.oldState.paginationToken = paginationToken;
|
||||
}
|
||||
|
||||
// set the state of the room to as it was before the timeline executes
|
||||
//
|
||||
// XXX: what if we've already seen (some of) the events in the timeline,
|
||||
|
||||
@@ -3,6 +3,7 @@ var sdk = require("../..");
|
||||
var HttpBackend = require("../mock-request");
|
||||
var utils = require("../test-utils");
|
||||
var MatrixEvent = sdk.MatrixEvent;
|
||||
var EventTimeline = sdk.EventTimeline;
|
||||
|
||||
describe("MatrixClient syncing", function() {
|
||||
var baseUrl = "http://localhost.or.something";
|
||||
@@ -548,5 +549,46 @@ describe("MatrixClient syncing", function() {
|
||||
return httpBackend.flush();
|
||||
}).catch(utils.failTest);
|
||||
});
|
||||
|
||||
it("should set the back-pagination token on left rooms", function(done) {
|
||||
var syncData = {
|
||||
next_batch: "batch_token",
|
||||
rooms: {
|
||||
leave: {}
|
||||
},
|
||||
};
|
||||
|
||||
syncData.rooms.leave[roomTwo] = {
|
||||
timeline: {
|
||||
events: [
|
||||
utils.mkMessage({
|
||||
room: roomTwo, user: otherUserId, msg: "hello"
|
||||
}),
|
||||
],
|
||||
prev_batch: "pagTok",
|
||||
},
|
||||
};
|
||||
|
||||
httpBackend.when("POST", "/filter").respond(200, {
|
||||
filter_id: "another_id"
|
||||
});
|
||||
|
||||
httpBackend.when("GET", "/sync").respond(200, syncData);
|
||||
|
||||
client.syncLeftRooms().then(function() {
|
||||
var room = client.getRoom(roomTwo);
|
||||
var tok = room.getLiveTimeline().getPaginationToken(
|
||||
EventTimeline.BACKWARDS);
|
||||
|
||||
expect(tok).toEqual("pagTok");
|
||||
done();
|
||||
}).catch(utils.failTest).done();
|
||||
|
||||
// first flush the filter request; this will make syncLeftRooms
|
||||
// make its /sync call
|
||||
httpBackend.flush("/filter").then(function() {
|
||||
return httpBackend.flush();
|
||||
}).catch(utils.failTest);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -376,13 +376,21 @@ describe("Room", function() {
|
||||
newLiveTimeline.getState(EventTimeline.FORWARDS));
|
||||
});
|
||||
|
||||
it("should emit Room.timelineReset event", function() {
|
||||
it("should emit Room.timelineReset event and set the correct " +
|
||||
"pagination token", function() {
|
||||
var callCount = 0;
|
||||
room.on("Room.timelineReset", function(emitRoom) {
|
||||
callCount += 1;
|
||||
expect(emitRoom).toEqual(room);
|
||||
|
||||
// make sure that the pagination token has been set before the
|
||||
// event is emitted.
|
||||
var tok = emitRoom.getLiveTimeline()
|
||||
.getPaginationToken(EventTimeline.BACKWARDS);
|
||||
|
||||
expect(tok).toEqual("pagToken");
|
||||
});
|
||||
room.resetLiveTimeline();
|
||||
room.resetLiveTimeline("pagToken");
|
||||
expect(callCount).toEqual(1);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user