From aa1cbe90ef97a7e47bc2bf2e31142e8f87c4963f Mon Sep 17 00:00:00 2001 From: Timo K Date: Mon, 6 Oct 2025 17:49:46 +0200 Subject: [PATCH] correct usage of methods that now became async Signed-off-by: Timo K --- spec/unit/matrixrtc/MatrixRTCSession.spec.ts | 52 ++++++++++---------- src/matrixrtc/MatrixRTCSession.ts | 8 +-- src/matrixrtc/MatrixRTCSessionManager.ts | 2 +- src/matrixrtc/MembershipManager.ts | 38 +++++++------- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/spec/unit/matrixrtc/MatrixRTCSession.spec.ts b/spec/unit/matrixrtc/MatrixRTCSession.spec.ts index f030f4235..86b0562cb 100644 --- a/spec/unit/matrixrtc/MatrixRTCSession.spec.ts +++ b/spec/unit/matrixrtc/MatrixRTCSession.spec.ts @@ -304,7 +304,10 @@ describe("MatrixRTCSession", () => { let sentStateEvent: Promise; beforeEach(async () => { sentStateEvent = new Promise((resolve) => { - sendStateEventMock = jest.fn(resolve); + sendStateEventMock = jest.fn().mockImplementation(() => { + resolve(); + return Promise.resolve({ event_id: "id" }); + }); }); sendEventMock = jest.fn().mockResolvedValue(undefined); client.sendStateEvent = sendStateEventMock; @@ -349,14 +352,8 @@ 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; + await sess!.onRTCSessionMemberUpdate(); const ownMembershipId = sess?.memberships[0].eventId; expect(client.sendEvent).toHaveBeenCalledWith(mockRoom!.roomId, EventType.RTCNotification, { @@ -425,7 +422,8 @@ describe("MatrixRTCSession", () => { }, ]); - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); + const ownMembershipId = sess?.memberships[0].eventId; expect(sess!.getConsensusCallIntent()).toEqual("audio"); @@ -476,13 +474,13 @@ describe("MatrixRTCSession", () => { it("doesn't send a notification when joining an existing call", async () => { // Add another member to the call so that it is considered an existing call mockRoomState(mockRoom, [membershipTemplate]); - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); // Simulate a join, including the update to the room state sess!.joinRoomSession([mockFocus], mockFocus, { notificationType: "ring" }); await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 5000))]); mockRoomState(mockRoom, [membershipTemplate, { ...membershipTemplate, user_id: client.getUserId()! }]); - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); expect(client.sendEvent).not.toHaveBeenCalled(); }); @@ -494,9 +492,9 @@ describe("MatrixRTCSession", () => { // But this time we want to simulate a race condition in which we receive a state event // from someone else, starting the call before our own state event has been sent mockRoomState(mockRoom, [membershipTemplate]); - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); mockRoomState(mockRoom, [membershipTemplate, { ...membershipTemplate, user_id: client.getUserId()! }]); - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); // We assume that the responsibility to send a notification, if any, lies with the other // participant that won the race @@ -511,7 +509,7 @@ describe("MatrixRTCSession", () => { const onMembershipsChanged = jest.fn(); sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); expect(onMembershipsChanged).not.toHaveBeenCalled(); }); @@ -524,8 +522,8 @@ describe("MatrixRTCSession", () => { sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged); mockRoomState(mockRoom, []); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); expect(onMembershipsChanged).toHaveBeenCalled(); }); @@ -708,14 +706,14 @@ describe("MatrixRTCSession", () => { // member2 leaves triggering key rotation mockRoomState(mockRoom, [membershipTemplate]); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); // member2 re-joins which should trigger an immediate re-send const keysSentPromise2 = new Promise((resolve) => { sendEventMock.mockImplementation((_roomId, _evType, payload) => resolve(payload)); }); mockRoomState(mockRoom, [membershipTemplate, member2]); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); // but, that immediate resend is throttled so we need to wait a bit jest.advanceTimersByTime(1000); const { keys } = await keysSentPromise2; @@ -766,7 +764,7 @@ describe("MatrixRTCSession", () => { }); mockRoomState(mockRoom, [membershipTemplate, member2]); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); await keysSentPromise2; @@ -813,7 +811,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockClear(); // these should be a no-op: - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); expect(sendEventMock).toHaveBeenCalledTimes(0); expect(sess!.statistics.counters.roomEventEncryptionKeysSent).toEqual(1); } finally { @@ -858,7 +856,7 @@ describe("MatrixRTCSession", () => { sendEventMock.mockClear(); // this should be a no-op: - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); expect(sendEventMock).toHaveBeenCalledTimes(0); // advance time to avoid key throttling @@ -873,7 +871,7 @@ describe("MatrixRTCSession", () => { }); // this should re-send the key - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); await keysSentPromise2; @@ -931,8 +929,10 @@ describe("MatrixRTCSession", () => { }); mockRoomState(mockRoom, [membershipTemplate]); - sess.onRTCSessionMemberUpdate(); - + const { promise, resolve } = Promise.withResolvers(); + sess.once(MatrixRTCSessionEvent.MembershipsChanged, resolve); + await sess.onRTCSessionMemberUpdate(); + await promise; jest.advanceTimersByTime(KEY_DELAY); expect(sendKeySpy).toHaveBeenCalledTimes(1); // check that we send the key with index 1 even though the send gets delayed when leaving. @@ -998,7 +998,7 @@ describe("MatrixRTCSession", () => { mockRoomState(mockRoom, members.slice(0, membersToTest - i)); } - sess!.onRTCSessionMemberUpdate(); + await sess!.onRTCSessionMemberUpdate(); // advance time to avoid key throttling jest.advanceTimersByTime(10000); @@ -1037,7 +1037,7 @@ describe("MatrixRTCSession", () => { }); mockRoomState(mockRoom, [membershipTemplate, member2]); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); await new Promise((resolve) => { realSetTimeout(resolve); @@ -1064,7 +1064,7 @@ describe("MatrixRTCSession", () => { manageMediaKeys: true, useExperimentalToDeviceTransport: true, }); - sess.onRTCSessionMemberUpdate(); + await sess.onRTCSessionMemberUpdate(); await keySentPromise; diff --git a/src/matrixrtc/MatrixRTCSession.ts b/src/matrixrtc/MatrixRTCSession.ts index fe483c3b2..5410eeb5e 100644 --- a/src/matrixrtc/MatrixRTCSession.ts +++ b/src/matrixrtc/MatrixRTCSession.ts @@ -731,7 +731,7 @@ export class MatrixRTCSession extends TypedEventEmitter< } if (soonestExpiry != undefined) { - this.expiryTimeout = setTimeout(this.onRTCSessionMemberUpdate, soonestExpiry); + this.expiryTimeout = setTimeout(() => void this.onRTCSessionMemberUpdate(), soonestExpiry); } } @@ -803,8 +803,8 @@ export class MatrixRTCSession extends TypedEventEmitter< /** * Call this when something changed that may impacts the current MatrixRTC members in this session. */ - public onRTCSessionMemberUpdate = (): void => { - void this.recalculateSessionMembers(); + public onRTCSessionMemberUpdate = (): Promise => { + return this.recalculateSessionMembers(); }; /** @@ -838,7 +838,7 @@ export class MatrixRTCSession extends TypedEventEmitter< this.emit(MatrixRTCSessionEvent.MembershipsChanged, oldMemberships, this.memberships); }); - void this.membershipManager?.onRTCSessionMemberUpdate(this.memberships); + await 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) { diff --git a/src/matrixrtc/MatrixRTCSessionManager.ts b/src/matrixrtc/MatrixRTCSessionManager.ts index 6f60b6ed1..577a240f1 100644 --- a/src/matrixrtc/MatrixRTCSessionManager.ts +++ b/src/matrixrtc/MatrixRTCSessionManager.ts @@ -135,7 +135,7 @@ export class MatrixRTCSessionManager extends TypedEventEmitter 0 and // nowActive = session.memberships.length // Alternatively we would need to setup some event emission when the RTC session ended. - session.onRTCSessionMemberUpdate(); + await session.onRTCSessionMemberUpdate(); const nowActive = session.memberships.length > 0; diff --git a/src/matrixrtc/MembershipManager.ts b/src/matrixrtc/MembershipManager.ts index 35183753b..4e83a8605 100644 --- a/src/matrixrtc/MembershipManager.ts +++ b/src/matrixrtc/MembershipManager.ts @@ -398,7 +398,7 @@ export class MembershipManager return this.joinConfig?.useRtcMemberFormat ?? false; } // LOOP HANDLER: - private async membershipLoopHandler(type: MembershipActionType): Promise { + private membershipLoopHandler(type: MembershipActionType): Promise { switch (type) { case MembershipActionType.SendDelayedEvent: { // Before we start we check if we come from a state where we have a delay id. @@ -418,19 +418,19 @@ export class MembershipManager case MembershipActionType.RestartDelayedEvent: { if (!this.state.delayId) { // Delay id got reset. This action was used to check if the hs canceled the delayed event when the join state got sent. - return createInsertActionUpdate(MembershipActionType.SendDelayedEvent); + return Promise.resolve(createInsertActionUpdate(MembershipActionType.SendDelayedEvent)); } return this.restartDelayedEvent(this.state.delayId); } case MembershipActionType.SendScheduledDelayedLeaveEvent: { // We are already good if (!this.state.hasMemberStateEvent) { - return { replace: [] }; + return Promise.resolve({ replace: [] }); } if (this.state.delayId) { return this.sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(this.state.delayId); } else { - return createInsertActionUpdate(MembershipActionType.SendLeaveEvent); + return Promise.resolve(createInsertActionUpdate(MembershipActionType.SendLeaveEvent)); } } case MembershipActionType.SendJoinEvent: { @@ -442,7 +442,7 @@ export class MembershipManager case MembershipActionType.SendLeaveEvent: { // We are good already if (!this.state.hasMemberStateEvent) { - return { replace: [] }; + return Promise.resolve({ replace: [] }); } // This is only a fallback in case we do not have working delayed events support. // first we should try to just send the scheduled leave event @@ -452,12 +452,12 @@ export class MembershipManager } // HANDLERS (used in the membershipLoopHandler) - private async sendOrResendDelayedLeaveEvent(): Promise { + private sendOrResendDelayedLeaveEvent(): Promise { // We can reach this at the start of a call (where we do not yet have a membership: state.hasMemberStateEvent=false) // or during a call if the state event canceled our delayed event or caused by an unexpected error that removed our delayed event. // (Another client could have canceled it, the homeserver might have removed/lost it due to a restart, ...) // In the `then` and `catch` block we treat both cases differently. "if (this.state.hasMemberStateEvent) {} else {}" - return await this.client + return this.client ._unstable_sendDelayedStateEvent( this.room.roomId, { @@ -514,9 +514,9 @@ export class MembershipManager }); } - private async cancelKnownDelayIdBeforeSendDelayedEvent(delayId: string): Promise { + private cancelKnownDelayIdBeforeSendDelayedEvent(delayId: string): Promise { // Remove all running updates and restarts - return await this.client + return this.client ._unstable_updateDelayedEvent(delayId, UpdateDelayedEventAction.Cancel) .then(() => { this.state.delayId = undefined; @@ -557,7 +557,7 @@ export class MembershipManager this.emit(MembershipManagerEvent.ProbablyLeft, this.state.probablyLeft); } - private async restartDelayedEvent(delayId: string): Promise { + private restartDelayedEvent(delayId: string): Promise { // Compute the duration until we expect the server to send the delayed leave event. const durationUntilServerDelayedLeave = this.state.expectedServerDelayLeaveTs ? this.state.expectedServerDelayLeaveTs - Date.now() @@ -579,7 +579,7 @@ export class MembershipManager // The obvious choice here would be to use the `IRequestOpts` to set the timeout. Since this call might be forwarded // to the widget driver this information would get lost. That is why we mimic the AbortError using the race. - return await Promise.race([ + return Promise.race([ this.client._unstable_updateDelayedEvent(delayId, UpdateDelayedEventAction.Restart), abortPromise, ]) @@ -618,8 +618,8 @@ export class MembershipManager }); } - private async sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(delayId: string): Promise { - return await this.client + private sendScheduledDelayedLeaveEventOrFallbackToSendLeaveEvent(delayId: string): Promise { + return this.client ._unstable_updateDelayedEvent(delayId, UpdateDelayedEventAction.Send) .then(() => { this.state.hasMemberStateEvent = false; @@ -646,8 +646,8 @@ export class MembershipManager }); } - private async sendJoinEvent(): Promise { - return await this.client + private sendJoinEvent(): Promise { + return this.client .sendStateEvent( this.room.roomId, this.useRtcMemberFormat ? EventType.RTCMembership : EventType.GroupCallMemberPrefix, @@ -691,9 +691,9 @@ export class MembershipManager }); } - private async updateExpiryOnJoinedEvent(): Promise { + private updateExpiryOnJoinedEvent(): Promise { const nextExpireUpdateIteration = this.state.expireUpdateIterations + 1; - return await this.client + return this.client .sendStateEvent( this.room.roomId, this.useRtcMemberFormat ? EventType.RTCMembership : EventType.GroupCallMemberPrefix, @@ -720,8 +720,8 @@ export class MembershipManager throw e; }); } - private async sendFallbackLeaveEvent(): Promise { - return await this.client + private sendFallbackLeaveEvent(): Promise { + return this.client .sendStateEvent( this.room.roomId, this.useRtcMemberFormat ? EventType.RTCMembership : EventType.GroupCallMemberPrefix,