You've already forked matrix-js-sdk
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:
@@ -143,12 +143,14 @@ function Room(roomId, opts) {
|
|||||||
|
|
||||||
this._notificationCounts = {};
|
this._notificationCounts = {};
|
||||||
|
|
||||||
|
this._liveTimeline = new EventTimeline(this.roomId);
|
||||||
|
this._fixUpLegacyTimelineFields();
|
||||||
|
|
||||||
// just a list - *not* ordered.
|
// just a list - *not* ordered.
|
||||||
this._timelines = [];
|
this._timelines = [this._liveTimeline];
|
||||||
this._eventIdToTimeline = {};
|
this._eventIdToTimeline = {};
|
||||||
this._timelineSupport = Boolean(opts.timelineSupport);
|
this._timelineSupport = Boolean(opts.timelineSupport);
|
||||||
|
|
||||||
this.resetLiveTimeline();
|
|
||||||
}
|
}
|
||||||
utils.inherits(Room, EventEmitter);
|
utils.inherits(Room, EventEmitter);
|
||||||
|
|
||||||
@@ -165,6 +167,8 @@ Room.prototype.getLiveTimeline = function() {
|
|||||||
* Reset the live timeline, and start a new one.
|
* Reset the live timeline, and start a new one.
|
||||||
*
|
*
|
||||||
* <p>This is used when /sync returns a 'limited' timeline.
|
* <p>This is used when /sync returns a 'limited' timeline.
|
||||||
|
*
|
||||||
|
* @fires module:client~MatrixClient#event:"Room.timelineReset"
|
||||||
*/
|
*/
|
||||||
Room.prototype.resetLiveTimeline = function() {
|
Room.prototype.resetLiveTimeline = function() {
|
||||||
var newTimeline;
|
var newTimeline;
|
||||||
@@ -178,10 +182,6 @@ Room.prototype.resetLiveTimeline = function() {
|
|||||||
newTimeline = this.addTimeline();
|
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
|
// initialise the state in the new timeline from our last known state
|
||||||
var evMap = this._liveTimeline.getState(EventTimeline.FORWARDS).events;
|
var evMap = this._liveTimeline.getState(EventTimeline.FORWARDS).events;
|
||||||
var events = [];
|
var events = [];
|
||||||
@@ -193,9 +193,18 @@ Room.prototype.resetLiveTimeline = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
newTimeline.initialiseState(events);
|
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,
|
// maintain this.timeline as a reference to the live timeline,
|
||||||
// and this.oldState and this.currentState as references to the
|
// and this.oldState and this.currentState as references to the
|
||||||
// state at the start and end of that timeline. These are more
|
// 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.
|
* Fires when an event we had previously received is redacted.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ SyncApi.prototype.createRoom = function(roomId) {
|
|||||||
timelineSupport: client.timelineSupport,
|
timelineSupport: client.timelineSupport,
|
||||||
});
|
});
|
||||||
reEmit(client, room, ["Room.name", "Room.timeline", "Room.redaction",
|
reEmit(client, room, ["Room.name", "Room.timeline", "Room.redaction",
|
||||||
"Room.receipt", "Room.tags"]);
|
"Room.receipt", "Room.tags",
|
||||||
|
"Room.timelineReset"]);
|
||||||
this._registerStateListeners(room);
|
this._registerStateListeners(room);
|
||||||
return room;
|
return room;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -512,5 +512,31 @@ describe("MatrixClient room timelines", function() {
|
|||||||
});
|
});
|
||||||
httpBackend.flush("/sync", 1);
|
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ var Room = sdk.Room;
|
|||||||
var RoomState = sdk.RoomState;
|
var RoomState = sdk.RoomState;
|
||||||
var MatrixEvent = sdk.MatrixEvent;
|
var MatrixEvent = sdk.MatrixEvent;
|
||||||
var EventStatus = sdk.EventStatus;
|
var EventStatus = sdk.EventStatus;
|
||||||
|
var EventTimeline = sdk.EventTimeline;
|
||||||
var utils = require("../test-utils");
|
var utils = require("../test-utils");
|
||||||
|
|
||||||
describe("Room", function() {
|
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() {
|
describe("compareEventOrdering", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
room = new Room(roomId, {timelineSupport: true});
|
room = new Room(roomId, {timelineSupport: true});
|
||||||
|
|||||||
Reference in New Issue
Block a user