1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

fix lints

Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Timo K
2025-10-06 15:06:03 +02:00
parent 8a21ff69bb
commit 4bbb240142
3 changed files with 143 additions and 121 deletions

View File

@@ -38,6 +38,8 @@ describe("MatrixRTCSession", () => {
client.getDeviceId = jest.fn().mockReturnValue("AAAAAAA");
client.sendEvent = jest.fn().mockResolvedValue({ event_id: "success" });
client.decryptEventIfNeeded = jest.fn();
client.fetchRoomEvent = jest.fn().mockResolvedValue(undefined);
client._unstable_sendDelayedStateEvent = jest.fn().mockResolvedValue({ event_id: "success" });
});
afterEach(async () => {
@@ -48,10 +50,10 @@ describe("MatrixRTCSession", () => {
});
describe("roomSessionForRoom", () => {
it("creates a room-scoped session from room state", () => {
it("creates a room-scoped session from room state", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships.length).toEqual(1);
expect(sess?.memberships[0].slotDescription.id).toEqual("");
expect(sess?.memberships[0].scope).toEqual("m.room");
@@ -61,26 +63,26 @@ describe("MatrixRTCSession", () => {
expect(sess?.slotDescription.id).toEqual("");
});
it("ignores memberships where application is not m.call", () => {
it("ignores memberships where application is not m.call", async () => {
const testMembership = Object.assign({}, membershipTemplate, {
application: "not-m.call",
});
const mockRoom = makeMockRoom([testMembership]);
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships).toHaveLength(0);
});
it("ignores memberships where callId is not empty", () => {
it("ignores memberships where callId is not empty", async () => {
const testMembership = Object.assign({}, membershipTemplate, {
call_id: "not-empty",
scope: "m.room",
});
const mockRoom = makeMockRoom([testMembership]);
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships).toHaveLength(0);
});
it("ignores expired memberships events", () => {
it("ignores expired memberships events", async () => {
jest.useFakeTimers();
const expiredMembership = Object.assign({}, membershipTemplate);
expiredMembership.expires = 1000;
@@ -88,38 +90,38 @@ describe("MatrixRTCSession", () => {
const mockRoom = makeMockRoom([membershipTemplate, expiredMembership]);
jest.advanceTimersByTime(2000);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships.length).toEqual(1);
expect(sess?.memberships[0].deviceId).toEqual("AAAAAAA");
jest.useRealTimers();
});
it("ignores memberships events of members not in the room", () => {
it("ignores memberships events of members not in the room", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
mockRoom.hasMembershipState = (state) => state === KnownMembership.Join;
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships.length).toEqual(0);
});
it("honours created_ts", () => {
it("honours created_ts", async () => {
jest.useFakeTimers();
jest.setSystemTime(500);
const expiredMembership = Object.assign({}, membershipTemplate);
expiredMembership.created_ts = 500;
expiredMembership.expires = 1000;
const mockRoom = makeMockRoom([expiredMembership]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships[0].getAbsoluteExpiry()).toEqual(1500);
jest.useRealTimers();
});
it("returns empty session if no membership events are present", () => {
it("returns empty session if no membership events are present", async () => {
const mockRoom = makeMockRoom([]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess?.memberships).toHaveLength(0);
});
it("safely ignores events with no memberships section", () => {
it("safely ignores events with no memberships section", async () => {
const roomId = secureRandomString(8);
const event = {
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
@@ -150,11 +152,11 @@ describe("MatrixRTCSession", () => {
}),
}),
};
sess = MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
expect(sess.memberships).toHaveLength(0);
});
it("safely ignores events with junk memberships section", () => {
it("safely ignores events with junk memberships section", async () => {
const roomId = secureRandomString(8);
const event = {
getType: jest.fn().mockReturnValue(EventType.GroupCallMemberPrefix),
@@ -185,29 +187,29 @@ describe("MatrixRTCSession", () => {
}),
}),
};
sess = MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom as unknown as Room, callSession);
expect(sess.memberships).toHaveLength(0);
});
it("ignores memberships with no device_id", () => {
it("ignores memberships with no device_id", async () => {
const testMembership = Object.assign({}, membershipTemplate);
(testMembership.device_id as string | undefined) = undefined;
const mockRoom = makeMockRoom([testMembership]);
const sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess.memberships).toHaveLength(0);
});
it("ignores memberships with no call_id", () => {
it("ignores memberships with no call_id", async () => {
const testMembership = Object.assign({}, membershipTemplate);
(testMembership.call_id as string | undefined) = undefined;
const mockRoom = makeMockRoom([testMembership]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess.memberships).toHaveLength(0);
});
});
describe("getOldestMembership", () => {
it("returns the oldest membership event", () => {
it("returns the oldest membership event", async () => {
jest.useFakeTimers();
jest.setSystemTime(4000);
const mockRoom = makeMockRoom([
@@ -216,7 +218,7 @@ describe("MatrixRTCSession", () => {
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess.getOldestMembership()!.deviceId).toEqual("old");
jest.useRealTimers();
});
@@ -229,7 +231,7 @@ describe("MatrixRTCSession", () => {
[undefined, "audio", "audio"],
["audio", "audio", "audio"],
["audio", "video", undefined],
])("gets correct consensus for %s + %s = %s", (intentA, intentB, result) => {
])("gets correct consensus for %s + %s = %s", async (intentA, intentB, result) => {
jest.useFakeTimers();
jest.setSystemTime(4000);
const mockRoom = makeMockRoom([
@@ -237,7 +239,7 @@ describe("MatrixRTCSession", () => {
Object.assign({}, membershipTemplate, { "m.call.intent": intentB }),
]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess.getConsensusCallIntent()).toEqual(result);
jest.useRealTimers();
});
@@ -249,7 +251,7 @@ describe("MatrixRTCSession", () => {
livekit_service_url: "https://active.url",
livekit_alias: "!active:active.url",
};
it("gets the correct active focus with oldest_membership", () => {
it("gets the correct active focus with oldest_membership", async () => {
jest.useFakeTimers();
jest.setSystemTime(3000);
const mockRoom = makeMockRoom([
@@ -262,7 +264,7 @@ describe("MatrixRTCSession", () => {
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
type: "livekit",
@@ -273,7 +275,7 @@ describe("MatrixRTCSession", () => {
);
jest.useRealTimers();
});
it("does not provide focus if the selection method is unknown", () => {
it("does not provide focus if the selection method is unknown", async () => {
const mockRoom = makeMockRoom([
Object.assign({}, membershipTemplate, {
device_id: "foo",
@@ -284,7 +286,7 @@ describe("MatrixRTCSession", () => {
Object.assign({}, membershipTemplate, { device_id: "bar", created_ts: 2000 }),
]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess.joinRoomSession([{ type: "livekit", livekit_service_url: "htts://test.org" }], {
type: "livekit",
@@ -300,7 +302,7 @@ describe("MatrixRTCSession", () => {
let sendStateEventMock: jest.Mock;
let sentStateEvent: Promise<void>;
beforeEach(() => {
beforeEach(async () => {
sentStateEvent = new Promise((resolve) => {
sendStateEventMock = jest.fn(resolve);
});
@@ -311,7 +313,7 @@ describe("MatrixRTCSession", () => {
client._unstable_updateDelayedEvent = jest.fn();
mockRoom = makeMockRoom([]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
});
afterEach(async () => {
@@ -347,8 +349,14 @@ describe("MatrixRTCSession", () => {
sess!.joinRoomSession([mockFocus], mockFocus, { notificationType: "ring" });
await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 5000))]);
const { resolve: r, promise: p } = Promise.withResolvers();
sess?.once(MatrixRTCSessionEvent.JoinStateChanged, r);
await p;
mockRoomState(mockRoom, [{ ...membershipTemplate, user_id: client.getUserId()! }]);
sess!.onRTCSessionMemberUpdate();
const { resolve, promise } = Promise.withResolvers();
sess?.once(MatrixRTCSessionEvent.MembershipsChanged, resolve);
await promise;
const ownMembershipId = sess?.memberships[0].eventId;
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.RTCNotification, {
@@ -361,7 +369,6 @@ describe("MatrixRTCSession", () => {
"lifetime": 30000,
"sender_ts": expect.any(Number),
});
// Check if deprecated notify event is also sent.
expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.CallNotify, {
"application": "m.call",
@@ -498,9 +505,9 @@ describe("MatrixRTCSession", () => {
});
describe("onMembershipsChanged", () => {
it("does not emit if no membership changes", () => {
it("does not emit if no membership changes", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const onMembershipsChanged = jest.fn();
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
@@ -509,9 +516,9 @@ describe("MatrixRTCSession", () => {
expect(onMembershipsChanged).not.toHaveBeenCalled();
});
it("emits on membership changes", () => {
it("emits on membership changes", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const onMembershipsChanged = jest.fn();
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
@@ -555,7 +562,7 @@ describe("MatrixRTCSession", () => {
let sendEventMock: jest.Mock;
let sendToDeviceMock: jest.Mock;
beforeEach(() => {
beforeEach(async () => {
sendStateEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
sendDelayedStateMock = jest.fn().mockResolvedValue({ event_id: "id" });
sendEventMock = jest.fn().mockResolvedValue({ event_id: "id" });
@@ -566,7 +573,7 @@ describe("MatrixRTCSession", () => {
client.encryptAndSendToDevice = sendToDeviceMock;
mockRoom = makeMockRoom([]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
});
afterEach(async () => {
@@ -685,7 +692,7 @@ describe("MatrixRTCSession", () => {
device_id: "BBBBBBB",
});
const mockRoom = makeMockRoom([membershipTemplate, member2]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
// joining will trigger an initial key send
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
@@ -734,7 +741,7 @@ describe("MatrixRTCSession", () => {
jest.useFakeTimers();
try {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const keysSentPromise1 = new Promise<EncryptionKeysEventContent>((resolve) => {
sendEventMock.mockImplementation((_roomId, _evType, payload) => resolve(payload));
@@ -785,7 +792,7 @@ describe("MatrixRTCSession", () => {
const mockRoom = makeMockRoom([member1, member2]);
mockRoomState(mockRoom, [member1, member2]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
await keysSentPromise1;
@@ -830,7 +837,7 @@ describe("MatrixRTCSession", () => {
};
const mockRoom = makeMockRoom([member1, member2]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
await keysSentPromise1;
@@ -894,7 +901,7 @@ describe("MatrixRTCSession", () => {
device_id: "BBBBBBB",
});
const mockRoom = makeMockRoom([membershipTemplate, member2]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const onMyEncryptionKeyChanged = jest.fn();
sess.on(
@@ -984,7 +991,7 @@ describe("MatrixRTCSession", () => {
if (i === 0) {
// if first time around then set up the session
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
} else {
// otherwise update the state reducing the membership each time in order to trigger key rotation
@@ -1010,7 +1017,7 @@ describe("MatrixRTCSession", () => {
jest.useFakeTimers();
try {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
const keysSentPromise1 = new Promise((resolve) => {
sendEventMock.mockImplementation(resolve);
@@ -1051,7 +1058,7 @@ describe("MatrixRTCSession", () => {
});
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, {
manageMediaKeys: true,
@@ -1074,7 +1081,7 @@ describe("MatrixRTCSession", () => {
describe("receiving", () => {
it("collects keys from encryption events", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
@@ -1099,7 +1106,7 @@ describe("MatrixRTCSession", () => {
it("collects keys at non-zero indices", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
@@ -1125,7 +1132,7 @@ describe("MatrixRTCSession", () => {
it("collects keys by merging", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
makeMockEvent("io.element.call.encryption_keys", "@bob:example.org", "1234roomId", {
@@ -1176,7 +1183,7 @@ describe("MatrixRTCSession", () => {
it("ignores older keys at same index", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
makeMockEvent(
@@ -1235,7 +1242,7 @@ describe("MatrixRTCSession", () => {
it("key timestamps are treated as monotonic", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
makeMockEvent(
@@ -1277,9 +1284,9 @@ describe("MatrixRTCSession", () => {
);
});
it("ignores keys event for the local participant", () => {
it("ignores keys event for the local participant", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
mockRoom.emitTimelineEvent(
@@ -1302,7 +1309,7 @@ describe("MatrixRTCSession", () => {
jest.useFakeTimers();
try {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
// defaults to getTs()
jest.setSystemTime(1000);
@@ -1356,9 +1363,9 @@ describe("MatrixRTCSession", () => {
});
});
describe("read status", () => {
it("returns the correct probablyLeft status", () => {
it("returns the correct probablyLeft status", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess!.probablyLeft).toBe(undefined);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });
@@ -1372,9 +1379,9 @@ describe("MatrixRTCSession", () => {
expect(sess!.probablyLeft).toBe(true);
});
it("returns membershipStatus once joinRoomSession got called", () => {
it("returns membershipStatus once joinRoomSession got called", async () => {
const mockRoom = makeMockRoom([membershipTemplate]);
sess = MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
sess = await MatrixRTCSession.sessionForRoom(client, mockRoom, callSession);
expect(sess!.membershipStatus).toBe(undefined);
sess!.joinRoomSession([mockFocus], mockFocus, { manageMediaKeys: true });

View File

@@ -17,6 +17,7 @@ limitations under the License.
import { type Logger, logger as rootLogger } from "../logger.ts";
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
import { EventTimeline } from "../models/event-timeline.ts";
import { MatrixEvent } from "../models/event.ts";
import { type Room } from "../models/room.ts";
import { type MatrixClient } from "../client.ts";
import { EventType, RelationType } from "../@types/event.ts";
@@ -50,7 +51,6 @@ import {
} from "./RoomAndToDeviceKeyTransport.ts";
import { TypedReEmitter } from "../ReEmitter.ts";
import { ToDeviceKeyTransport } from "./ToDeviceKeyTransport.ts";
import { MatrixEvent } from "../models/event.ts";
/**
* Events emitted by MatrixRTCSession
@@ -311,8 +311,9 @@ export class MatrixRTCSession extends TypedEventEmitter<
*/
public static async callMembershipsForRoom(
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
client: Pick<MatrixClient, "fetchRoomEvent">,
): Promise<CallMembership[]> {
return await MatrixRTCSession.sessionMembershipsForSlot(room, {
return await MatrixRTCSession.sessionMembershipsForSlot(room, client, {
id: "",
application: "m.call",
});
@@ -323,9 +324,10 @@ export class MatrixRTCSession extends TypedEventEmitter<
*/
public static async sessionMembershipsForRoom(
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
client: Pick<MatrixClient, "fetchRoomEvent">,
sessionDescription: SlotDescription,
): Promise<CallMembership[]> {
return await this.sessionMembershipsForSlot(room, sessionDescription);
return await this.sessionMembershipsForSlot(room, client, sessionDescription);
}
/**
@@ -334,6 +336,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
*/
public static async sessionMembershipsForSlot(
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState" | "findEventById" | "client">,
client: Pick<MatrixClient, "fetchRoomEvent">,
slotDescription: SlotDescription,
existingMemberships?: CallMembership[],
): Promise<CallMembership[]> {
@@ -350,9 +353,18 @@ export class MatrixRTCSession extends TypedEventEmitter<
let membership = existingMemberships?.find((m) => m.eventId === memberEvent.getId());
if (!membership) {
const relatedEventId = memberEvent.relationEventId;
const getRelatedMatrixEvent = async (): Promise<MatrixEvent | undefined> => {
const eventData = await client
.fetchRoomEvent(room.roomId, relatedEventId!)
.catch((e) =>
logger.error(`Could not get related event ${relatedEventId} for call membership`, e),
);
return eventData ? new MatrixEvent(eventData) : undefined;
};
const relatedEvent = relatedEventId
? room.findEventById(relatedEventId)
: new MatrixEvent(await room.client.fetchRoomEvent(room.roomId, relatedEventId!));
: await getRelatedMatrixEvent();
try {
membership = new CallMembership(memberEvent, relatedEvent);
@@ -403,7 +415,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
* @deprecated Use `MatrixRTCSession.sessionForSlot` with sessionDescription `{ id: "", application: "m.call" }` instead.
*/
public static async roomSessionForRoom(client: MatrixClient, room: Room): Promise<MatrixRTCSession> {
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, {
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, client, {
id: "",
application: "m.call",
});
@@ -413,7 +425,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
/**
* @deprecated Use `MatrixRTCSession.sessionForSlot` instead.
*/
public static async sessionForRoom(
public static sessionForRoom(
client: MatrixClient,
room: Room,
slotDescription: SlotDescription,
@@ -431,7 +443,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
room: Room,
slotDescription: SlotDescription,
): Promise<MatrixRTCSession> {
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, slotDescription);
const callMemberships = await MatrixRTCSession.sessionMembershipsForSlot(room, client, slotDescription);
return new MatrixRTCSession(client, room, callMemberships, slotDescription);
}
@@ -472,6 +484,7 @@ export class MatrixRTCSession extends TypedEventEmitter<
| "off"
| "on"
| "decryptEventIfNeeded"
| "fetchRoomEvent"
>,
private roomSubset: Pick<
Room,
@@ -784,14 +797,14 @@ export class MatrixRTCSession extends TypedEventEmitter<
* Call this when the Matrix room members have changed.
*/
public onRoomMemberUpdate = (): void => {
this.recalculateSessionMembers();
void this.recalculateSessionMembers();
};
/**
* Call this when something changed that may impacts the current MatrixRTC members in this session.
*/
public onRTCSessionMemberUpdate = (): void => {
this.recalculateSessionMembers();
void this.recalculateSessionMembers();
};
/**
@@ -801,52 +814,54 @@ export class MatrixRTCSession extends TypedEventEmitter<
*
* This function should be called when the room members or call memberships might have changed.
*/
private recalculateSessionMembers = (): void => {
private recalculateSessionMembers = async (): Promise<void> => {
const oldMemberships = this.memberships;
void MatrixRTCSession.sessionMembershipsForSlot(this.room, this.slotDescription, oldMemberships).then(
(newMemberships) => {
this.memberships = newMemberships;
this._slotId = this._slotId ?? this.memberships[0]?.slotId;
const changed =
oldMemberships.length != this.memberships.length ||
// If they have the same length, this is enough to check "changed"
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
if (changed) {
this.logger.info(
`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting (${this.memberships.length} members)`,
);
logDurationSync(this.logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
});
void this.membershipManager?.onRTCSessionMemberUpdate(this.memberships);
// The `ownMembership` will be set when calling `onRTCSessionMemberUpdate`.
const ownMembership = this.membershipManager?.ownMembership;
if (this.pendingNotificationToSend && ownMembership && oldMemberships.length === 0) {
// If we're the first member in the call, we're responsible for
// sending the notification event
if (ownMembership.eventId && this.joinConfig?.notificationType) {
this.sendCallNotify(
ownMembership.eventId,
this.joinConfig.notificationType,
ownMembership.callIntent,
);
} else {
this.logger.warn("Own membership eventId is undefined, cannot send call notification");
}
}
// If anyone else joins the session it is no longer our responsibility to send the notification.
// (If we were the joiner we already did sent the notification in the block above.)
if (this.memberships.length > 0) this.pendingNotificationToSend = undefined;
}
// This also needs to be done if `changed` = false
// A member might have updated their fingerprint (created_ts)
void this.encryptionManager?.onMembershipsUpdate(oldMemberships);
this.setExpiryTimer();
},
const newMemberships = await MatrixRTCSession.sessionMembershipsForSlot(
this.room,
this.client,
this.slotDescription,
oldMemberships,
);
this.memberships = newMemberships;
this._slotId = this._slotId ?? this.memberships[0]?.slotId;
const changed =
oldMemberships.length != this.memberships.length ||
// If they have the same length, this is enough to check "changed"
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
if (changed) {
this.logger.info(
`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting (${this.memberships.length} members)`,
);
logDurationSync(this.logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
});
void this.membershipManager?.onRTCSessionMemberUpdate(this.memberships);
// The `ownMembership` will be set when calling `onRTCSessionMemberUpdate`.
const ownMembership = this.membershipManager?.ownMembership;
if (this.pendingNotificationToSend && ownMembership && oldMemberships.length === 0) {
// If we're the first member in the call, we're responsible for
// sending the notification event
if (ownMembership.eventId && this.joinConfig?.notificationType) {
this.sendCallNotify(
ownMembership.eventId,
this.joinConfig.notificationType,
ownMembership.callIntent,
);
} else {
this.logger.warn("Own membership eventId is undefined, cannot send call notification");
}
}
// If anyone else joins the session it is no longer our responsibility to send the notification.
// (If we were the joiner we already did sent the notification in the block above.)
if (this.memberships.length > 0) this.pendingNotificationToSend = undefined;
}
// This also needs to be done if `changed` = false
// A member might have updated their fingerprint (created_ts)
void this.encryptionManager?.onMembershipsUpdate(oldMemberships);
this.setExpiryTimer();
};
}

View File

@@ -62,11 +62,11 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
this.logger = rootLogger.getChild("[MatrixRTCSessionManager]");
}
public start(): void {
public async start(): Promise<void> {
// We shouldn't need to null-check here, but matrix-client.spec.ts mocks getRooms
// returning nothing, and breaks tests if you change it to return an empty array :'(
for (const room of this.client.getRooms() ?? []) {
const session = MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription);
const session = await MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription);
if (session.memberships.length > 0) {
this.roomSessions.set(room.roomId, session);
}
@@ -98,11 +98,11 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
* Gets the main MatrixRTC session for a room, returning an empty session
* if no members are currently participating
*/
public getRoomSession(room: Room): MatrixRTCSession {
public async getRoomSession(room: Room): Promise<MatrixRTCSession> {
if (!this.roomSessions.has(room.roomId)) {
this.roomSessions.set(
room.roomId,
MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription),
await MatrixRTCSession.sessionForRoom(this.client, room, this.sessionDescription),
);
}
@@ -110,7 +110,7 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
}
private onRoom = (room: Room): void => {
this.refreshRoom(room);
void this.refreshRoom(room);
};
private onRoomState = (event: MatrixEvent, _state: RoomState): void => {
@@ -121,13 +121,13 @@ export class MatrixRTCSessionManager extends TypedEventEmitter<MatrixRTCSessionM
}
if (event.getType() == EventType.GroupCallMemberPrefix) {
this.refreshRoom(room);
void this.refreshRoom(room);
}
};
private refreshRoom(room: Room): void {
private async refreshRoom(room: Room): Promise<void> {
const isNewSession = !this.roomSessions.has(room.roomId);
const session = this.getRoomSession(room);
const session = await this.getRoomSession(room);
const wasActiveAndKnown = session.memberships.length > 0 && !isNewSession;
// This needs to be here and the event listener cannot be setup in the MatrixRTCSession,