You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Better fallback for the event localTimestamp
calculation. (#3900)
* better fallback to localTimestamp calculation Signed-off-by: Timo K <toger5@hotmail.de> * make `isExpired` impl simpler to read Signed-off-by: Timo K <toger5@hotmail.de> * update tests Signed-off-by: Timo K <toger5@hotmail.de> * refactor to use localTimestamp in the mocks Signed-off-by: Timo K <toger5@hotmail.de> * Update src/models/event.ts Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/models/event.ts Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update and clarify comments. So that the localTimestamp and localAge behavior is easier to understand. Signed-off-by: Timo K <toger5@hotmail.de> * Replace localTimestamp biding with binding the whole roomState Signed-off-by: Timo K <toger5@hotmail.de> --------- Signed-off-by: Timo K <toger5@hotmail.de> Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
@@ -85,7 +85,7 @@ describe("CallMembership", () => {
|
|||||||
|
|
||||||
it("considers memberships expired when local age large", () => {
|
it("considers memberships expired when local age large", () => {
|
||||||
const fakeEvent = makeMockEvent(1000);
|
const fakeEvent = makeMockEvent(1000);
|
||||||
fakeEvent.getLocalAge = jest.fn().mockReturnValue(6000);
|
fakeEvent.localTimestamp = Date.now() - 6000;
|
||||||
const membership = new CallMembership(fakeEvent, membershipTemplate);
|
const membership = new CallMembership(fakeEvent, membershipTemplate);
|
||||||
expect(membership.isExpired()).toEqual(true);
|
expect(membership.isExpired()).toEqual(true);
|
||||||
});
|
});
|
||||||
|
@@ -67,7 +67,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
const expiredMembership = Object.assign({}, membershipTemplate);
|
const expiredMembership = Object.assign({}, membershipTemplate);
|
||||||
expiredMembership.expires = 1000;
|
expiredMembership.expires = 1000;
|
||||||
expiredMembership.device_id = "EXPIRED";
|
expiredMembership.device_id = "EXPIRED";
|
||||||
const mockRoom = makeMockRoom([membershipTemplate, expiredMembership], () => 10000);
|
const mockRoom = makeMockRoom([membershipTemplate, expiredMembership], 10000);
|
||||||
|
|
||||||
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
||||||
expect(sess?.memberships.length).toEqual(1);
|
expect(sess?.memberships.length).toEqual(1);
|
||||||
@@ -266,7 +266,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
const timeElapsed = 60 * 60 * 1000 - 1000;
|
const timeElapsed = 60 * 60 * 1000 - 1000;
|
||||||
mockRoom.getLiveTimeline().getState(EventTimeline.FORWARDS)!.getStateEvents = jest
|
mockRoom.getLiveTimeline().getState(EventTimeline.FORWARDS)!.getStateEvents = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockReturnValue(mockRTCEvent(eventContent.memberships, mockRoom.roomId, () => timeElapsed));
|
.mockReturnValue(mockRTCEvent(eventContent.memberships, mockRoom.roomId, timeElapsed));
|
||||||
|
|
||||||
const eventReSentPromise = new Promise<Record<string, any>>((r) => {
|
const eventReSentPromise = new Promise<Record<string, any>>((r) => {
|
||||||
resolveFn = (_roomId: string, _type: string, val: Record<string, any>) => {
|
resolveFn = (_roomId: string, _type: string, val: Record<string, any>) => {
|
||||||
@@ -539,10 +539,8 @@ describe("MatrixRTCSession", () => {
|
|||||||
it("emits an event at the time a membership event expires", () => {
|
it("emits an event at the time a membership event expires", () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
try {
|
try {
|
||||||
let eventAge = 0;
|
|
||||||
|
|
||||||
const membership = Object.assign({}, membershipTemplate);
|
const membership = Object.assign({}, membershipTemplate);
|
||||||
const mockRoom = makeMockRoom([membership], () => eventAge);
|
const mockRoom = makeMockRoom([membership], 0);
|
||||||
|
|
||||||
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
||||||
const membershipObject = sess.memberships[0];
|
const membershipObject = sess.memberships[0];
|
||||||
@@ -550,7 +548,6 @@ describe("MatrixRTCSession", () => {
|
|||||||
const onMembershipsChanged = jest.fn();
|
const onMembershipsChanged = jest.fn();
|
||||||
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
||||||
|
|
||||||
eventAge = 61 * 1000 * 1000;
|
|
||||||
jest.advanceTimersByTime(61 * 1000 * 1000);
|
jest.advanceTimersByTime(61 * 1000 * 1000);
|
||||||
|
|
||||||
expect(onMembershipsChanged).toHaveBeenCalledWith([membershipObject], []);
|
expect(onMembershipsChanged).toHaveBeenCalledWith([membershipObject], []);
|
||||||
@@ -561,47 +558,49 @@ describe("MatrixRTCSession", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("prunes expired memberships on update", () => {
|
it("prunes expired memberships on update", () => {
|
||||||
client.sendStateEvent = jest.fn();
|
jest.useFakeTimers();
|
||||||
|
try {
|
||||||
|
client.sendStateEvent = jest.fn();
|
||||||
|
|
||||||
let eventAge = 0;
|
const mockMemberships = [
|
||||||
|
|
||||||
const mockRoom = makeMockRoom(
|
|
||||||
[
|
|
||||||
Object.assign({}, membershipTemplate, {
|
Object.assign({}, membershipTemplate, {
|
||||||
device_id: "OTHERDEVICE",
|
device_id: "OTHERDEVICE",
|
||||||
expires: 1000,
|
expires: 1000,
|
||||||
}),
|
}),
|
||||||
],
|
];
|
||||||
() => eventAge,
|
const mockRoomNoExpired = makeMockRoom(mockMemberships, 0);
|
||||||
);
|
|
||||||
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
|
||||||
|
|
||||||
// sanity check
|
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoomNoExpired);
|
||||||
expect(sess.memberships).toHaveLength(1);
|
|
||||||
expect(sess.memberships[0].deviceId).toEqual("OTHERDEVICE");
|
|
||||||
|
|
||||||
eventAge = 10000;
|
// sanity check
|
||||||
|
expect(sess.memberships).toHaveLength(1);
|
||||||
|
expect(sess.memberships[0].deviceId).toEqual("OTHERDEVICE");
|
||||||
|
|
||||||
sess.joinRoomSession([mockFocus]);
|
jest.advanceTimersByTime(10000);
|
||||||
|
|
||||||
expect(client.sendStateEvent).toHaveBeenCalledWith(
|
sess.joinRoomSession([mockFocus]);
|
||||||
mockRoom!.roomId,
|
|
||||||
EventType.GroupCallMemberPrefix,
|
expect(client.sendStateEvent).toHaveBeenCalledWith(
|
||||||
{
|
mockRoomNoExpired!.roomId,
|
||||||
memberships: [
|
EventType.GroupCallMemberPrefix,
|
||||||
{
|
{
|
||||||
application: "m.call",
|
memberships: [
|
||||||
scope: "m.room",
|
{
|
||||||
call_id: "",
|
application: "m.call",
|
||||||
device_id: "AAAAAAA",
|
scope: "m.room",
|
||||||
expires: 3600000,
|
call_id: "",
|
||||||
foci_active: [mockFocus],
|
device_id: "AAAAAAA",
|
||||||
membershipID: expect.stringMatching(".*"),
|
expires: 3600000,
|
||||||
},
|
foci_active: [mockFocus],
|
||||||
],
|
membershipID: expect.stringMatching(".*"),
|
||||||
},
|
},
|
||||||
"@alice:example.org",
|
],
|
||||||
);
|
},
|
||||||
|
"@alice:example.org",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
jest.useRealTimers();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
it("fills in created_ts for other memberships on update", () => {
|
it("fills in created_ts for other memberships on update", () => {
|
||||||
|
@@ -18,41 +18,29 @@ import { EventType, MatrixEvent, Room } from "../../../src";
|
|||||||
import { CallMembershipData } from "../../../src/matrixrtc/CallMembership";
|
import { CallMembershipData } from "../../../src/matrixrtc/CallMembership";
|
||||||
import { randomString } from "../../../src/randomstring";
|
import { randomString } from "../../../src/randomstring";
|
||||||
|
|
||||||
export function makeMockRoom(
|
export function makeMockRoom(memberships: CallMembershipData[], localAge: number | null = null): Room {
|
||||||
memberships: CallMembershipData[],
|
|
||||||
getLocalAge: (() => number) | undefined = undefined,
|
|
||||||
): Room {
|
|
||||||
const roomId = randomString(8);
|
const roomId = randomString(8);
|
||||||
|
// Caching roomState here so it does not get recreated when calling `getLiveTimeline.getState()`
|
||||||
|
const roomState = makeMockRoomState(memberships, roomId, localAge);
|
||||||
return {
|
return {
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
getLiveTimeline: jest.fn().mockReturnValue({
|
getLiveTimeline: jest.fn().mockReturnValue({
|
||||||
getState: jest.fn().mockReturnValue(makeMockRoomState(memberships, roomId, getLocalAge)),
|
getState: jest.fn().mockReturnValue(roomState),
|
||||||
}),
|
}),
|
||||||
} as unknown as Room;
|
} as unknown as Room;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeMockRoomState(
|
export function makeMockRoomState(memberships: CallMembershipData[], roomId: string, localAge: number | null = null) {
|
||||||
memberships: CallMembershipData[],
|
const event = mockRTCEvent(memberships, roomId, localAge);
|
||||||
roomId: string,
|
|
||||||
getLocalAge: (() => number) | undefined,
|
|
||||||
) {
|
|
||||||
return {
|
return {
|
||||||
getStateEvents: (_: string, stateKey: string) => {
|
getStateEvents: (_: string, stateKey: string) => {
|
||||||
const event = mockRTCEvent(memberships, roomId, getLocalAge);
|
|
||||||
|
|
||||||
if (stateKey !== undefined) return event;
|
if (stateKey !== undefined) return event;
|
||||||
return [event];
|
return [event];
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mockRTCEvent(
|
export function mockRTCEvent(memberships: CallMembershipData[], roomId: string, localAge: number | null): MatrixEvent {
|
||||||
memberships: CallMembershipData[],
|
|
||||||
roomId: string,
|
|
||||||
getLocalAge: (() => number) | undefined,
|
|
||||||
): MatrixEvent {
|
|
||||||
const getLocalAgeFn = getLocalAge ?? (() => 10);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
|
||||||
getContent: jest.fn().mockReturnValue({
|
getContent: jest.fn().mockReturnValue({
|
||||||
@@ -60,8 +48,7 @@ export function mockRTCEvent(
|
|||||||
}),
|
}),
|
||||||
getSender: jest.fn().mockReturnValue("@mock:user.example"),
|
getSender: jest.fn().mockReturnValue("@mock:user.example"),
|
||||||
getTs: jest.fn().mockReturnValue(1000),
|
getTs: jest.fn().mockReturnValue(1000),
|
||||||
getLocalAge: getLocalAgeFn,
|
localTimestamp: Date.now() - (localAge ?? 10),
|
||||||
localTimestamp: Date.now(),
|
|
||||||
getRoomId: jest.fn().mockReturnValue(roomId),
|
getRoomId: jest.fn().mockReturnValue(roomId),
|
||||||
sender: {
|
sender: {
|
||||||
userId: "@mock:user.example",
|
userId: "@mock:user.example",
|
||||||
|
@@ -91,7 +91,7 @@ export class CallMembership {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public isExpired(): boolean {
|
public isExpired(): boolean {
|
||||||
return this.getAbsoluteExpiry() < this.parentEvent.getTs() + this.parentEvent.getLocalAge();
|
return this.getMsUntilExpiry() <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getActiveFoci(): Focus[] {
|
public getActiveFoci(): Focus[] {
|
||||||
|
@@ -404,7 +404,13 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.txnId = event.txn_id;
|
this.txnId = event.txn_id;
|
||||||
this.localTimestamp = Date.now() - (this.getAge() ?? 0);
|
// The localTimestamp is calculated using the age.
|
||||||
|
// Some events lack an `age` property, either because they are EDUs such as typing events,
|
||||||
|
// or due to server-side bugs such as https://github.com/matrix-org/synapse/issues/8429.
|
||||||
|
// The fallback in these cases will be to use the origin_server_ts.
|
||||||
|
// For EDUs, the origin_server_ts also is not defined so we use Date.now().
|
||||||
|
const age = this.getAge();
|
||||||
|
this.localTimestamp = age !== undefined ? Date.now() - age : this.getTs() ?? Date.now();
|
||||||
this.reEmitter = new TypedReEmitter(this);
|
this.reEmitter = new TypedReEmitter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user