1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-07-31 15:24:23 +03:00

sliding sync bugfix: ensure history is treated as history and not live events

with tests
This commit is contained in:
Kegan Dougal
2022-08-10 12:32:28 +01:00
parent 8f13df2dd9
commit 1635ac9971
2 changed files with 72 additions and 1 deletions

View File

@ -28,6 +28,7 @@ import {
import { SlidingSyncSdk } from "../../src/sliding-sync-sdk"; import { SlidingSyncSdk } from "../../src/sliding-sync-sdk";
import { SyncState } from "../../src/sync"; import { SyncState } from "../../src/sync";
import { IStoredClientOpts } from "../../src/client"; import { IStoredClientOpts } from "../../src/client";
import { logger } from "../../src/logger";
describe("SlidingSyncSdk", () => { describe("SlidingSyncSdk", () => {
let client: MatrixClient = null; let client: MatrixClient = null;
@ -372,6 +373,36 @@ describe("SlidingSyncSdk", () => {
gotRoom.getUnreadNotificationCount(NotificationCountType.Total), gotRoom.getUnreadNotificationCount(NotificationCountType.Total),
).toEqual(1); ).toEqual(1);
}); });
// Regression test for a bug which caused the timeline entries to be out-of-order
// when the same room appears twice with different timeline limits. E.g appears in
// the list with timeline_limit:1 then appears again as a room subscription with
// timeline_limit:50
it("can return history with a larger timeline_limit", async () => {
const timeline = data[roomA].timeline;
const oldTimeline = [
mkOwnEvent(EventType.RoomMessage, { body: "old event A" }),
mkOwnEvent(EventType.RoomMessage, { body: "old event B" }),
mkOwnEvent(EventType.RoomMessage, { body: "old event C" }),
...timeline,
];
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomA, {
timeline: oldTimeline,
required_state: [],
name: data[roomA].name,
initial: true, // e.g requested via room subscription
});
const gotRoom = client.getRoom(roomA);
expect(gotRoom).toBeDefined();
logger.log("want:", oldTimeline.map((e) => (e.type + " : " + (e.content || {}).body)));
logger.log("got:", gotRoom.getLiveTimeline().getEvents().map(
(e) => (e.getType() + " : " + e.getContent().body)),
);
// we expect the timeline now to be oldTimeline (so the old events are in fact old)
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents(), oldTimeline);
});
}); });
}); });
}); });

View File

@ -406,9 +406,49 @@ export class SlidingSyncSdk {
// this helps large account to speed up faster // this helps large account to speed up faster
// room::decryptCriticalEvent is in charge of decrypting all the events // room::decryptCriticalEvent is in charge of decrypting all the events
// required for a client to function properly // required for a client to function properly
const timelineEvents = mapEvents(this.client, room.roomId, roomData.timeline, false); let timelineEvents = mapEvents(this.client, room.roomId, roomData.timeline, false);
const ephemeralEvents = []; // TODO this.mapSyncEventsFormat(joinObj.ephemeral); const ephemeralEvents = []; // TODO this.mapSyncEventsFormat(joinObj.ephemeral);
// TODO: handle threaded / beacon events
if (roomData.initial) {
// we should not know about any of these timeline entries if this is a genuinely new room.
// If we do, then we've effectively done scrollback (e.g requesting timeline_limit: 1 for
// this room, then timeline_limit: 50).
const knownEvents: Record<string, boolean> = {};
room.getLiveTimeline().getEvents().forEach((e) => {
knownEvents[e.getId()] = true;
});
// all unknown events BEFORE a known event must be scrollback e.g:
// D E <-- what we know
// A B C D E F <-- what we just received
// means:
// A B C <-- scrollback
// D E <-- dupes
// F <-- new event
// We bucket events based on if we have seen a known event yet.
const oldEvents: MatrixEvent[] = [];
const newEvents: MatrixEvent[] = [];
let seenKnownEvent = false;
for (let i = timelineEvents.length-1; i >= 0; i--) {
const recvEvent = timelineEvents[i];
if (knownEvents[recvEvent.getId()]) {
seenKnownEvent = true;
continue; // don't include this event, it's a dupe
}
if (seenKnownEvent) {
// old -> new
oldEvents.push(recvEvent);
} else {
// old -> new
newEvents.unshift(recvEvent);
}
}
timelineEvents = newEvents;
// old events are scrollback, insert them now
room.addEventsToTimeline(oldEvents, true, room.getLiveTimeline());
}
const encrypted = this.client.isRoomEncrypted(room.roomId); const encrypted = this.client.isRoomEncrypted(room.roomId);
// we do this first so it's correct when any of the events fire // we do this first so it's correct when any of the events fire
if (roomData.notification_count != null) { if (roomData.notification_count != null) {