Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bugfix: sliding sync initial room timelines shouldn't notify #2933

Merged
merged 6 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion spec/integ/sliding-sync-sdk.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { TestClient } from "../TestClient";
import { IRoomEvent, IStateEvent } from "../../src/sync-accumulator";
import {
MatrixClient, MatrixEvent, NotificationCountType, JoinRule, MatrixError,
EventType, IPushRules, PushRuleKind, TweakName, ClientEvent, RoomMemberEvent,
EventType, IPushRules, PushRuleKind, TweakName, ClientEvent, RoomMemberEvent, RoomEvent, Room, IRoomTimelineData,
} from "../../src";
import { SlidingSyncSdk } from "../../src/sliding-sync-sdk";
import { SyncState } from "../../src/sync";
Expand Down Expand Up @@ -170,6 +170,7 @@ describe("SlidingSyncSdk", () => {
const roomE = "!e_with_invite:localhost";
const roomF = "!f_calc_room_name:localhost";
const roomG = "!g_join_invite_counts:localhost";
const roomH = "!g_num_live:localhost";
const data: Record<string, MSC3575RoomData> = {
[roomA]: {
name: "A",
Expand Down Expand Up @@ -275,6 +276,18 @@ describe("SlidingSyncSdk", () => {
invited_count: 2,
initial: true,
},
[roomH]: {
name: "H",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "live event" }),
],
initial: true,
num_live: 1,
},
};

it("can be created with required_state and timeline", () => {
Expand Down Expand Up @@ -326,6 +339,33 @@ describe("SlidingSyncSdk", () => {
expect(gotRoom.getJoinedMemberCount()).toEqual(data[roomG].joined_count);
});

it("can be created with live events", () => {
let seenLiveEvent = false;
const listener = (
ev: MatrixEvent,
room?: Room,
toStartOfTimeline?: boolean,
deleted?: boolean,
timelineData?: IRoomTimelineData,
) => {
if (timelineData?.liveEvent) {
assertTimelineEvents([ev], data[roomH].timeline.slice(-1));
seenLiveEvent = true;
}
};
client!.on(RoomEvent.Timeline, listener);
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomH, data[roomH]);
client!.off(RoomEvent.Timeline, listener);
const gotRoom = client!.getRoom(roomH);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.name).toEqual(data[roomH].name);
expect(gotRoom.getMyMembership()).toEqual("join");
// check the entire timeline is correct
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents(), data[roomH].timeline);
expect(seenLiveEvent).toBe(true);
});

it("can be created with invite_state", () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomE, data[roomE]);
const gotRoom = client!.getRoom(roomE);
Expand Down
28 changes: 24 additions & 4 deletions src/sliding-sync-sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ export class SlidingSyncSdk {
}
} */

this.injectRoomEvents(room, stateEvents, timelineEvents, false);
this.injectRoomEvents(room, stateEvents, timelineEvents, roomData.num_live);

// we deliberately don't add ephemeral events to the timeline
room.addEphemeralEvents(ephemeralEvents);
Expand Down Expand Up @@ -725,17 +725,19 @@ export class SlidingSyncSdk {
* @param {MatrixEvent[]} stateEventList A list of state events. This is the state
* at the *START* of the timeline list if it is supplied.
* @param {MatrixEvent[]} [timelineEventList] A list of timeline events. Lower index
* @param {boolean} fromCache whether the sync response came from cache
* is earlier in time. Higher index is later.
* @param {number} numLive the number of events in timelineEventList which just happened,
* supplied from the server.
*/
public injectRoomEvents(
room: Room,
stateEventList: MatrixEvent[],
timelineEventList?: MatrixEvent[],
fromCache = false,
numLive?: number,
): void {
timelineEventList = timelineEventList || [];
stateEventList = stateEventList || [];
numLive = numLive || 0;

// If there are no events in the timeline yet, initialise it with
// the given state events
Expand Down Expand Up @@ -774,13 +776,31 @@ export class SlidingSyncSdk {
room.currentState.setStateEvents(stateEventList);
}

// the timeline is broken into 'live' events which just happened and normal timeline events
// which are still to be appended to the end of the live timeline but happened a while ago.
// The live events are marked as fromCache=false to ensure that downstream components know
// this is a live event, not historical (from a remote server cache).

let liveTimelineEvents: MatrixEvent[] = [];
if (numLive > 0) {
// last numLive events are live
liveTimelineEvents = timelineEventList.slice(-1 * numLive);
// everything else is not live
timelineEventList = timelineEventList.slice(0, -1 * liveTimelineEvents.length);
}

// execute the timeline events. This will continue to diverge the current state
// if the timeline has any state events in it.
// This also needs to be done before running push rules on the events as they need
// to be decorated with sender etc.
room.addLiveEvents(timelineEventList, {
fromCache: fromCache,
fromCache: true,
});
if (liveTimelineEvents.length > 0) {
room.addLiveEvents(liveTimelineEvents, {
fromCache: false,
});
}

room.recalculate();

Expand Down
1 change: 1 addition & 0 deletions src/sliding-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export interface MSC3575RoomData {
limited?: boolean;
is_dm?: boolean;
prev_batch?: string;
num_live?: number;
}

interface ListResponse {
Expand Down