1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-28 05:03:59 +03:00

Fire a 'Room.timelineReset' event when we get a gappy sync

We need to reset things at the UI level when we get a gappy sync, so give the
clients something to listen for.

Also add a bunch of tests for that bit of code.
This commit is contained in:
Richard van der Hoff
2016-02-25 13:15:18 +00:00
parent 46912431cc
commit abf908b14f
4 changed files with 141 additions and 18 deletions

View File

@@ -143,12 +143,14 @@ function Room(roomId, opts) {
this._notificationCounts = {};
this._liveTimeline = new EventTimeline(this.roomId);
this._fixUpLegacyTimelineFields();
// just a list - *not* ordered.
this._timelines = [];
this._timelines = [this._liveTimeline];
this._eventIdToTimeline = {};
this._timelineSupport = Boolean(opts.timelineSupport);
this.resetLiveTimeline();
}
utils.inherits(Room, EventEmitter);
@@ -165,6 +167,8 @@ Room.prototype.getLiveTimeline = function() {
* Reset the live timeline, and start a new one.
*
* <p>This is used when /sync returns a 'limited' timeline.
*
* @fires module:client~MatrixClient#event:"Room.timelineReset"
*/
Room.prototype.resetLiveTimeline = function() {
var newTimeline;
@@ -178,10 +182,6 @@ Room.prototype.resetLiveTimeline = function() {
newTimeline = this.addTimeline();
}
if (this._liveTimeline) {
// we have an existing timeline. This will always be true, except when
// this method is called by our own constructor.
// initialise the state in the new timeline from our last known state
var evMap = this._liveTimeline.getState(EventTimeline.FORWARDS).events;
var events = [];
@@ -193,9 +193,18 @@ Room.prototype.resetLiveTimeline = function() {
}
}
newTimeline.initialiseState(events);
}
this._liveTimeline = newTimeline;
this._liveTimeline = newTimeline;
this._fixUpLegacyTimelineFields();
this.emit("Room.timelineReset", this);
};
/**
* Fix up this.timeline, this.oldState and this.currentState
*
* @private
*/
Room.prototype._fixUpLegacyTimelineFields = function() {
// maintain this.timeline as a reference to the live timeline,
// and this.oldState and this.currentState as references to the
// state at the start and end of that timeline. These are more
@@ -1218,6 +1227,18 @@ module.exports = Room;
* });
*/
/**
* Fires wheneer the live timeline in a room is reset.
*
* When we get a 'limited' sync (for example, after a network outage), we reset
* the live timeline to be empty before adding the recent events to the new
* timeline. This event is fired after the timeline is reset, and before the
* new events are added.
*
* @event module:clinet~MatrixClient#"Room.timelineReset"
* @param {Room} room The room whose live timeline was reset.
*/
/**
* Fires when an event we had previously received is redacted.
*

View File

@@ -84,7 +84,8 @@ SyncApi.prototype.createRoom = function(roomId) {
timelineSupport: client.timelineSupport,
});
reEmit(client, room, ["Room.name", "Room.timeline", "Room.redaction",
"Room.receipt", "Room.tags"]);
"Room.receipt", "Room.tags",
"Room.timelineReset"]);
this._registerStateListeners(room);
return room;
};

View File

@@ -512,5 +512,31 @@ describe("MatrixClient room timelines", function() {
});
httpBackend.flush("/sync", 1);
});
it("should emit a 'Room.timelineReset' event", function(done) {
var eventData = [
utils.mkMessage({user: userId, room: roomId}),
];
setNextSyncData(eventData);
NEXT_SYNC_DATA.rooms.join[roomId].timeline.limited = true;
client.on("sync", function(state) {
if (state !== "PREPARED") { return; }
var room = client.getRoom(roomId);
var emitCount = 0;
client.on("Room.timelineReset", function(emitRoom) {
expect(emitRoom).toEqual(room);
emitCount++;
});
httpBackend.flush("/messages", 1);
httpBackend.flush("/sync", 1).done(function() {
expect(emitCount).toEqual(1);
done();
});
});
httpBackend.flush("/sync", 1);
});
});
});

View File

@@ -4,6 +4,7 @@ var Room = sdk.Room;
var RoomState = sdk.RoomState;
var MatrixEvent = sdk.MatrixEvent;
var EventStatus = sdk.EventStatus;
var EventTimeline = sdk.EventTimeline;
var utils = require("../test-utils");
describe("Room", function() {
@@ -329,6 +330,80 @@ describe("Room", function() {
});
});
var resetTimelineTests = function(timelineSupport) {
var events = [
utils.mkMessage({
room: roomId, user: userA, msg: "A message", event: true
}),
utils.mkEvent({
type: "m.room.name", room: roomId, user: userA, event: true,
content: { name: "New Room Name" }
}),
utils.mkEvent({
type: "m.room.name", room: roomId, user: userA, event: true,
content: { name: "Another New Name" }
}),
];
beforeEach(function() {
room = new Room(roomId, {timelineSupport: timelineSupport});
});
it("should copy state from previous timeline", function() {
room.addEventsToTimeline([events[0], events[1]]);
expect(room.getLiveTimeline().getEvents().length).toEqual(2);
room.resetLiveTimeline();
room.addEventsToTimeline([events[2]]);
var oldState = room.getLiveTimeline().getState(EventTimeline.BACKWARDS);
var newState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
expect(room.getLiveTimeline().getEvents().length).toEqual(1);
expect(oldState.getStateEvents("m.room.name", "")).toEqual(events[1]);
expect(newState.getStateEvents("m.room.name", "")).toEqual(events[2]);
});
it("should reset the legacy timeline fields", function() {
room.addEventsToTimeline([events[0], events[1]]);
expect(room.timeline.length).toEqual(2);
room.resetLiveTimeline();
room.addEventsToTimeline([events[2]]);
var newLiveTimeline = room.getLiveTimeline();
expect(room.timeline).toEqual(newLiveTimeline.getEvents());
expect(room.oldState).toEqual(
newLiveTimeline.getState(EventTimeline.BACKWARDS));
expect(room.currentState).toEqual(
newLiveTimeline.getState(EventTimeline.FORWARDS));
});
it("should emit Room.timelineReset event", function() {
var callCount = 0;
room.on("Room.timelineReset", function(emitRoom) {
callCount += 1;
expect(emitRoom).toEqual(room);
});
room.resetLiveTimeline();
expect(callCount).toEqual(1);
});
it("should " + (timelineSupport ? "remember" : "forget") +
" old timelines", function() {
room.addEventsToTimeline([events[0]]);
expect(room.timeline.length).toEqual(1);
var firstLiveTimeline = room.getLiveTimeline();
room.resetLiveTimeline();
var tl = room.getTimelineForEvent(events[0].getId());
expect(tl).toBe(timelineSupport ? firstLiveTimeline : null);
});
};
describe("resetLiveTimeline with timelinesupport enabled",
resetTimelineTests.bind(null, true));
describe("resetLiveTimeline with timelinesupport disabled",
resetTimelineTests.bind(null, false));
describe("compareEventOrdering", function() {
beforeEach(function() {
room = new Room(roomId, {timelineSupport: true});