Skip to content

Commit 99600e8

Browse files
authored
Add expire_ts compatibility to matrixRTC (#4032)
* add expire_ts compatibility to matrixRTC Signed-off-by: Timo K <[email protected]> * add expire_ts Signed-off-by: Timo K <[email protected]> * rename expire_ts -> expires_ts Signed-off-by: Timo K <[email protected]> * allow events without `expires` Signed-off-by: Timo K <[email protected]> * fix test for expires_ts Signed-off-by: Timo K <[email protected]> * comment clarification Signed-off-by: Timo K <[email protected]> * add comment where one needs to use the origin_server_ts Signed-off-by: Timo K <[email protected]> * add additional expires_ts tests Signed-off-by: Timo K <[email protected]> * fix fake timer Signed-off-by: Timo K <[email protected]> * change priority order to favor expires Signed-off-by: Timo K <[email protected]> --------- Signed-off-by: Timo K <[email protected]>
1 parent 7cf59d6 commit 99600e8

File tree

4 files changed

+67
-12
lines changed

4 files changed

+67
-12
lines changed

spec/unit/matrixrtc/CallMembership.spec.ts

+24-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ function makeMockEvent(originTs = 0): MatrixEvent {
3434
}
3535

3636
describe("CallMembership", () => {
37-
it("rejects membership with no expiry", () => {
37+
it("rejects membership with no expiry and no expires_ts", () => {
3838
expect(() => {
39-
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: undefined }));
39+
new CallMembership(
40+
makeMockEvent(),
41+
Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: undefined }),
42+
);
4043
}).toThrow();
4144
});
4245

@@ -57,6 +60,16 @@ describe("CallMembership", () => {
5760
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { scope: undefined }));
5861
}).toThrow();
5962
});
63+
it("rejects with malformatted expires_ts", () => {
64+
expect(() => {
65+
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires_ts: "string" }));
66+
}).toThrow();
67+
});
68+
it("rejects with malformatted expires", () => {
69+
expect(() => {
70+
new CallMembership(makeMockEvent(), Object.assign({}, membershipTemplate, { expires: "string" }));
71+
}).toThrow();
72+
});
6073

6174
it("uses event timestamp if no created_ts", () => {
6275
const membership = new CallMembership(makeMockEvent(12345), membershipTemplate);
@@ -71,11 +84,19 @@ describe("CallMembership", () => {
7184
expect(membership.createdTs()).toEqual(67890);
7285
});
7386

74-
it("computes absolute expiry time", () => {
87+
it("computes absolute expiry time based on expires", () => {
7588
const membership = new CallMembership(makeMockEvent(1000), membershipTemplate);
7689
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
7790
});
7891

92+
it("computes absolute expiry time based on expires_ts", () => {
93+
const membership = new CallMembership(
94+
makeMockEvent(1000),
95+
Object.assign({}, membershipTemplate, { expires: undefined, expires_ts: 6000 }),
96+
);
97+
expect(membership.getAbsoluteExpiry()).toEqual(5000 + 1000);
98+
});
99+
79100
it("considers memberships unexpired if local age low enough", () => {
80101
const fakeEvent = makeMockEvent(1000);
81102
fakeEvent.getLocalAge = jest.fn().mockReturnValue(3000);

spec/unit/matrixrtc/MatrixRTCSession.spec.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ describe("MatrixRTCSession", () => {
214214
});
215215

216216
it("sends a membership event when joining a call", () => {
217+
jest.useFakeTimers();
217218
sess!.joinRoomSession([mockFocus]);
218-
219219
expect(client.sendStateEvent).toHaveBeenCalledWith(
220220
mockRoom!.roomId,
221221
EventType.GroupCallMemberPrefix,
@@ -227,13 +227,15 @@ describe("MatrixRTCSession", () => {
227227
call_id: "",
228228
device_id: "AAAAAAA",
229229
expires: 3600000,
230+
expires_ts: Date.now() + 3600000,
230231
foci_active: [{ type: "mock" }],
231232
membershipID: expect.stringMatching(".*"),
232233
},
233234
],
234235
},
235236
"@alice:example.org",
236237
);
238+
jest.useRealTimers();
237239
});
238240

239241
it("does nothing if join called when already joined", () => {
@@ -291,6 +293,7 @@ describe("MatrixRTCSession", () => {
291293
call_id: "",
292294
device_id: "AAAAAAA",
293295
expires: 3600000 * 2,
296+
expires_ts: 1000 + 3600000 * 2,
294297
foci_active: [{ type: "mock" }],
295298
created_ts: 1000,
296299
membershipID: expect.stringMatching(".*"),
@@ -510,7 +513,7 @@ describe("MatrixRTCSession", () => {
510513
});
511514
});
512515

513-
it("Does not emits if no membership changes", () => {
516+
it("Does not emit if no membership changes", () => {
514517
const mockRoom = makeMockRoom([membershipTemplate]);
515518
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
516519

@@ -591,6 +594,7 @@ describe("MatrixRTCSession", () => {
591594
call_id: "",
592595
device_id: "AAAAAAA",
593596
expires: 3600000,
597+
expires_ts: Date.now() + 3600000,
594598
foci_active: [mockFocus],
595599
membershipID: expect.stringMatching(".*"),
596600
},
@@ -605,7 +609,7 @@ describe("MatrixRTCSession", () => {
605609

606610
it("fills in created_ts for other memberships on update", () => {
607611
client.sendStateEvent = jest.fn();
608-
612+
jest.useFakeTimers();
609613
const mockRoom = makeMockRoom([
610614
Object.assign({}, membershipTemplate, {
611615
device_id: "OTHERDEVICE",
@@ -635,13 +639,15 @@ describe("MatrixRTCSession", () => {
635639
call_id: "",
636640
device_id: "AAAAAAA",
637641
expires: 3600000,
642+
expires_ts: Date.now() + 3600000,
638643
foci_active: [mockFocus],
639644
membershipID: expect.stringMatching(".*"),
640645
},
641646
],
642647
},
643648
"@alice:example.org",
644649
);
650+
jest.useRealTimers();
645651
});
646652

647653
it("collects keys from encryption events", () => {

src/matrixrtc/CallMembership.ts

+31-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export interface CallMembershipData {
2727
scope: CallScope;
2828
device_id: string;
2929
created_ts?: number;
30-
expires: number;
30+
expires?: number;
31+
expires_ts?: number;
3132
foci_active?: Focus[];
3233
membershipID: string;
3334
}
@@ -41,7 +42,20 @@ export class CallMembership {
4142
private parentEvent: MatrixEvent,
4243
private data: CallMembershipData,
4344
) {
44-
if (typeof data.expires !== "number") throw new Error("Malformed membership: expires must be numeric");
45+
if (!(data.expires || data.expires_ts)) {
46+
throw new Error("Malformed membership: expires_ts or expires must be present");
47+
}
48+
if (data.expires) {
49+
if (typeof data.expires !== "number") {
50+
throw new Error("Malformed membership: expires must be numeric");
51+
}
52+
}
53+
if (data.expires_ts) {
54+
if (typeof data.expires_ts !== "number") {
55+
throw new Error("Malformed membership: expires_ts must be numeric");
56+
}
57+
}
58+
4559
if (typeof data.device_id !== "string") throw new Error("Malformed membership event: device_id must be string");
4660
if (typeof data.call_id !== "string") throw new Error("Malformed membership event: call_id must be string");
4761
if (typeof data.scope !== "string") throw new Error("Malformed membership event: scope must be string");
@@ -77,16 +91,27 @@ export class CallMembership {
7791
}
7892

7993
public getAbsoluteExpiry(): number {
80-
return this.createdTs() + this.data.expires;
94+
if (this.data.expires) {
95+
return this.createdTs() + this.data.expires;
96+
} else {
97+
// We know it exists because we checked for this in the constructor.
98+
return this.data.expires_ts!;
99+
}
81100
}
82101

83102
// gets the expiry time of the event, converted into the device's local time
84103
public getLocalExpiry(): number {
85-
const relativeCreationTime = this.parentEvent.getTs() - this.createdTs();
104+
if (this.data.expires) {
105+
const relativeCreationTime = this.parentEvent.getTs() - this.createdTs();
86106

87-
const localCreationTs = this.parentEvent.localTimestamp - relativeCreationTime;
107+
const localCreationTs = this.parentEvent.localTimestamp - relativeCreationTime;
88108

89-
return localCreationTs + this.data.expires;
109+
return localCreationTs + this.data.expires;
110+
} else {
111+
// With expires_ts we cannot convert to local time.
112+
// TODO: Check the server timestamp and compute a diff to local time.
113+
return this.data.expires_ts!;
114+
}
90115
}
91116

92117
public getMsUntilExpiry(): number {

src/matrixrtc/MatrixRTCSession.ts

+3
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,9 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
624624
};
625625

626626
if (prevMembership) m.created_ts = prevMembership.createdTs();
627+
if (m.created_ts) m.expires_ts = m.created_ts + (m.expires ?? 0);
628+
// TODO: Date.now() should be the origin_server_ts (now).
629+
else m.expires_ts = Date.now() + (m.expires ?? 0);
627630

628631
return m;
629632
}

0 commit comments

Comments
 (0)