Skip to content

Commit d87e538

Browse files
authored
Merge pull request #2628 from matrix-org/kegan/ss-member-counts
sliding sync: add invited|joined_count
2 parents 917e8c0 + ac7f505 commit d87e538

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

spec/integ/sliding-sync-sdk.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ describe("SlidingSyncSdk", () => {
168168
const roomD = "!d_with_notif_count:localhost";
169169
const roomE = "!e_with_invite:localhost";
170170
const roomF = "!f_calc_room_name:localhost";
171+
const roomG = "!g_join_invite_counts:localhost";
171172
const data: Record<string, MSC3575RoomData> = {
172173
[roomA]: {
173174
name: "A",
@@ -261,12 +262,25 @@ describe("SlidingSyncSdk", () => {
261262
],
262263
initial: true,
263264
},
265+
[roomG]: {
266+
name: "G",
267+
required_state: [],
268+
timeline: [
269+
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
270+
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
271+
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
272+
],
273+
joined_count: 5,
274+
invited_count: 2,
275+
initial: true,
276+
},
264277
};
265278

266279
it("can be created with required_state and timeline", () => {
267280
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomA, data[roomA]);
268281
const gotRoom = client.getRoom(roomA);
269282
expect(gotRoom).toBeDefined();
283+
if (gotRoom == null) { return; }
270284
expect(gotRoom.name).toEqual(data[roomA].name);
271285
expect(gotRoom.getMyMembership()).toEqual("join");
272286
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-2), data[roomA].timeline);
@@ -276,6 +290,7 @@ describe("SlidingSyncSdk", () => {
276290
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomB, data[roomB]);
277291
const gotRoom = client.getRoom(roomB);
278292
expect(gotRoom).toBeDefined();
293+
if (gotRoom == null) { return; }
279294
expect(gotRoom.name).toEqual(data[roomB].name);
280295
expect(gotRoom.getMyMembership()).toEqual("join");
281296
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-5), data[roomB].timeline);
@@ -285,6 +300,7 @@ describe("SlidingSyncSdk", () => {
285300
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomC, data[roomC]);
286301
const gotRoom = client.getRoom(roomC);
287302
expect(gotRoom).toBeDefined();
303+
if (gotRoom == null) { return; }
288304
expect(
289305
gotRoom.getUnreadNotificationCount(NotificationCountType.Highlight),
290306
).toEqual(data[roomC].highlight_count);
@@ -294,15 +310,26 @@ describe("SlidingSyncSdk", () => {
294310
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomD, data[roomD]);
295311
const gotRoom = client.getRoom(roomD);
296312
expect(gotRoom).toBeDefined();
313+
if (gotRoom == null) { return; }
297314
expect(
298315
gotRoom.getUnreadNotificationCount(NotificationCountType.Total),
299316
).toEqual(data[roomD].notification_count);
300317
});
301318

319+
it("can be created with an invited/joined_count", () => {
320+
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomG, data[roomG]);
321+
const gotRoom = client.getRoom(roomG);
322+
expect(gotRoom).toBeDefined();
323+
if (gotRoom == null) { return; }
324+
expect(gotRoom.getInvitedMemberCount()).toEqual(data[roomG].invited_count);
325+
expect(gotRoom.getJoinedMemberCount()).toEqual(data[roomG].joined_count);
326+
});
327+
302328
it("can be created with invite_state", () => {
303329
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomE, data[roomE]);
304330
const gotRoom = client.getRoom(roomE);
305331
expect(gotRoom).toBeDefined();
332+
if (gotRoom == null) { return; }
306333
expect(gotRoom.getMyMembership()).toEqual("invite");
307334
expect(gotRoom.currentState.getJoinRule()).toEqual(JoinRule.Invite);
308335
});
@@ -311,6 +338,7 @@ describe("SlidingSyncSdk", () => {
311338
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomF, data[roomF]);
312339
const gotRoom = client.getRoom(roomF);
313340
expect(gotRoom).toBeDefined();
341+
if (gotRoom == null) { return; }
314342
expect(
315343
gotRoom.name,
316344
).toEqual(data[roomF].name);
@@ -326,13 +354,16 @@ describe("SlidingSyncSdk", () => {
326354
});
327355
const gotRoom = client.getRoom(roomA);
328356
expect(gotRoom).toBeDefined();
357+
if (gotRoom == null) { return; }
329358
const newTimeline = data[roomA].timeline;
330359
newTimeline.push(newEvent);
331360
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-3), newTimeline);
332361
});
333362

334363
it("can update with a new required_state event", async () => {
335364
let gotRoom = client.getRoom(roomB);
365+
expect(gotRoom).toBeDefined();
366+
if (gotRoom == null) { return; }
336367
expect(gotRoom.getJoinRule()).toEqual(JoinRule.Invite); // default
337368
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomB, {
338369
required_state: [
@@ -343,6 +374,7 @@ describe("SlidingSyncSdk", () => {
343374
});
344375
gotRoom = client.getRoom(roomB);
345376
expect(gotRoom).toBeDefined();
377+
if (gotRoom == null) { return; }
346378
expect(gotRoom.getJoinRule()).toEqual(JoinRule.Restricted);
347379
});
348380

@@ -355,6 +387,7 @@ describe("SlidingSyncSdk", () => {
355387
});
356388
const gotRoom = client.getRoom(roomC);
357389
expect(gotRoom).toBeDefined();
390+
if (gotRoom == null) { return; }
358391
expect(
359392
gotRoom.getUnreadNotificationCount(NotificationCountType.Highlight),
360393
).toEqual(1);
@@ -369,11 +402,25 @@ describe("SlidingSyncSdk", () => {
369402
});
370403
const gotRoom = client.getRoom(roomD);
371404
expect(gotRoom).toBeDefined();
405+
if (gotRoom == null) { return; }
372406
expect(
373407
gotRoom.getUnreadNotificationCount(NotificationCountType.Total),
374408
).toEqual(1);
375409
});
376410

411+
it("can update with a new joined_count", () => {
412+
mockSlidingSync.emit(SlidingSyncEvent.RoomData, roomG, {
413+
name: data[roomD].name,
414+
required_state: [],
415+
timeline: [],
416+
joined_count: 1,
417+
});
418+
const gotRoom = client.getRoom(roomG);
419+
expect(gotRoom).toBeDefined();
420+
if (gotRoom == null) { return; }
421+
expect(gotRoom.getJoinedMemberCount()).toEqual(1);
422+
});
423+
377424
// Regression test for a bug which caused the timeline entries to be out-of-order
378425
// when the same room appears twice with different timeline limits. E.g appears in
379426
// the list with timeline_limit:1 then appears again as a room subscription with
@@ -394,6 +441,7 @@ describe("SlidingSyncSdk", () => {
394441
});
395442
const gotRoom = client.getRoom(roomA);
396443
expect(gotRoom).toBeDefined();
444+
if (gotRoom == null) { return; }
397445

398446
logger.log("want:", oldTimeline.map((e) => (e.type + " : " + (e.content || {}).body)));
399447
logger.log("got:", gotRoom.getLiveTimeline().getEvents().map(

src/sliding-sync-sdk.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,13 +293,16 @@ export class SlidingSyncSdk {
293293
this.processRoomData(this.client, room, roomData);
294294
}
295295

296-
private onLifecycle(state: SlidingSyncState, resp: MSC3575SlidingSyncResponse, err?: Error): void {
296+
private onLifecycle(state: SlidingSyncState, resp: MSC3575SlidingSyncResponse | null, err: Error | null): void {
297297
if (err) {
298298
logger.debug("onLifecycle", state, err);
299299
}
300300
switch (state) {
301301
case SlidingSyncState.Complete:
302302
this.purgeNotifications();
303+
if (!resp) {
304+
break;
305+
}
303306
// Element won't stop showing the initial loading spinner unless we fire SyncState.Prepared
304307
if (!this.lastPos) {
305308
this.updateSyncState(SyncState.Prepared, {
@@ -472,6 +475,13 @@ export class SlidingSyncSdk {
472475
}
473476
}
474477

478+
if (Number.isInteger(roomData.invited_count)) {
479+
room.currentState.setInvitedMemberCount(roomData.invited_count!);
480+
}
481+
if (Number.isInteger(roomData.joined_count)) {
482+
room.currentState.setJoinedMemberCount(roomData.joined_count!);
483+
}
484+
475485
if (roomData.invite_state) {
476486
const inviteStateEvents = mapEvents(this.client, room.roomId, roomData.invite_state);
477487
this.processRoomEvents(room, inviteStateEvents);

src/sliding-sync.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ export interface MSC3575RoomData {
8484
timeline: (IRoomEvent | IStateEvent)[];
8585
notification_count?: number;
8686
highlight_count?: number;
87+
joined_count?: number;
88+
invited_count?: number;
8789
invite_state?: IStateEvent[];
8890
initial?: boolean;
8991
limited?: boolean;
@@ -320,7 +322,9 @@ export enum SlidingSyncEvent {
320322

321323
export type SlidingSyncEventHandlerMap = {
322324
[SlidingSyncEvent.RoomData]: (roomId: string, roomData: MSC3575RoomData) => void;
323-
[SlidingSyncEvent.Lifecycle]: (state: SlidingSyncState, resp: MSC3575SlidingSyncResponse, err: Error) => void;
325+
[SlidingSyncEvent.Lifecycle]: (
326+
state: SlidingSyncState, resp: MSC3575SlidingSyncResponse | null, err: Error | null,
327+
) => void;
324328
[SlidingSyncEvent.List]: (
325329
listIndex: number, joinedCount: number, roomIndexToRoomId: Record<number, string>,
326330
) => void;

0 commit comments

Comments
 (0)