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
Make logging consistent for matrixRTC (#4788)
* Consistent RTC logging * tests: Add more RTC key transport tests * test: improve rtc key room transport test * fixup: missing mock * rtc: more tests * coverage trick --------- Co-authored-by: Valere <bill.carson@valrsoft.com>
This commit is contained in:
@@ -993,6 +993,7 @@ describe("MatrixRTCSession", () => {
|
|||||||
|
|
||||||
sess!.joinRoomSession([mockFocus], mockFocus, {
|
sess!.joinRoomSession([mockFocus], mockFocus, {
|
||||||
manageMediaKeys: true,
|
manageMediaKeys: true,
|
||||||
|
useNewMembershipManager: true,
|
||||||
useExperimentalToDeviceTransport: true,
|
useExperimentalToDeviceTransport: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -31,6 +31,7 @@ import { LegacyMembershipManager } from "../../../src/matrixrtc/LegacyMembership
|
|||||||
import { makeMockClient, makeMockRoom, membershipTemplate, mockCallMembership, type MockClient } from "./mocks";
|
import { makeMockClient, makeMockRoom, membershipTemplate, mockCallMembership, type MockClient } from "./mocks";
|
||||||
import { MembershipManager } from "../../../src/matrixrtc/NewMembershipManager";
|
import { MembershipManager } from "../../../src/matrixrtc/NewMembershipManager";
|
||||||
import { defer } from "../../../src/utils";
|
import { defer } from "../../../src/utils";
|
||||||
|
import { logger } from "../../../src/logger.ts";
|
||||||
|
|
||||||
function waitForMockCall(method: MockedFunction<any>, returnVal?: Promise<any>) {
|
function waitForMockCall(method: MockedFunction<any>, returnVal?: Promise<any>) {
|
||||||
return new Promise<void>((resolve) => {
|
return new Promise<void>((resolve) => {
|
||||||
@@ -763,3 +764,19 @@ describe.each([
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("Should prefix log with MembershipManager used", () => {
|
||||||
|
const client = makeMockClient("@alice:example.org", "AAAAAAA");
|
||||||
|
const room = makeMockRoom(membershipTemplate);
|
||||||
|
|
||||||
|
const membershipManager = new MembershipManager(undefined, room, client, () => undefined, logger);
|
||||||
|
|
||||||
|
const spy = jest.spyOn(console, "error");
|
||||||
|
// Double join
|
||||||
|
membershipManager.join([]);
|
||||||
|
membershipManager.join([]);
|
||||||
|
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
|
const logline: string = spy.mock.calls[0][0];
|
||||||
|
expect(logline.startsWith("[NewMembershipManager]")).toBe(true);
|
||||||
|
});
|
||||||
|
@@ -18,7 +18,9 @@ import { makeMockEvent, makeMockRoom, membershipTemplate, makeKey } from "./mock
|
|||||||
import { RoomKeyTransport } from "../../../src/matrixrtc/RoomKeyTransport";
|
import { RoomKeyTransport } from "../../../src/matrixrtc/RoomKeyTransport";
|
||||||
import { KeyTransportEvents } from "../../../src/matrixrtc/IKeyTransport";
|
import { KeyTransportEvents } from "../../../src/matrixrtc/IKeyTransport";
|
||||||
import { EventType, MatrixClient, RoomEvent } from "../../../src";
|
import { EventType, MatrixClient, RoomEvent } from "../../../src";
|
||||||
import type { IRoomTimelineData, MatrixEvent, Room } from "../../../src";
|
import { type IRoomTimelineData, MatrixEvent, type Room } from "../../../src";
|
||||||
|
import type { Mocked } from "jest-mock";
|
||||||
|
import type { Logger } from "../../../src/logger.ts";
|
||||||
|
|
||||||
describe("RoomKeyTransport", () => {
|
describe("RoomKeyTransport", () => {
|
||||||
let client: MatrixClient;
|
let client: MatrixClient;
|
||||||
@@ -26,9 +28,17 @@ describe("RoomKeyTransport", () => {
|
|||||||
emitTimelineEvent: (event: MatrixEvent) => void;
|
emitTimelineEvent: (event: MatrixEvent) => void;
|
||||||
};
|
};
|
||||||
let transport: RoomKeyTransport;
|
let transport: RoomKeyTransport;
|
||||||
|
let mockLogger: Mocked<Logger>;
|
||||||
|
|
||||||
const onCallEncryptionMock = jest.fn();
|
const onCallEncryptionMock = jest.fn();
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
onCallEncryptionMock.mockReset();
|
onCallEncryptionMock.mockReset();
|
||||||
|
mockLogger = {
|
||||||
|
debug: jest.fn(),
|
||||||
|
warn: jest.fn(),
|
||||||
|
info: jest.fn(),
|
||||||
|
} as unknown as Mocked<Logger>;
|
||||||
|
|
||||||
const statistics = {
|
const statistics = {
|
||||||
counters: {
|
counters: {
|
||||||
roomEventEncryptionKeysSent: 0,
|
roomEventEncryptionKeysSent: 0,
|
||||||
@@ -41,7 +51,9 @@ describe("RoomKeyTransport", () => {
|
|||||||
room = makeMockRoom([membershipTemplate]);
|
room = makeMockRoom([membershipTemplate]);
|
||||||
client = new MatrixClient({ baseUrl: "base_url" });
|
client = new MatrixClient({ baseUrl: "base_url" });
|
||||||
client.matrixRTC.start();
|
client.matrixRTC.start();
|
||||||
transport = new RoomKeyTransport(room, client, statistics);
|
transport = new RoomKeyTransport(room, client, statistics, {
|
||||||
|
getChild: jest.fn().mockReturnValue(mockLogger),
|
||||||
|
} as unknown as Mocked<Logger>);
|
||||||
transport.on(KeyTransportEvents.ReceivedKeys, (...p) => {
|
transport.on(KeyTransportEvents.ReceivedKeys, (...p) => {
|
||||||
onCallEncryptionMock(...p);
|
onCallEncryptionMock(...p);
|
||||||
});
|
});
|
||||||
@@ -138,4 +150,78 @@ describe("RoomKeyTransport", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("malformed events", () => {
|
||||||
|
const MALFORMED_EVENT = [
|
||||||
|
// empty content
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
sender: "@alice:example.com",
|
||||||
|
content: {},
|
||||||
|
}),
|
||||||
|
// no sender
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
content: {
|
||||||
|
call_id: "",
|
||||||
|
keys: [makeKey(0, "testKey")],
|
||||||
|
sent_ts: Date.now(),
|
||||||
|
device_id: "AAAAAAA",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Call_id not empty string
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
sender: "@alice:example.com",
|
||||||
|
content: {
|
||||||
|
call_id: "FOO",
|
||||||
|
keys: [makeKey(0, "testKey")],
|
||||||
|
sent_ts: Date.now(),
|
||||||
|
device_id: "AAAAAAA",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// Various Malformed keys
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
sender: "@alice:example.com",
|
||||||
|
content: {
|
||||||
|
call_id: "",
|
||||||
|
keys: "FOO",
|
||||||
|
sent_ts: Date.now(),
|
||||||
|
device_id: "AAAAAAA",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
sender: "@alice:example.com",
|
||||||
|
content: {
|
||||||
|
call_id: "",
|
||||||
|
keys: [{ index: 0 }],
|
||||||
|
sent_ts: Date.now(),
|
||||||
|
device_id: "AAAAAAA",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
new MatrixEvent({
|
||||||
|
type: EventType.CallEncryptionKeysPrefix,
|
||||||
|
sender: "@alice:example.com",
|
||||||
|
content: {
|
||||||
|
call_id: "",
|
||||||
|
keys: [
|
||||||
|
{
|
||||||
|
key: "BASE64KEY",
|
||||||
|
index: "mcall",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sent_ts: Date.now(),
|
||||||
|
device_id: "AAAAAAA",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
test.each(MALFORMED_EVENT)("should warn on malformed event %j", (event) => {
|
||||||
|
transport.onEncryptionEvent(event);
|
||||||
|
expect(mockLogger.warn).toHaveBeenCalled();
|
||||||
|
expect(onCallEncryptionMock).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -205,31 +205,31 @@ describe("ToDeviceKeyTransport", () => {
|
|||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
keys: { keys: "ABCDEF" },
|
keys: { key: "ABCDEF" },
|
||||||
member: { claimed_device_id: "MYDEVICE" },
|
member: { claimed_device_id: "MYDEVICE" },
|
||||||
room_id: "!room:id",
|
room_id: "!room:id",
|
||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
keys: { keys: "ABCDEF", index: 2 },
|
keys: { key: "ABCDEF", index: 2 },
|
||||||
room_id: "!room:id",
|
room_id: "!room:id",
|
||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
keys: { keys: "ABCDEF", index: 2 },
|
keys: { key: "ABCDEF", index: 2 },
|
||||||
member: {},
|
member: {},
|
||||||
room_id: "!room:id",
|
room_id: "!room:id",
|
||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
keys: { keys: "ABCDEF", index: 2 },
|
keys: { key: "ABCDEF", index: 2 },
|
||||||
member: { claimed_device_id: "MYDEVICE" },
|
member: { claimed_device_id: "MYDEVICE" },
|
||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
keys: { keys: "ABCDEF", index: 2 },
|
keys: { key: "ABCDEF", index: 2 },
|
||||||
member: { claimed_device_id: "MYDEVICE" },
|
member: { claimed_device_id: "MYDEVICE" },
|
||||||
room_id: "!room:id",
|
room_id: "!wrong_room",
|
||||||
session: { application: "m.call", call_id: "", scope: "m.room" },
|
session: { application: "m.call", call_id: "", scope: "m.room" },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -29,7 +29,7 @@ It is very specific to the MembershipManager.spec.ts file and introduces the fol
|
|||||||
import { TestEnvironment } from "jest-environment-jsdom";
|
import { TestEnvironment } from "jest-environment-jsdom";
|
||||||
|
|
||||||
import { logger as rootLogger } from "../../../src/logger";
|
import { logger as rootLogger } from "../../../src/logger";
|
||||||
const logger = rootLogger.getChild("MatrixRTCSession");
|
const logger = rootLogger.getChild("[MatrixRTCSession]");
|
||||||
|
|
||||||
class MemberManagerTestEnvironment extends TestEnvironment {
|
class MemberManagerTestEnvironment extends TestEnvironment {
|
||||||
handleTestEvent(event: any) {
|
handleTestEvent(event: any) {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { logger as rootLogger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import { type EncryptionConfig } from "./MatrixRTCSession.ts";
|
import { type EncryptionConfig } from "./MatrixRTCSession.ts";
|
||||||
import { secureRandomBase64Url } from "../randomstring.ts";
|
import { secureRandomBase64Url } from "../randomstring.ts";
|
||||||
import { decodeBase64, encodeUnpaddedBase64 } from "../base64.ts";
|
import { decodeBase64, encodeUnpaddedBase64 } from "../base64.ts";
|
||||||
@@ -7,8 +7,6 @@ import { type CallMembership } from "./CallMembership.ts";
|
|||||||
import { type KeyTransportEventListener, KeyTransportEvents, type IKeyTransport } from "./IKeyTransport.ts";
|
import { type KeyTransportEventListener, KeyTransportEvents, type IKeyTransport } from "./IKeyTransport.ts";
|
||||||
import { isMyMembership, type Statistics } from "./types.ts";
|
import { isMyMembership, type Statistics } from "./types.ts";
|
||||||
|
|
||||||
const logger = rootLogger.getChild("MatrixRTCSession");
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface is for testing and for making it possible to interchange the encryption manager.
|
* This interface is for testing and for making it possible to interchange the encryption manager.
|
||||||
* @internal
|
* @internal
|
||||||
@@ -78,7 +76,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
|
|
||||||
private latestGeneratedKeyIndex = -1;
|
private latestGeneratedKeyIndex = -1;
|
||||||
private joinConfig: EncryptionConfig | undefined;
|
private joinConfig: EncryptionConfig | undefined;
|
||||||
|
private logger: Logger;
|
||||||
public constructor(
|
public constructor(
|
||||||
private userId: string,
|
private userId: string,
|
||||||
private deviceId: string,
|
private deviceId: string,
|
||||||
@@ -90,7 +88,10 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
encryptionKeyIndex: number,
|
encryptionKeyIndex: number,
|
||||||
participantId: string,
|
participantId: string,
|
||||||
) => void,
|
) => void,
|
||||||
) {}
|
parentLogger?: Logger,
|
||||||
|
) {
|
||||||
|
this.logger = (parentLogger ?? rootLogger).getChild(`[EncryptionManager]`);
|
||||||
|
}
|
||||||
|
|
||||||
public getEncryptionKeys(): Map<string, Array<{ key: Uint8Array; timestamp: number }>> {
|
public getEncryptionKeys(): Map<string, Array<{ key: Uint8Array; timestamp: number }>> {
|
||||||
return this.encryptionKeys;
|
return this.encryptionKeys;
|
||||||
@@ -158,11 +159,11 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
if (this.makeNewKeyTimeout) {
|
if (this.makeNewKeyTimeout) {
|
||||||
// existing rotation in progress, so let it complete
|
// existing rotation in progress, so let it complete
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`Member(s) have left: queueing sender key rotation`);
|
this.logger.debug(`Member(s) have left: queueing sender key rotation`);
|
||||||
this.makeNewKeyTimeout = setTimeout(this.onRotateKeyTimeout, this.makeKeyDelay);
|
this.makeNewKeyTimeout = setTimeout(this.onRotateKeyTimeout, this.makeKeyDelay);
|
||||||
}
|
}
|
||||||
} else if (anyJoined) {
|
} else if (anyJoined) {
|
||||||
logger.debug(`New member(s) have joined: re-sending keys`);
|
this.logger.debug(`New member(s) have joined: re-sending keys`);
|
||||||
this.requestSendCurrentKey();
|
this.requestSendCurrentKey();
|
||||||
} else if (oldFingerprints) {
|
} else if (oldFingerprints) {
|
||||||
// does it look like any of the members have updated their memberships?
|
// does it look like any of the members have updated their memberships?
|
||||||
@@ -174,7 +175,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
Array.from(oldFingerprints).some((x) => !newFingerprints.has(x)) ||
|
Array.from(oldFingerprints).some((x) => !newFingerprints.has(x)) ||
|
||||||
Array.from(newFingerprints).some((x) => !oldFingerprints.has(x));
|
Array.from(newFingerprints).some((x) => !oldFingerprints.has(x));
|
||||||
if (candidateUpdates) {
|
if (candidateUpdates) {
|
||||||
logger.debug(`Member(s) have updated/reconnected: re-sending keys to everyone`);
|
this.logger.debug(`Member(s) have updated/reconnected: re-sending keys to everyone`);
|
||||||
this.requestSendCurrentKey();
|
this.requestSendCurrentKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -190,7 +191,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
private makeNewSenderKey(delayBeforeUse = false): number {
|
private makeNewSenderKey(delayBeforeUse = false): number {
|
||||||
const encryptionKey = secureRandomBase64Url(16);
|
const encryptionKey = secureRandomBase64Url(16);
|
||||||
const encryptionKeyIndex = this.getNewEncryptionKeyIndex();
|
const encryptionKeyIndex = this.getNewEncryptionKeyIndex();
|
||||||
logger.info("Generated new key at index " + encryptionKeyIndex);
|
this.logger.info("Generated new key at index " + encryptionKeyIndex);
|
||||||
this.setEncryptionKey(
|
this.setEncryptionKey(
|
||||||
this.userId,
|
this.userId,
|
||||||
this.deviceId,
|
this.deviceId,
|
||||||
@@ -213,7 +214,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
this.lastEncryptionKeyUpdateRequest &&
|
this.lastEncryptionKeyUpdateRequest &&
|
||||||
this.lastEncryptionKeyUpdateRequest + this.updateEncryptionKeyThrottle > Date.now()
|
this.lastEncryptionKeyUpdateRequest + this.updateEncryptionKeyThrottle > Date.now()
|
||||||
) {
|
) {
|
||||||
logger.info("Last encryption key event sent too recently: postponing");
|
this.logger.info("Last encryption key event sent too recently: postponing");
|
||||||
if (this.keysEventUpdateTimeout === undefined) {
|
if (this.keysEventUpdateTimeout === undefined) {
|
||||||
this.keysEventUpdateTimeout = setTimeout(
|
this.keysEventUpdateTimeout = setTimeout(
|
||||||
() => void this.sendEncryptionKeysEvent(),
|
() => void this.sendEncryptionKeysEvent(),
|
||||||
@@ -252,18 +253,18 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
const myKeys = this.getKeysForParticipant(this.userId, this.deviceId);
|
const myKeys = this.getKeysForParticipant(this.userId, this.deviceId);
|
||||||
|
|
||||||
if (!myKeys) {
|
if (!myKeys) {
|
||||||
logger.warn("Tried to send encryption keys event but no keys found!");
|
this.logger.warn("Tried to send encryption keys event but no keys found!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof indexToSend !== "number" && this.latestGeneratedKeyIndex === -1) {
|
if (typeof indexToSend !== "number" && this.latestGeneratedKeyIndex === -1) {
|
||||||
logger.warn("Tried to send encryption keys event but no current key index found!");
|
this.logger.warn("Tried to send encryption keys event but no current key index found!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const keyIndexToSend = indexToSend ?? this.latestGeneratedKeyIndex;
|
const keyIndexToSend = indexToSend ?? this.latestGeneratedKeyIndex;
|
||||||
|
|
||||||
logger.info(
|
this.logger.info(
|
||||||
`Try sending encryption keys event. keyIndexToSend=${keyIndexToSend} (method parameter: ${indexToSend})`,
|
`Try sending encryption keys event. keyIndexToSend=${keyIndexToSend} (method parameter: ${indexToSend})`,
|
||||||
);
|
);
|
||||||
const keyToSend = myKeys[keyIndexToSend];
|
const keyToSend = myKeys[keyIndexToSend];
|
||||||
@@ -271,23 +272,23 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
try {
|
try {
|
||||||
this.statistics.counters.roomEventEncryptionKeysSent += 1;
|
this.statistics.counters.roomEventEncryptionKeysSent += 1;
|
||||||
await this.transport.sendKey(encodeUnpaddedBase64(keyToSend), keyIndexToSend, this.getMemberships());
|
await this.transport.sendKey(encodeUnpaddedBase64(keyToSend), keyIndexToSend, this.getMemberships());
|
||||||
logger.debug(
|
this.logger.debug(
|
||||||
`sendEncryptionKeysEvent participantId=${this.userId}:${this.deviceId} numKeys=${myKeys.length} currentKeyIndex=${this.latestGeneratedKeyIndex} keyIndexToSend=${keyIndexToSend}`,
|
`sendEncryptionKeysEvent participantId=${this.userId}:${this.deviceId} numKeys=${myKeys.length} currentKeyIndex=${this.latestGeneratedKeyIndex} keyIndexToSend=${keyIndexToSend}`,
|
||||||
this.encryptionKeys,
|
this.encryptionKeys,
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (this.keysEventUpdateTimeout === undefined) {
|
if (this.keysEventUpdateTimeout === undefined) {
|
||||||
const resendDelay = safeGetRetryAfterMs(error, 5000);
|
const resendDelay = safeGetRetryAfterMs(error, 5000);
|
||||||
logger.warn(`Failed to send m.call.encryption_key, retrying in ${resendDelay}`, error);
|
this.logger.warn(`Failed to send m.call.encryption_key, retrying in ${resendDelay}`, error);
|
||||||
this.keysEventUpdateTimeout = setTimeout(() => void this.sendEncryptionKeysEvent(), resendDelay);
|
this.keysEventUpdateTimeout = setTimeout(() => void this.sendEncryptionKeysEvent(), resendDelay);
|
||||||
} else {
|
} else {
|
||||||
logger.info("Not scheduling key resend as another re-send is already pending");
|
this.logger.info("Not scheduling key resend as another re-send is already pending");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public onNewKeyReceived: KeyTransportEventListener = (userId, deviceId, keyBase64Encoded, index, timestamp) => {
|
public onNewKeyReceived: KeyTransportEventListener = (userId, deviceId, keyBase64Encoded, index, timestamp) => {
|
||||||
logger.debug(`Received key over key transport ${userId}:${deviceId} at index ${index}`);
|
this.logger.debug(`Received key over key transport ${userId}:${deviceId} at index ${index}`);
|
||||||
this.setEncryptionKey(userId, deviceId, index, keyBase64Encoded, timestamp);
|
this.setEncryptionKey(userId, deviceId, index, keyBase64Encoded, timestamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -330,7 +331,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
timestamp: number,
|
timestamp: number,
|
||||||
delayBeforeUse = false,
|
delayBeforeUse = false,
|
||||||
): void {
|
): void {
|
||||||
logger.debug(`Setting encryption key for ${userId}:${deviceId} at index ${encryptionKeyIndex}`);
|
this.logger.debug(`Setting encryption key for ${userId}:${deviceId} at index ${encryptionKeyIndex}`);
|
||||||
const keyBin = decodeBase64(encryptionKeyString);
|
const keyBin = decodeBase64(encryptionKeyString);
|
||||||
|
|
||||||
const participantId = getParticipantId(userId, deviceId);
|
const participantId = getParticipantId(userId, deviceId);
|
||||||
@@ -343,7 +344,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
|
|
||||||
if (existingKeyAtIndex) {
|
if (existingKeyAtIndex) {
|
||||||
if (existingKeyAtIndex.timestamp > timestamp) {
|
if (existingKeyAtIndex.timestamp > timestamp) {
|
||||||
logger.info(
|
this.logger.info(
|
||||||
`Ignoring new key at index ${encryptionKeyIndex} for ${participantId} as it is older than existing known key`,
|
`Ignoring new key at index ${encryptionKeyIndex} for ${participantId} as it is older than existing known key`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -372,7 +373,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
if (delayBeforeUse) {
|
if (delayBeforeUse) {
|
||||||
const useKeyTimeout = setTimeout(() => {
|
const useKeyTimeout = setTimeout(() => {
|
||||||
this.setNewKeyTimeouts.delete(useKeyTimeout);
|
this.setNewKeyTimeouts.delete(useKeyTimeout);
|
||||||
logger.info(`Delayed-emitting key changed event for ${participantId} index ${encryptionKeyIndex}`);
|
this.logger.info(`Delayed-emitting key changed event for ${participantId} index ${encryptionKeyIndex}`);
|
||||||
|
|
||||||
this.onEncryptionKeysChanged(keyBin, encryptionKeyIndex, participantId);
|
this.onEncryptionKeysChanged(keyBin, encryptionKeyIndex, participantId);
|
||||||
}, this.useKeyDelay);
|
}, this.useKeyDelay);
|
||||||
@@ -386,7 +387,7 @@ export class EncryptionManager implements IEncryptionManager {
|
|||||||
if (!this.manageMediaKeys) return;
|
if (!this.manageMediaKeys) return;
|
||||||
|
|
||||||
this.makeNewKeyTimeout = undefined;
|
this.makeNewKeyTimeout = undefined;
|
||||||
logger.info("Making new sender key for key rotation");
|
this.logger.info("Making new sender key for key rotation");
|
||||||
const newKeyIndex = this.makeNewSenderKey(true);
|
const newKeyIndex = this.makeNewSenderKey(true);
|
||||||
// send immediately: if we're about to start sending with a new key, it's
|
// send immediately: if we're about to start sending with a new key, it's
|
||||||
// important we get it out to others as soon as we can.
|
// important we get it out to others as soon as we can.
|
||||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { logger as rootLogger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
||||||
import { EventTimeline } from "../models/event-timeline.ts";
|
import { EventTimeline } from "../models/event-timeline.ts";
|
||||||
import { type Room } from "../models/room.ts";
|
import { type Room } from "../models/room.ts";
|
||||||
@@ -33,8 +33,6 @@ import { type Statistics } from "./types.ts";
|
|||||||
import { RoomKeyTransport } from "./RoomKeyTransport.ts";
|
import { RoomKeyTransport } from "./RoomKeyTransport.ts";
|
||||||
import type { IMembershipManager } from "./IMembershipManager.ts";
|
import type { IMembershipManager } from "./IMembershipManager.ts";
|
||||||
|
|
||||||
const logger = rootLogger.getChild("MatrixRTCSession");
|
|
||||||
|
|
||||||
export enum MatrixRTCSessionEvent {
|
export enum MatrixRTCSessionEvent {
|
||||||
// A member joined, left, or updated a property of their membership.
|
// A member joined, left, or updated a property of their membership.
|
||||||
MembershipsChanged = "memberships_changed",
|
MembershipsChanged = "memberships_changed",
|
||||||
@@ -169,7 +167,7 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
private encryptionManager?: IEncryptionManager;
|
private encryptionManager?: IEncryptionManager;
|
||||||
// The session Id of the call, this is the call_id of the call Member event.
|
// The session Id of the call, this is the call_id of the call Member event.
|
||||||
private _callId: string | undefined;
|
private _callId: string | undefined;
|
||||||
|
private logger: Logger;
|
||||||
/**
|
/**
|
||||||
* This timeout is responsible to track any expiration. We need to know when we have to start
|
* This timeout is responsible to track any expiration. We need to know when we have to start
|
||||||
* to ignore other call members. There is no callback for this. This timeout will always be configured to
|
* to ignore other call members. There is no callback for this. This timeout will always be configured to
|
||||||
@@ -206,6 +204,7 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
public static callMembershipsForRoom(
|
public static callMembershipsForRoom(
|
||||||
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState">,
|
room: Pick<Room, "getLiveTimeline" | "roomId" | "hasMembershipState">,
|
||||||
): CallMembership[] {
|
): CallMembership[] {
|
||||||
|
const logger = rootLogger.getChild(`[MatrixRTCSession ${room.roomId}]`);
|
||||||
const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
const roomState = room.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
||||||
if (!roomState) {
|
if (!roomState) {
|
||||||
logger.warn("Couldn't get state for room " + room.roomId);
|
logger.warn("Couldn't get state for room " + room.roomId);
|
||||||
@@ -321,6 +320,7 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
public memberships: CallMembership[],
|
public memberships: CallMembership[],
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this.logger = rootLogger.getChild(`[MatrixRTCSession ${roomSubset.roomId}]`);
|
||||||
this._callId = memberships[0]?.callId;
|
this._callId = memberships[0]?.callId;
|
||||||
const roomState = this.roomSubset.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
const roomState = this.roomSubset.getLiveTimeline().getState(EventTimeline.FORWARDS);
|
||||||
// TODO: double check if this is actually needed. Should be covered by refreshRoom in MatrixRTCSessionManager
|
// TODO: double check if this is actually needed. Should be covered by refreshRoom in MatrixRTCSessionManager
|
||||||
@@ -365,13 +365,17 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
*/
|
*/
|
||||||
public joinRoomSession(fociPreferred: Focus[], fociActive?: Focus, joinConfig?: JoinSessionConfig): void {
|
public joinRoomSession(fociPreferred: Focus[], fociActive?: Focus, joinConfig?: JoinSessionConfig): void {
|
||||||
if (this.isJoined()) {
|
if (this.isJoined()) {
|
||||||
logger.info(`Already joined to session in room ${this.roomSubset.roomId}: ignoring join call`);
|
this.logger.info(`Already joined to session in room ${this.roomSubset.roomId}: ignoring join call`);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Create MembershipManager
|
// Create MembershipManager and pass the RTCSession logger (with room id info)
|
||||||
if (joinConfig?.useNewMembershipManager ?? false) {
|
if (joinConfig?.useNewMembershipManager ?? false) {
|
||||||
this.membershipManager = new MembershipManager(joinConfig, this.roomSubset, this.client, () =>
|
this.membershipManager = new MembershipManager(
|
||||||
this.getOldestMembership(),
|
joinConfig,
|
||||||
|
this.roomSubset,
|
||||||
|
this.client,
|
||||||
|
() => this.getOldestMembership(),
|
||||||
|
this.logger,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.membershipManager = new LegacyMembershipManager(joinConfig, this.roomSubset, this.client, () =>
|
this.membershipManager = new LegacyMembershipManager(joinConfig, this.roomSubset, this.client, () =>
|
||||||
@@ -381,14 +385,14 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
// Create Encryption manager
|
// Create Encryption manager
|
||||||
let transport;
|
let transport;
|
||||||
if (joinConfig?.useExperimentalToDeviceTransport) {
|
if (joinConfig?.useExperimentalToDeviceTransport) {
|
||||||
logger.info("Using experimental to-device transport for encryption keys");
|
this.logger.info("Using experimental to-device transport for encryption keys");
|
||||||
transport = new ToDeviceKeyTransport(
|
transport = new ToDeviceKeyTransport(
|
||||||
this.client.getUserId()!,
|
this.client.getUserId()!,
|
||||||
this.client.getDeviceId()!,
|
this.client.getDeviceId()!,
|
||||||
this.roomSubset.roomId,
|
this.roomSubset.roomId,
|
||||||
this.client,
|
this.client,
|
||||||
this.statistics,
|
this.statistics,
|
||||||
logger,
|
this.logger,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
transport = new RoomKeyTransport(this.roomSubset, this.client, this.statistics);
|
transport = new RoomKeyTransport(this.roomSubset, this.client, this.statistics);
|
||||||
@@ -402,12 +406,13 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
(keyBin: Uint8Array<ArrayBufferLike>, encryptionKeyIndex: number, participantId: string) => {
|
(keyBin: Uint8Array<ArrayBufferLike>, encryptionKeyIndex: number, participantId: string) => {
|
||||||
this.emit(MatrixRTCSessionEvent.EncryptionKeyChanged, keyBin, encryptionKeyIndex, participantId);
|
this.emit(MatrixRTCSessionEvent.EncryptionKeyChanged, keyBin, encryptionKeyIndex, participantId);
|
||||||
},
|
},
|
||||||
|
this.logger,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Join!
|
// Join!
|
||||||
this.membershipManager!.join(fociPreferred, fociActive, (e) => {
|
this.membershipManager!.join(fociPreferred, fociActive, (e) => {
|
||||||
logger.error("MembershipManager encountered an unrecoverable error: ", e);
|
this.logger.error("MembershipManager encountered an unrecoverable error: ", e);
|
||||||
this.emit(MatrixRTCSessionEvent.MembershipManagerError, e);
|
this.emit(MatrixRTCSessionEvent.MembershipManagerError, e);
|
||||||
this.emit(MatrixRTCSessionEvent.JoinStateChanged, this.isJoined());
|
this.emit(MatrixRTCSessionEvent.JoinStateChanged, this.isJoined());
|
||||||
});
|
});
|
||||||
@@ -428,11 +433,11 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
*/
|
*/
|
||||||
public async leaveRoomSession(timeout: number | undefined = undefined): Promise<boolean> {
|
public async leaveRoomSession(timeout: number | undefined = undefined): Promise<boolean> {
|
||||||
if (!this.isJoined()) {
|
if (!this.isJoined()) {
|
||||||
logger.info(`Not joined to session in room ${this.roomSubset.roomId}: ignoring leave call`);
|
this.logger.info(`Not joined to session in room ${this.roomSubset.roomId}: ignoring leave call`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(`Leaving call session in room ${this.roomSubset.roomId}`);
|
this.logger.info(`Leaving call session in room ${this.roomSubset.roomId}`);
|
||||||
|
|
||||||
this.encryptionManager!.leave();
|
this.encryptionManager!.leave();
|
||||||
|
|
||||||
@@ -553,8 +558,8 @@ export class MatrixRTCSession extends TypedEventEmitter<MatrixRTCSessionEvent, M
|
|||||||
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
|
oldMemberships.some((m, i) => !CallMembership.equal(m, this.memberships[i]));
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
logger.info(`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting`);
|
this.logger.info(`Memberships for call in room ${this.roomSubset.roomId} have changed: emitting`);
|
||||||
logDurationSync(logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
|
logDurationSync(this.logger, "emit MatrixRTCSessionEvent.MembershipsChanged", () => {
|
||||||
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
|
this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ import { type MatrixEvent } from "../models/event.ts";
|
|||||||
import { MatrixRTCSession } from "./MatrixRTCSession.ts";
|
import { MatrixRTCSession } from "./MatrixRTCSession.ts";
|
||||||
import { EventType } from "../@types/event.ts";
|
import { EventType } from "../@types/event.ts";
|
||||||
|
|
||||||
const logger = rootLogger.getChild("MatrixRTCSessionManager");
|
const logger = rootLogger.getChild("[MatrixRTCSessionManager]");
|
||||||
|
|
||||||
export enum MatrixRTCSessionManagerEvents {
|
export enum MatrixRTCSessionManagerEvents {
|
||||||
// A member has joined the MatrixRTC session, creating an active session in a room where there wasn't previously
|
// A member has joined the MatrixRTC session, creating an active session in a room where there wasn't previously
|
||||||
|
@@ -19,7 +19,7 @@ import { UpdateDelayedEventAction } from "../@types/requests.ts";
|
|||||||
import { type MatrixClient } from "../client.ts";
|
import { type MatrixClient } from "../client.ts";
|
||||||
import { UnsupportedDelayedEventsEndpointError } from "../errors.ts";
|
import { UnsupportedDelayedEventsEndpointError } from "../errors.ts";
|
||||||
import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
|
import { ConnectionError, HTTPError, MatrixError } from "../http-api/errors.ts";
|
||||||
import { logger as rootLogger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import { type Room } from "../models/room.ts";
|
import { type Room } from "../models/room.ts";
|
||||||
import { defer, type IDeferred } from "../utils.ts";
|
import { defer, type IDeferred } from "../utils.ts";
|
||||||
import { type CallMembership, DEFAULT_EXPIRE_DURATION, type SessionMembershipData } from "./CallMembership.ts";
|
import { type CallMembership, DEFAULT_EXPIRE_DURATION, type SessionMembershipData } from "./CallMembership.ts";
|
||||||
@@ -35,8 +35,6 @@ import {
|
|||||||
type MembershipManagerEventHandlerMap,
|
type MembershipManagerEventHandlerMap,
|
||||||
} from "./IMembershipManager.ts";
|
} from "./IMembershipManager.ts";
|
||||||
|
|
||||||
const logger = rootLogger.getChild("MatrixRTCSession");
|
|
||||||
|
|
||||||
/* MembershipActionTypes:
|
/* MembershipActionTypes:
|
||||||
|
|
||||||
On Join: ───────────────┐ ┌───────────────(1)───────────┐
|
On Join: ───────────────┐ ┌───────────────(1)───────────┐
|
||||||
@@ -146,6 +144,8 @@ export class MembershipManager
|
|||||||
implements IMembershipManager
|
implements IMembershipManager
|
||||||
{
|
{
|
||||||
private activated = false;
|
private activated = false;
|
||||||
|
private logger: Logger;
|
||||||
|
|
||||||
public isActivated(): boolean {
|
public isActivated(): boolean {
|
||||||
return this.activated;
|
return this.activated;
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,7 @@ export class MembershipManager
|
|||||||
*/
|
*/
|
||||||
public join(fociPreferred: Focus[], focusActive?: Focus, onError?: (error: unknown) => void): void {
|
public join(fociPreferred: Focus[], focusActive?: Focus, onError?: (error: unknown) => void): void {
|
||||||
if (this.scheduler.running) {
|
if (this.scheduler.running) {
|
||||||
logger.error("MembershipManager is already running. Ignoring join request.");
|
this.logger.error("MembershipManager is already running. Ignoring join request.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.fociPreferred = fociPreferred;
|
this.fociPreferred = fociPreferred;
|
||||||
@@ -177,7 +177,7 @@ export class MembershipManager
|
|||||||
this.scheduler
|
this.scheduler
|
||||||
.startWithJoin()
|
.startWithJoin()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
logger.error("MembershipManager stopped because: ", e);
|
this.logger.error("MembershipManager stopped because: ", e);
|
||||||
onError?.(e);
|
onError?.(e);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -201,7 +201,7 @@ export class MembershipManager
|
|||||||
*/
|
*/
|
||||||
public leave(timeout?: number): Promise<boolean> {
|
public leave(timeout?: number): Promise<boolean> {
|
||||||
if (!this.scheduler.running) {
|
if (!this.scheduler.running) {
|
||||||
logger.warn("Called MembershipManager.leave() even though the MembershipManager is not running");
|
this.logger.warn("Called MembershipManager.leave() even though the MembershipManager is not running");
|
||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,9 +228,9 @@ export class MembershipManager
|
|||||||
MembershipActionType.SendDelayedEvent,
|
MembershipActionType.SendDelayedEvent,
|
||||||
MembershipActionType.SendJoinEvent,
|
MembershipActionType.SendJoinEvent,
|
||||||
];
|
];
|
||||||
logger.warn("Missing own membership: force re-join");
|
this.logger.warn("Missing own membership: force re-join");
|
||||||
if (this.scheduler.actions.find((a) => sendingMembershipActions.includes(a.type as MembershipActionType))) {
|
if (this.scheduler.actions.find((a) => sendingMembershipActions.includes(a.type as MembershipActionType))) {
|
||||||
logger.error(
|
this.logger.error(
|
||||||
"NewMembershipManger tried adding another `SendFirstDelayedEvent` actions even though we already have one in the Queue\nActionQueueOnMemberUpdate:",
|
"NewMembershipManger tried adding another `SendFirstDelayedEvent` actions even though we already have one in the Queue\nActionQueueOnMemberUpdate:",
|
||||||
this.scheduler.actions,
|
this.scheduler.actions,
|
||||||
);
|
);
|
||||||
@@ -252,7 +252,7 @@ export class MembershipManager
|
|||||||
return oldestMembership?.getPreferredFoci()[0];
|
return oldestMembership?.getPreferredFoci()[0];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn("Unknown own ActiveFocus type. This makes it impossible to connect to an SFU.");
|
this.logger.warn("Unknown own ActiveFocus type. This makes it impossible to connect to an SFU.");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We do not understand the membership format (could be legacy). We default to oldestMembership
|
// We do not understand the membership format (could be legacy). We default to oldestMembership
|
||||||
@@ -281,16 +281,38 @@ export class MembershipManager
|
|||||||
| "_unstable_updateDelayedEvent"
|
| "_unstable_updateDelayedEvent"
|
||||||
>,
|
>,
|
||||||
private getOldestMembership: () => CallMembership | undefined,
|
private getOldestMembership: () => CallMembership | undefined,
|
||||||
|
parentLogger?: Logger,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
|
this.logger = (parentLogger ?? rootLogger).getChild(`[NewMembershipManager]`);
|
||||||
const [userId, deviceId] = [this.client.getUserId(), this.client.getDeviceId()];
|
const [userId, deviceId] = [this.client.getUserId(), this.client.getDeviceId()];
|
||||||
if (userId === null) throw Error("Missing userId in client");
|
if (userId === null) throw Error("Missing userId in client");
|
||||||
if (deviceId === null) throw Error("Missing deviceId in client");
|
if (deviceId === null) throw Error("Missing deviceId in client");
|
||||||
this.deviceId = deviceId;
|
this.deviceId = deviceId;
|
||||||
this.stateKey = this.makeMembershipStateKey(userId, deviceId);
|
this.stateKey = this.makeMembershipStateKey(userId, deviceId);
|
||||||
this.state = MembershipManager.defaultState;
|
this.state = MembershipManager.defaultState;
|
||||||
|
this.scheduler = new ActionScheduler((type): Promise<ActionUpdate> => {
|
||||||
|
if (this.oldStatus) {
|
||||||
|
// we put this at the beginning of the actions scheduler loop handle callback since it is a loop this
|
||||||
|
// is equivalent to running it at the end of the loop. (just after applying the status/action list changes)
|
||||||
|
// This order is required because this method needs to return the action updates.
|
||||||
|
this.logger.debug(
|
||||||
|
`MembershipManager applied action changes. Status: ${this.oldStatus} -> ${this.status}`,
|
||||||
|
);
|
||||||
|
if (this.oldStatus !== this.status) {
|
||||||
|
this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.oldStatus = this.status;
|
||||||
|
this.logger.debug(`MembershipManager before processing action. status=${this.oldStatus}`);
|
||||||
|
return this.membershipLoopHandler(type);
|
||||||
|
}, this.logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scheduler
|
||||||
|
private oldStatus?: Status;
|
||||||
|
private scheduler: ActionScheduler;
|
||||||
|
|
||||||
// MembershipManager mutable state.
|
// MembershipManager mutable state.
|
||||||
private state: MembershipManagerState;
|
private state: MembershipManagerState;
|
||||||
private static get defaultState(): MembershipManagerState {
|
private static get defaultState(): MembershipManagerState {
|
||||||
@@ -346,23 +368,6 @@ export class MembershipManager
|
|||||||
return this.joinConfig?.maximumNetworkErrorRetryCount ?? 10;
|
return this.joinConfig?.maximumNetworkErrorRetryCount ?? 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scheduler:
|
|
||||||
private oldStatus?: Status;
|
|
||||||
private scheduler = new ActionScheduler((type): Promise<ActionUpdate> => {
|
|
||||||
if (this.oldStatus) {
|
|
||||||
// we put this at the beginning of the actions scheduler loop handle callback since it is a loop this
|
|
||||||
// is equivalent to running it at the end of the loop. (just after applying the status/action list changes)
|
|
||||||
// This order is required because this method needs to return the action updates.
|
|
||||||
logger.debug(`MembershipManager applied action changes. Status: ${this.oldStatus} -> ${this.status}`);
|
|
||||||
if (this.oldStatus !== this.status) {
|
|
||||||
this.emit(MembershipManagerEvent.StatusChanged, this.oldStatus, this.status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.oldStatus = this.status;
|
|
||||||
logger.debug(`MembershipManager before processing action. status=${this.oldStatus}`);
|
|
||||||
return this.membershipLoopHandler(type);
|
|
||||||
});
|
|
||||||
|
|
||||||
// LOOP HANDLER:
|
// LOOP HANDLER:
|
||||||
private async membershipLoopHandler(type: MembershipActionType): Promise<ActionUpdate> {
|
private async membershipLoopHandler(type: MembershipActionType): Promise<ActionUpdate> {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@@ -468,9 +473,9 @@ export class MembershipManager
|
|||||||
// This action was scheduled because we are in the process of joining
|
// This action was scheduled because we are in the process of joining
|
||||||
// log and fall through
|
// log and fall through
|
||||||
if (this.isUnsupportedDelayedEndpoint(e)) {
|
if (this.isUnsupportedDelayedEndpoint(e)) {
|
||||||
logger.info("Not using delayed event because the endpoint is not supported");
|
this.logger.info("Not using delayed event because the endpoint is not supported");
|
||||||
} else {
|
} else {
|
||||||
logger.info("Not using delayed event because: " + e);
|
this.logger.info("Not using delayed event because: " + e);
|
||||||
}
|
}
|
||||||
// On any other error we fall back to not using delayed events and send the join state event immediately
|
// On any other error we fall back to not using delayed events and send the join state event immediately
|
||||||
return createInsertActionUpdate(MembershipActionType.SendJoinEvent);
|
return createInsertActionUpdate(MembershipActionType.SendJoinEvent);
|
||||||
@@ -561,7 +566,7 @@ export class MembershipManager
|
|||||||
if (update) return update;
|
if (update) return update;
|
||||||
|
|
||||||
// On any other error we fall back to SendLeaveEvent (this includes hard errors from rate limiting)
|
// On any other error we fall back to SendLeaveEvent (this includes hard errors from rate limiting)
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
"Encountered unexpected error during SendScheduledDelayedLeaveEvent. Falling back to SendLeaveEvent",
|
"Encountered unexpected error during SendScheduledDelayedLeaveEvent. Falling back to SendLeaveEvent",
|
||||||
e,
|
e,
|
||||||
);
|
);
|
||||||
@@ -695,7 +700,7 @@ export class MembershipManager
|
|||||||
if (typeof maxDelayAllowed === "number" && this.membershipServerSideExpiryTimeout > maxDelayAllowed) {
|
if (typeof maxDelayAllowed === "number" && this.membershipServerSideExpiryTimeout > maxDelayAllowed) {
|
||||||
this.membershipServerSideExpiryTimeoutOverride = maxDelayAllowed;
|
this.membershipServerSideExpiryTimeoutOverride = maxDelayAllowed;
|
||||||
}
|
}
|
||||||
logger.warn("Retry sending delayed disconnection event due to server timeout limitations:", error);
|
this.logger.warn("Retry sending delayed disconnection event due to server timeout limitations:", error);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -737,9 +742,9 @@ export class MembershipManager
|
|||||||
const defaultMs = 5000;
|
const defaultMs = 5000;
|
||||||
try {
|
try {
|
||||||
resendDelay = error.getRetryAfterMs() ?? defaultMs;
|
resendDelay = error.getRetryAfterMs() ?? defaultMs;
|
||||||
logger.info(`Rate limited by server, retrying in ${resendDelay}ms`);
|
this.logger.info(`Rate limited by server, retrying in ${resendDelay}ms`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
`Error while retrieving a rate-limit retry delay, retrying after default delay of ${defaultMs}`,
|
`Error while retrieving a rate-limit retry delay, retrying after default delay of ${defaultMs}`,
|
||||||
e,
|
e,
|
||||||
);
|
);
|
||||||
@@ -767,7 +772,7 @@ export class MembershipManager
|
|||||||
const retryDurationString = this.callMemberEventRetryDelayMinimum / 1000 + "s";
|
const retryDurationString = this.callMemberEventRetryDelayMinimum / 1000 + "s";
|
||||||
const retryCounterString = "(" + retries + "/" + this.maximumNetworkErrorRetryCount + ")";
|
const retryCounterString = "(" + retries + "/" + this.maximumNetworkErrorRetryCount + ")";
|
||||||
if (error instanceof Error && error.name === "AbortError") {
|
if (error instanceof Error && error.name === "AbortError") {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
"Network local timeout error while sending event, retrying in " +
|
"Network local timeout error while sending event, retrying in " +
|
||||||
retryDurationString +
|
retryDurationString +
|
||||||
" " +
|
" " +
|
||||||
@@ -785,12 +790,12 @@ export class MembershipManager
|
|||||||
//
|
//
|
||||||
// A proper fix would be to either find a place to convert the `HttpError` into a `MatrixError` and the `processError`
|
// A proper fix would be to either find a place to convert the `HttpError` into a `MatrixError` and the `processError`
|
||||||
// method to handle it as expected or to adjust `processError` to also process `HttpError`'s.
|
// method to handle it as expected or to adjust `processError` to also process `HttpError`'s.
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
"delayed event update timeout error, retrying in " + retryDurationString + " " + retryCounterString,
|
"delayed event update timeout error, retrying in " + retryDurationString + " " + retryCounterString,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
} else if (error instanceof ConnectionError) {
|
} else if (error instanceof ConnectionError) {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
"Network connection error while sending event, retrying in " +
|
"Network connection error while sending event, retrying in " +
|
||||||
retryDurationString +
|
retryDurationString +
|
||||||
" " +
|
" " +
|
||||||
@@ -803,7 +808,7 @@ export class MembershipManager
|
|||||||
error.httpStatus >= 500 &&
|
error.httpStatus >= 500 &&
|
||||||
error.httpStatus < 600
|
error.httpStatus < 600
|
||||||
) {
|
) {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
"Server error while sending event, retrying in " + retryDurationString + " " + retryCounterString,
|
"Server error while sending event, retrying in " + retryDurationString + " " + retryCounterString,
|
||||||
error,
|
error,
|
||||||
);
|
);
|
||||||
@@ -879,7 +884,7 @@ export class MembershipManager
|
|||||||
return Status.Disconnected;
|
return Status.Disconnected;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.error("MembershipManager has an unknown state. Actions: ", actions);
|
this.logger.error("MembershipManager has an unknown state. Actions: ", actions);
|
||||||
return Status.Unknown;
|
return Status.Unknown;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,10 +1,8 @@
|
|||||||
import { logger as rootLogger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import { type EmptyObject } from "../matrix.ts";
|
import { type EmptyObject } from "../matrix.ts";
|
||||||
import { sleep } from "../utils.ts";
|
import { sleep } from "../utils.ts";
|
||||||
import { MembershipActionType } from "./NewMembershipManager.ts";
|
import { MembershipActionType } from "./NewMembershipManager.ts";
|
||||||
|
|
||||||
const logger = rootLogger.getChild("MatrixRTCSession");
|
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
export interface Action {
|
export interface Action {
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +38,7 @@ export type ActionUpdate =
|
|||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export class ActionScheduler {
|
export class ActionScheduler {
|
||||||
|
private logger: Logger;
|
||||||
/**
|
/**
|
||||||
* This is tracking the state of the scheduler loop.
|
* This is tracking the state of the scheduler loop.
|
||||||
* Only used to prevent starting the loop twice.
|
* Only used to prevent starting the loop twice.
|
||||||
@@ -49,11 +48,14 @@ export class ActionScheduler {
|
|||||||
public constructor(
|
public constructor(
|
||||||
/** This is the callback called for each scheduled action (`this.addAction()`) */
|
/** This is the callback called for each scheduled action (`this.addAction()`) */
|
||||||
private membershipLoopHandler: (type: MembershipActionType) => Promise<ActionUpdate>,
|
private membershipLoopHandler: (type: MembershipActionType) => Promise<ActionUpdate>,
|
||||||
) {}
|
parentLogger?: Logger,
|
||||||
|
) {
|
||||||
|
this.logger = (parentLogger ?? rootLogger).getChild(`[NewMembershipActionScheduler]`);
|
||||||
|
}
|
||||||
|
|
||||||
// function for the wakeup mechanism (in case we add an action externally and need to leave the current sleep)
|
// function for the wakeup mechanism (in case we add an action externally and need to leave the current sleep)
|
||||||
private wakeup: (update: ActionUpdate) => void = (update: ActionUpdate): void => {
|
private wakeup: (update: ActionUpdate) => void = (update: ActionUpdate): void => {
|
||||||
logger.error("Cannot call wakeup before calling `startWithJoin()`");
|
this.logger.error("Cannot call wakeup before calling `startWithJoin()`");
|
||||||
};
|
};
|
||||||
private _actions: Action[] = [];
|
private _actions: Action[] = [];
|
||||||
public get actions(): Action[] {
|
public get actions(): Action[] {
|
||||||
@@ -69,7 +71,7 @@ export class ActionScheduler {
|
|||||||
*/
|
*/
|
||||||
public async startWithJoin(): Promise<void> {
|
public async startWithJoin(): Promise<void> {
|
||||||
if (this.running) {
|
if (this.running) {
|
||||||
logger.error("Cannot call startWithJoin() on NewMembershipActionScheduler while already running");
|
this.logger.error("Cannot call startWithJoin() on NewMembershipActionScheduler while already running");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.running = true;
|
this.running = true;
|
||||||
@@ -92,7 +94,7 @@ export class ActionScheduler {
|
|||||||
|
|
||||||
let handlerResult: ActionUpdate = {};
|
let handlerResult: ActionUpdate = {};
|
||||||
if (!wakeupUpdate) {
|
if (!wakeupUpdate) {
|
||||||
logger.debug(
|
this.logger.debug(
|
||||||
`Current MembershipManager processing: ${nextAction.type}\nQueue:`,
|
`Current MembershipManager processing: ${nextAction.type}\nQueue:`,
|
||||||
this._actions,
|
this._actions,
|
||||||
`\nDate.now: "${Date.now()}`,
|
`\nDate.now: "${Date.now()}`,
|
||||||
@@ -121,7 +123,7 @@ export class ActionScheduler {
|
|||||||
this.running = false;
|
this.running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Leave MembershipManager ActionScheduler loop (no more actions)");
|
this.logger.debug("Leave MembershipManager ActionScheduler loop (no more actions)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public initiateJoin(): void {
|
public initiateJoin(): void {
|
||||||
|
@@ -18,7 +18,7 @@ import type { MatrixClient } from "../client.ts";
|
|||||||
import type { EncryptionKeysEventContent, Statistics } from "./types.ts";
|
import type { EncryptionKeysEventContent, Statistics } from "./types.ts";
|
||||||
import { EventType } from "../@types/event.ts";
|
import { EventType } from "../@types/event.ts";
|
||||||
import { type MatrixError } from "../http-api/errors.ts";
|
import { type MatrixError } from "../http-api/errors.ts";
|
||||||
import { logger, type Logger } from "../logger.ts";
|
import { logger as rootLogger, type Logger } from "../logger.ts";
|
||||||
import { KeyTransportEvents, type KeyTransportEventsHandlerMap, type IKeyTransport } from "./IKeyTransport.ts";
|
import { KeyTransportEvents, type KeyTransportEventsHandlerMap, type IKeyTransport } from "./IKeyTransport.ts";
|
||||||
import { type MatrixEvent } from "../models/event.ts";
|
import { type MatrixEvent } from "../models/event.ts";
|
||||||
import { type CallMembership } from "./CallMembership.ts";
|
import { type CallMembership } from "./CallMembership.ts";
|
||||||
@@ -29,7 +29,7 @@ export class RoomKeyTransport
|
|||||||
extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>
|
extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>
|
||||||
implements IKeyTransport
|
implements IKeyTransport
|
||||||
{
|
{
|
||||||
private readonly prefixedLogger: Logger;
|
private readonly logger: Logger;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private room: Pick<Room, "on" | "off" | "roomId">,
|
private room: Pick<Room, "on" | "off" | "roomId">,
|
||||||
@@ -38,9 +38,10 @@ export class RoomKeyTransport
|
|||||||
"sendEvent" | "getDeviceId" | "getUserId" | "cancelPendingEvent" | "decryptEventIfNeeded"
|
"sendEvent" | "getDeviceId" | "getUserId" | "cancelPendingEvent" | "decryptEventIfNeeded"
|
||||||
>,
|
>,
|
||||||
private statistics: Statistics,
|
private statistics: Statistics,
|
||||||
|
parentLogger?: Logger,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.prefixedLogger = logger.getChild(`[RTC: ${room.roomId} RoomKeyTransport]`);
|
this.logger = (parentLogger ?? rootLogger).getChild(`[RoomKeyTransport]`);
|
||||||
}
|
}
|
||||||
public start(): void {
|
public start(): void {
|
||||||
this.room.on(RoomEvent.Timeline, (ev) => void this.consumeCallEncryptionEvent(ev));
|
this.room.on(RoomEvent.Timeline, (ev) => void this.consumeCallEncryptionEvent(ev));
|
||||||
@@ -54,23 +55,23 @@ export class RoomKeyTransport
|
|||||||
|
|
||||||
if (event.isDecryptionFailure()) {
|
if (event.isDecryptionFailure()) {
|
||||||
if (!isRetry) {
|
if (!isRetry) {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
`Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason} will retry once only`,
|
`Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason} will retry once only`,
|
||||||
);
|
);
|
||||||
// retry after 1 second. After this we give up.
|
// retry after 1 second. After this we give up.
|
||||||
setTimeout(() => void this.consumeCallEncryptionEvent(event, true), 1000);
|
setTimeout(() => void this.consumeCallEncryptionEvent(event, true), 1000);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason}`);
|
this.logger.warn(`Decryption failed for event ${event.getId()}: ${event.decryptionFailureReason}`);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (isRetry) {
|
} else if (isRetry) {
|
||||||
logger.info(`Decryption succeeded for event ${event.getId()} after retry`);
|
this.logger.info(`Decryption succeeded for event ${event.getId()} after retry`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.getType() !== EventType.CallEncryptionKeysPrefix) return Promise.resolve();
|
if (event.getType() !== EventType.CallEncryptionKeysPrefix) return Promise.resolve();
|
||||||
|
|
||||||
if (!this.room) {
|
if (!this.room) {
|
||||||
logger.error(`Got room state event for unknown room ${event.getRoomId()}!`);
|
this.logger.error(`Got room state event for unknown room ${event.getRoomId()}!`);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ export class RoomKeyTransport
|
|||||||
try {
|
try {
|
||||||
await this.client.sendEvent(this.room.roomId, EventType.CallEncryptionKeysPrefix, content);
|
await this.client.sendEvent(this.room.roomId, EventType.CallEncryptionKeysPrefix, content);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.prefixedLogger.error("Failed to send call encryption keys", error);
|
this.logger.error("Failed to send call encryption keys", error);
|
||||||
const matrixError = error as MatrixError;
|
const matrixError = error as MatrixError;
|
||||||
if (matrixError.event) {
|
if (matrixError.event) {
|
||||||
// cancel the pending event: we'll just generate a new one with our latest
|
// cancel the pending event: we'll just generate a new one with our latest
|
||||||
@@ -114,20 +115,20 @@ export class RoomKeyTransport
|
|||||||
const callId = content["call_id"];
|
const callId = content["call_id"];
|
||||||
|
|
||||||
if (!userId) {
|
if (!userId) {
|
||||||
logger.warn(`Received m.call.encryption_keys with no userId: callId=${callId}`);
|
this.logger.warn(`Received m.call.encryption_keys with no userId: callId=${callId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We currently only handle callId = "" (which is the default for room scoped calls)
|
// We currently only handle callId = "" (which is the default for room scoped calls)
|
||||||
if (callId !== "") {
|
if (callId !== "") {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
`Received m.call.encryption_keys with unsupported callId: userId=${userId}, deviceId=${deviceId}, callId=${callId}`,
|
`Received m.call.encryption_keys with unsupported callId: userId=${userId}, deviceId=${deviceId}, callId=${callId}`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(content.keys)) {
|
if (!Array.isArray(content.keys)) {
|
||||||
logger.warn(`Received m.call.encryption_keys where keys wasn't an array: callId=${callId}`);
|
this.logger.warn(`Received m.call.encryption_keys where keys wasn't an array: callId=${callId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ export class RoomKeyTransport
|
|||||||
// We store our own sender key in the same set along with keys from others, so it's
|
// We store our own sender key in the same set along with keys from others, so it's
|
||||||
// important we don't allow our own keys to be set by one of these events (apart from
|
// important we don't allow our own keys to be set by one of these events (apart from
|
||||||
// the fact that we don't need it anyway because we already know our own keys).
|
// the fact that we don't need it anyway because we already know our own keys).
|
||||||
logger.info("Ignoring our own keys event");
|
this.logger.info("Ignoring our own keys event");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +146,7 @@ export class RoomKeyTransport
|
|||||||
|
|
||||||
for (const key of content.keys) {
|
for (const key of content.keys) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
logger.info("Ignoring false-y key in keys event");
|
this.logger.info("Ignoring false-y key in keys event");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,11 +164,11 @@ export class RoomKeyTransport
|
|||||||
typeof encryptionKey !== "string" ||
|
typeof encryptionKey !== "string" ||
|
||||||
typeof encryptionKeyIndex !== "number"
|
typeof encryptionKeyIndex !== "number"
|
||||||
) {
|
) {
|
||||||
logger.warn(
|
this.logger.warn(
|
||||||
`Malformed call encryption_key: userId=${userId}, deviceId=${deviceId}, encryptionKeyIndex=${encryptionKeyIndex} callId=${callId}`,
|
`Malformed call encryption_key: userId=${userId}, deviceId=${deviceId}, encryptionKeyIndex=${encryptionKeyIndex} callId=${callId}`,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
logger.debug(
|
this.logger.debug(
|
||||||
`onCallEncryption userId=${userId}:${deviceId} encryptionKeyIndex=${encryptionKeyIndex} age=${age}ms`,
|
`onCallEncryption userId=${userId}:${deviceId} encryptionKeyIndex=${encryptionKeyIndex} age=${age}ms`,
|
||||||
);
|
);
|
||||||
this.emit(
|
this.emit(
|
||||||
|
@@ -16,7 +16,7 @@ limitations under the License.
|
|||||||
|
|
||||||
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
||||||
import { type IKeyTransport, KeyTransportEvents, type KeyTransportEventsHandlerMap } from "./IKeyTransport.ts";
|
import { type IKeyTransport, KeyTransportEvents, type KeyTransportEventsHandlerMap } from "./IKeyTransport.ts";
|
||||||
import { type Logger } from "../logger.ts";
|
import { type Logger, logger as rootLogger } from "../logger.ts";
|
||||||
import type { CallMembership } from "./CallMembership.ts";
|
import type { CallMembership } from "./CallMembership.ts";
|
||||||
import type { EncryptionKeysToDeviceEventContent, Statistics } from "./types.ts";
|
import type { EncryptionKeysToDeviceEventContent, Statistics } from "./types.ts";
|
||||||
import { ClientEvent, type MatrixClient } from "../client.ts";
|
import { ClientEvent, type MatrixClient } from "../client.ts";
|
||||||
@@ -31,7 +31,7 @@ export class ToDeviceKeyTransport
|
|||||||
extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>
|
extends TypedEventEmitter<KeyTransportEvents, KeyTransportEventsHandlerMap>
|
||||||
implements IKeyTransport
|
implements IKeyTransport
|
||||||
{
|
{
|
||||||
private readonly prefixedLogger: Logger;
|
private readonly logger: Logger;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private userId: string,
|
private userId: string,
|
||||||
@@ -39,10 +39,10 @@ export class ToDeviceKeyTransport
|
|||||||
private roomId: string,
|
private roomId: string,
|
||||||
private client: Pick<MatrixClient, "encryptAndSendToDevice" | "on" | "off">,
|
private client: Pick<MatrixClient, "encryptAndSendToDevice" | "on" | "off">,
|
||||||
private statistics: Statistics,
|
private statistics: Statistics,
|
||||||
logger: Logger,
|
parentLogger?: Logger,
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.prefixedLogger = logger.getChild(`[${roomId} ToDeviceKeyTransport]`);
|
this.logger = (parentLogger ?? rootLogger).getChild(`[ToDeviceKeyTransport]`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
@@ -74,7 +74,7 @@ export class ToDeviceKeyTransport
|
|||||||
.filter((member) => {
|
.filter((member) => {
|
||||||
// filter malformed call members
|
// filter malformed call members
|
||||||
if (member.sender == undefined || member.deviceId == undefined) {
|
if (member.sender == undefined || member.deviceId == undefined) {
|
||||||
this.prefixedLogger.warn(`Malformed call member: ${member.sender}|${member.deviceId}`);
|
this.logger.warn(`Malformed call member: ${member.sender}|${member.deviceId}`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Filter out me
|
// Filter out me
|
||||||
@@ -91,7 +91,7 @@ export class ToDeviceKeyTransport
|
|||||||
await this.client.encryptAndSendToDevice(EventType.CallEncryptionKeysPrefix, targets, content);
|
await this.client.encryptAndSendToDevice(EventType.CallEncryptionKeysPrefix, targets, content);
|
||||||
this.statistics.counters.roomEventEncryptionKeysSent += 1;
|
this.statistics.counters.roomEventEncryptionKeysSent += 1;
|
||||||
} else {
|
} else {
|
||||||
this.prefixedLogger.warn("No targets found for sending key");
|
this.logger.warn("No targets found for sending key");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,21 +145,21 @@ export class ToDeviceKeyTransport
|
|||||||
const roomId = content.room_id;
|
const roomId = content.room_id;
|
||||||
if (!roomId) {
|
if (!roomId) {
|
||||||
// Invalid event
|
// Invalid event
|
||||||
this.prefixedLogger.warn("Malformed Event: invalid call encryption keys event, no roomId");
|
this.logger.warn("Malformed Event: invalid call encryption keys event, no roomId");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (roomId !== this.roomId) {
|
if (roomId !== this.roomId) {
|
||||||
this.prefixedLogger.warn("Malformed Event: Mismatch roomId");
|
this.logger.warn("Malformed Event: Mismatch roomId");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content.keys || !content.keys.key || typeof content.keys.index !== "number") {
|
if (!content.keys || !content.keys.key || typeof content.keys.index !== "number") {
|
||||||
this.prefixedLogger.warn("Malformed Event: Missing keys field");
|
this.logger.warn("Malformed Event: Missing keys field");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!content.member || !content.member.claimed_device_id) {
|
if (!content.member || !content.member.claimed_device_id) {
|
||||||
this.prefixedLogger.warn("Malformed Event: Missing claimed_device_id");
|
this.logger.warn("Malformed Event: Missing claimed_device_id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user