Skip to content

Commit fb565f3

Browse files
Remove support for unstable private read receipts (#2624)
1 parent afa3b37 commit fb565f3

File tree

7 files changed

+32
-142
lines changed

7 files changed

+32
-142
lines changed

spec/unit/room.spec.ts

Lines changed: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,15 +2452,13 @@ describe("Room", function() {
24522452
if (receiptType === ReceiptType.ReadPrivate) {
24532453
return { eventId: "eventId1" } as IWrappedReceipt;
24542454
}
2455-
if (receiptType === ReceiptType.UnstableReadPrivate) {
2456-
return { eventId: "eventId2" } as IWrappedReceipt;
2457-
}
24582455
if (receiptType === ReceiptType.Read) {
2459-
return { eventId: "eventId3" } as IWrappedReceipt;
2456+
return { eventId: "eventId2" } as IWrappedReceipt;
24602457
}
2458+
return null;
24612459
};
24622460

2463-
for (let i = 1; i <= 3; i++) {
2461+
for (let i = 1; i <= 2; i++) {
24642462
room.getUnfilteredTimelineSet = () => ({ compareEventOrdering: (event1, event2) => {
24652463
return (event1 === `eventId${i}`) ? 1 : -1;
24662464
} } as EventTimelineSet);
@@ -2471,20 +2469,18 @@ describe("Room", function() {
24712469

24722470
describe("correctly compares by timestamp", () => {
24732471
it("should correctly compare, if we have all receipts", () => {
2474-
for (let i = 1; i <= 3; i++) {
2472+
for (let i = 1; i <= 2; i++) {
24752473
room.getUnfilteredTimelineSet = () => ({
24762474
compareEventOrdering: (_1, _2) => null,
24772475
} as EventTimelineSet);
24782476
room.getReadReceiptForUserId = (userId, ignore, receiptType) => {
24792477
if (receiptType === ReceiptType.ReadPrivate) {
2480-
return { eventId: "eventId1", data: { ts: i === 1 ? 1 : 0 } } as IWrappedReceipt;
2481-
}
2482-
if (receiptType === ReceiptType.UnstableReadPrivate) {
2483-
return { eventId: "eventId2", data: { ts: i === 2 ? 1 : 0 } } as IWrappedReceipt;
2478+
return { eventId: "eventId1", data: { ts: i === 1 ? 2 : 1 } } as IWrappedReceipt;
24842479
}
24852480
if (receiptType === ReceiptType.Read) {
2486-
return { eventId: "eventId3", data: { ts: i === 3 ? 1 : 0 } } as IWrappedReceipt;
2481+
return { eventId: "eventId2", data: { ts: i === 2 ? 2 : 1 } } as IWrappedReceipt;
24872482
}
2483+
return null;
24882484
};
24892485

24902486
expect(room.getEventReadUpTo(userA)).toEqual(`eventId${i}`);
@@ -2496,12 +2492,10 @@ describe("Room", function() {
24962492
compareEventOrdering: (_1, _2) => null,
24972493
} as EventTimelineSet);
24982494
room.getReadReceiptForUserId = (userId, ignore, receiptType) => {
2499-
if (receiptType === ReceiptType.UnstableReadPrivate) {
2500-
return { eventId: "eventId1", data: { ts: 0 } } as IWrappedReceipt;
2501-
}
25022495
if (receiptType === ReceiptType.Read) {
25032496
return { eventId: "eventId2", data: { ts: 1 } } as IWrappedReceipt;
25042497
}
2498+
return null;
25052499
};
25062500

25072501
expect(room.getEventReadUpTo(userA)).toEqual(`eventId2`);
@@ -2520,35 +2514,21 @@ describe("Room", function() {
25202514
if (receiptType === ReceiptType.ReadPrivate) {
25212515
return { eventId: "eventId1" } as IWrappedReceipt;
25222516
}
2523-
if (receiptType === ReceiptType.UnstableReadPrivate) {
2524-
return { eventId: "eventId2" } as IWrappedReceipt;
2525-
}
2526-
if (receiptType === ReceiptType.Read) {
2527-
return { eventId: "eventId3" } as IWrappedReceipt;
2528-
}
2529-
};
2530-
2531-
expect(room.getEventReadUpTo(userA)).toEqual(`eventId1`);
2532-
});
2533-
2534-
it("should give precedence to org.matrix.msc2285.read.private", () => {
2535-
room.getReadReceiptForUserId = (userId, ignore, receiptType) => {
2536-
if (receiptType === ReceiptType.UnstableReadPrivate) {
2537-
return { eventId: "eventId2" } as IWrappedReceipt;
2538-
}
25392517
if (receiptType === ReceiptType.Read) {
25402518
return { eventId: "eventId2" } as IWrappedReceipt;
25412519
}
2520+
return null;
25422521
};
25432522

2544-
expect(room.getEventReadUpTo(userA)).toEqual(`eventId2`);
2523+
expect(room.getEventReadUpTo(userA)).toEqual(`eventId1`);
25452524
});
25462525

25472526
it("should give precedence to m.read", () => {
25482527
room.getReadReceiptForUserId = (userId, ignore, receiptType) => {
25492528
if (receiptType === ReceiptType.Read) {
25502529
return { eventId: "eventId3" } as IWrappedReceipt;
25512530
}
2531+
return null;
25522532
};
25532533

25542534
expect(room.getEventReadUpTo(userA)).toEqual(`eventId3`);

spec/unit/sync-accumulator.spec.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -302,9 +302,6 @@ describe("SyncAccumulator", function() {
302302
[ReceiptType.ReadPrivate]: {
303303
"@dan:localhost": { ts: 4 },
304304
},
305-
[ReceiptType.UnstableReadPrivate]: {
306-
"@matthew:localhost": { ts: 5 },
307-
},
308305
"some.other.receipt.type": {
309306
"@should_be_ignored:localhost": { key: "val" },
310307
},
@@ -350,9 +347,6 @@ describe("SyncAccumulator", function() {
350347
[ReceiptType.ReadPrivate]: {
351348
"@dan:localhost": { ts: 4 },
352349
},
353-
[ReceiptType.UnstableReadPrivate]: {
354-
"@matthew:localhost": { ts: 5 },
355-
},
356350
},
357351
"$event2:localhost": {
358352
[ReceiptType.Read]: {

spec/unit/utils.spec.ts

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -528,38 +528,6 @@ describe("utils", function() {
528528
});
529529
});
530530

531-
describe('getPrivateReadReceiptField', () => {
532-
it('should return m.read.private if server supports stable', async () => {
533-
expect(await utils.getPrivateReadReceiptField({
534-
doesServerSupportUnstableFeature: jest.fn().mockImplementation((feature) => {
535-
return feature === "org.matrix.msc2285.stable";
536-
}),
537-
} as any)).toBe(ReceiptType.ReadPrivate);
538-
});
539-
540-
it('should return m.read.private if server supports stable and unstable', async () => {
541-
expect(await utils.getPrivateReadReceiptField({
542-
doesServerSupportUnstableFeature: jest.fn().mockImplementation((feature) => {
543-
return ["org.matrix.msc2285.stable", "org.matrix.msc2285"].includes(feature);
544-
}),
545-
} as any)).toBe(ReceiptType.ReadPrivate);
546-
});
547-
548-
it('should return org.matrix.msc2285.read.private if server supports unstable', async () => {
549-
expect(await utils.getPrivateReadReceiptField({
550-
doesServerSupportUnstableFeature: jest.fn().mockImplementation((feature) => {
551-
return feature === "org.matrix.msc2285";
552-
}),
553-
} as any)).toBe(ReceiptType.UnstableReadPrivate);
554-
});
555-
556-
it('should return none if server does not support either', async () => {
557-
expect(await utils.getPrivateReadReceiptField({
558-
doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(false),
559-
} as any)).toBeFalsy();
560-
});
561-
});
562-
563531
describe('isSupportedReceiptType', () => {
564532
it('should support m.read', () => {
565533
expect(utils.isSupportedReceiptType(ReceiptType.Read)).toBeTruthy();
@@ -569,10 +537,6 @@ describe("utils", function() {
569537
expect(utils.isSupportedReceiptType(ReceiptType.ReadPrivate)).toBeTruthy();
570538
});
571539

572-
it('should support org.matrix.msc2285.read.private', () => {
573-
expect(utils.isSupportedReceiptType(ReceiptType.UnstableReadPrivate)).toBeTruthy();
574-
});
575-
576540
it('should not support other receipt types', () => {
577541
expect(utils.isSupportedReceiptType("this is a receipt type")).toBeFalsy();
578542
});

src/@types/read_receipts.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,4 @@ export enum ReceiptType {
1818
Read = "m.read",
1919
FullyRead = "m.fully_read",
2020
ReadPrivate = "m.read.private",
21-
/**
22-
* @deprecated Please use the ReadPrivate type when possible. This value may be removed at any time without notice.
23-
*/
24-
UnstableReadPrivate = "org.matrix.msc2285.read.private",
2521
}

src/client.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7543,9 +7543,8 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
75437543
[ReceiptType.Read]: rrEventId,
75447544
};
75457545

7546-
const privateField = await utils.getPrivateReadReceiptField(this);
7547-
if (privateField) {
7548-
content[privateField] = rpEventId;
7546+
if (await this.doesServerSupportUnstableFeature("org.matrix.msc2285.stable")) {
7547+
content[ReceiptType.ReadPrivate] = rpEventId;
75497548
}
75507549

75517550
return this.http.authedRequest(undefined, Method.Post, path, undefined, content);

src/models/room.ts

Lines changed: 17 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,59 +2600,26 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
26002600
// some more intelligent manner or the client should just use timestamps
26012601

26022602
const timelineSet = this.getUnfilteredTimelineSet();
2603-
const publicReadReceipt = this.getReadReceiptForUserId(
2604-
userId,
2605-
ignoreSynthesized,
2606-
ReceiptType.Read,
2607-
);
2608-
const privateReadReceipt = this.getReadReceiptForUserId(
2609-
userId,
2610-
ignoreSynthesized,
2611-
ReceiptType.ReadPrivate,
2612-
);
2613-
const unstablePrivateReadReceipt = this.getReadReceiptForUserId(
2614-
userId,
2615-
ignoreSynthesized,
2616-
ReceiptType.UnstableReadPrivate,
2617-
);
2603+
const publicReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, ReceiptType.Read);
2604+
const privateReadReceipt = this.getReadReceiptForUserId(userId, ignoreSynthesized, ReceiptType.ReadPrivate);
26182605

2619-
// If we have all, compare them
2620-
if (publicReadReceipt?.eventId && privateReadReceipt?.eventId && unstablePrivateReadReceipt?.eventId) {
2621-
const comparison1 = timelineSet.compareEventOrdering(
2622-
publicReadReceipt.eventId,
2623-
privateReadReceipt.eventId,
2624-
);
2625-
const comparison2 = timelineSet.compareEventOrdering(
2626-
publicReadReceipt.eventId,
2627-
unstablePrivateReadReceipt.eventId,
2628-
);
2629-
const comparison3 = timelineSet.compareEventOrdering(
2630-
privateReadReceipt.eventId,
2631-
unstablePrivateReadReceipt.eventId,
2632-
);
2633-
if (comparison1 && comparison2 && comparison3) {
2634-
return (comparison1 > 0)
2635-
? ((comparison2 > 0) ? publicReadReceipt.eventId : unstablePrivateReadReceipt.eventId)
2636-
: ((comparison3 > 0) ? privateReadReceipt.eventId : unstablePrivateReadReceipt.eventId);
2637-
}
2606+
// If we have both, compare them
2607+
let comparison: number | null | undefined;
2608+
if (publicReadReceipt?.eventId && privateReadReceipt?.eventId) {
2609+
comparison = timelineSet.compareEventOrdering(publicReadReceipt?.eventId, privateReadReceipt?.eventId);
26382610
}
26392611

2640-
let latest = privateReadReceipt;
2641-
[unstablePrivateReadReceipt, publicReadReceipt].forEach((receipt) => {
2642-
if (receipt?.data?.ts > latest?.data?.ts || !latest) {
2643-
latest = receipt;
2644-
}
2645-
});
2646-
if (latest?.eventId) return latest?.eventId;
2647-
2648-
// The more less likely it is for a read receipt to drift out of date
2649-
// the bigger is its precedence
2650-
return (
2651-
privateReadReceipt?.eventId ??
2652-
unstablePrivateReadReceipt?.eventId ??
2653-
publicReadReceipt?.eventId ??
2654-
null
2655-
);
2612+
// If we didn't get a comparison try to compare the ts of the receipts
2613+
if (!comparison && publicReadReceipt?.data?.ts && privateReadReceipt?.data?.ts) {
2614+
comparison = publicReadReceipt?.data?.ts - privateReadReceipt?.data?.ts;
2615+
}
2616+
2617+
// The public receipt is more likely to drift out of date so the private
2618+
// one has precedence
2619+
if (!comparison) return privateReadReceipt?.eventId ?? publicReadReceipt?.eventId ?? null;
2620+
2621+
// If public read receipt is older, return the private one
2622+
return ((comparison < 0) ? privateReadReceipt?.eventId : publicReadReceipt?.eventId) ?? null;
26562623
}
26572624

26582625
/**

src/utils.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import unhomoglyph from "unhomoglyph";
2424
import promiseRetry from "p-retry";
2525

2626
import type * as NodeCrypto from "crypto";
27-
import { MatrixClient, MatrixEvent } from ".";
27+
import { MatrixEvent } from ".";
2828
import { M_TIMESTAMP } from "./@types/location";
2929
import { ReceiptType } from "./@types/read_receipts";
3030

@@ -670,17 +670,7 @@ export function sortEventsByLatestContentTimestamp(left: MatrixEvent, right: Mat
670670
return getContentTimestampWithFallback(right) - getContentTimestampWithFallback(left);
671671
}
672672

673-
export async function getPrivateReadReceiptField(client: MatrixClient): Promise<ReceiptType | null> {
674-
if (await client.doesServerSupportUnstableFeature("org.matrix.msc2285.stable")) return ReceiptType.ReadPrivate;
675-
if (await client.doesServerSupportUnstableFeature("org.matrix.msc2285")) return ReceiptType.UnstableReadPrivate;
676-
return null;
677-
}
678-
679673
export function isSupportedReceiptType(receiptType: string): boolean {
680-
return [
681-
ReceiptType.Read,
682-
ReceiptType.ReadPrivate,
683-
ReceiptType.UnstableReadPrivate,
684-
].includes(receiptType as ReceiptType);
674+
return [ReceiptType.Read, ReceiptType.ReadPrivate].includes(receiptType as ReceiptType);
685675
}
686676

0 commit comments

Comments
 (0)