You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-30 04:23:07 +03:00
MatrixRTC: refactor MatrixRTCSession MemberManager API (#4610)
* update join and leave internal api. * rename onMembershipUpdate and triggerCallMembershipEventUpdate to onMembershipsUpdate This makes it more clear that we do not talk about our own membership but all memberships in the session * cleanup MembershipManager - add comments and interface how to test this class. - sort methods by public/private - make triggerCallMembershipEventUpdate private * docstrings for getFocusInUse and getActiveFocus * simplify tests and make them only use MembershipManagerInterface methods. This allows to exchange the membershipManager with a different implementation. * convert interface to abstract class. * review (implement interface, make interface internal, dont change public api.) * Make the interface an actual interface. The actual constructor of the class now contains the `Pick` to define what it needs from the client. * move update condition into MembershipManager * renaming public api * Update src/matrixrtc/MatrixRTCSession.ts Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com> * Update src/matrixrtc/MatrixRTCSession.ts Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com> --------- Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
This commit is contained in:
@ -17,10 +17,10 @@ limitations under the License.
|
||||
import { encodeBase64, EventType, MatrixClient, MatrixError, MatrixEvent, Room } from "../../../src";
|
||||
import { KnownMembership } from "../../../src/@types/membership";
|
||||
import { DEFAULT_EXPIRE_DURATION, SessionMembershipData } from "../../../src/matrixrtc/CallMembership";
|
||||
import { MembershipManager } from "../../../src/matrixrtc/MembershipManager";
|
||||
import { MatrixRTCSession, MatrixRTCSessionEvent } from "../../../src/matrixrtc/MatrixRTCSession";
|
||||
import { EncryptionKeysEventContent } from "../../../src/matrixrtc/types";
|
||||
import { randomString } from "../../../src/randomstring";
|
||||
import { flushPromises } from "../../test-utils/flushPromises";
|
||||
import { makeMockRoom, makeMockRoomState, membershipTemplate } from "./mocks";
|
||||
|
||||
const mockFocus = { type: "mock" };
|
||||
@ -236,16 +236,15 @@ describe("MatrixRTCSession", () => {
|
||||
});
|
||||
|
||||
async function testSession(membershipData: SessionMembershipData): Promise<void> {
|
||||
const makeNewMembershipSpy = jest.spyOn(MembershipManager.prototype as any, "makeNewMembership");
|
||||
sess = MatrixRTCSession.roomSessionForRoom(client, makeMockRoom(membershipData));
|
||||
|
||||
sess.joinRoomSession([mockFocus], mockFocus, joinSessionConfig);
|
||||
await Promise.race([sentStateEvent, new Promise((resolve) => setTimeout(resolve, 500))]);
|
||||
|
||||
expect(makeNewMembershipSpy).toHaveBeenCalledTimes(1);
|
||||
expect(sendStateEventMock).toHaveBeenCalledTimes(1);
|
||||
|
||||
await Promise.race([sentDelayedState, new Promise((resolve) => setTimeout(resolve, 500))]);
|
||||
expect(client._unstable_sendDelayedStateEvent).toHaveBeenCalledTimes(1);
|
||||
expect(sendDelayedStateMock).toHaveBeenCalledTimes(1);
|
||||
}
|
||||
|
||||
it("sends events", async () => {
|
||||
@ -323,9 +322,11 @@ describe("MatrixRTCSession", () => {
|
||||
let sendStateEventMock: jest.Mock;
|
||||
let sendDelayedStateMock: jest.Mock;
|
||||
let sendEventMock: jest.Mock;
|
||||
let updateDelayedEventMock: jest.Mock;
|
||||
|
||||
let sentStateEvent: Promise<void>;
|
||||
let sentDelayedState: Promise<void>;
|
||||
let updatedDelayedEvent: Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
sentStateEvent = new Promise((resolve) => {
|
||||
@ -339,12 +340,15 @@ describe("MatrixRTCSession", () => {
|
||||
};
|
||||
});
|
||||
});
|
||||
updatedDelayedEvent = new Promise((r) => {
|
||||
updateDelayedEventMock = jest.fn(r);
|
||||
});
|
||||
sendEventMock = jest.fn();
|
||||
client.sendStateEvent = sendStateEventMock;
|
||||
client._unstable_sendDelayedStateEvent = sendDelayedStateMock;
|
||||
client.sendEvent = sendEventMock;
|
||||
|
||||
client._unstable_updateDelayedEvent = jest.fn();
|
||||
client._unstable_updateDelayedEvent = updateDelayedEventMock;
|
||||
|
||||
mockRoom = makeMockRoom([]);
|
||||
sess = MatrixRTCSession.roomSessionForRoom(client, mockRoom);
|
||||
@ -482,19 +486,7 @@ describe("MatrixRTCSession", () => {
|
||||
membershipServerSideExpiryTimeout: 9000,
|
||||
});
|
||||
|
||||
// needed to advance the mock timers properly
|
||||
// depends on myMembershipManager being created
|
||||
const scheduledDelayDisconnection = new Promise<void>((resolve) => {
|
||||
const membershipManager = (sess as any).membershipManager;
|
||||
const originalFn: () => void = membershipManager.scheduleDelayDisconnection;
|
||||
membershipManager.scheduleDelayDisconnection = jest.fn(() => {
|
||||
originalFn.call(membershipManager);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await sendDelayedStateExceedAttempt.then(); // needed to resolve after the send attempt catches
|
||||
|
||||
await sendDelayedStateAttempt;
|
||||
const callProps = (d: number) => {
|
||||
return [mockRoom!.roomId, { delay: d }, "org.matrix.msc3401.call.member", {}, userStateKey];
|
||||
@ -525,11 +517,13 @@ describe("MatrixRTCSession", () => {
|
||||
await sentDelayedState;
|
||||
|
||||
// should have prepared the heartbeat to keep delaying the leave event while still connected
|
||||
await scheduledDelayDisconnection;
|
||||
// should have tried updating the delayed leave to test that it wasn't replaced by own state
|
||||
await updatedDelayedEvent;
|
||||
expect(client._unstable_updateDelayedEvent).toHaveBeenCalledTimes(1);
|
||||
// should update delayed disconnect
|
||||
|
||||
// ensures that we reach the code that schedules the timeout for the next delay update before we advance the timers.
|
||||
await flushPromises();
|
||||
jest.advanceTimersByTime(5000);
|
||||
// should update delayed disconnect
|
||||
expect(client._unstable_updateDelayedEvent).toHaveBeenCalledTimes(2);
|
||||
|
||||
jest.useRealTimers();
|
||||
@ -561,7 +555,7 @@ describe("MatrixRTCSession", () => {
|
||||
|
||||
const onMembershipsChanged = jest.fn();
|
||||
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
expect(onMembershipsChanged).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -574,7 +568,7 @@ describe("MatrixRTCSession", () => {
|
||||
sess.on(MatrixRTCSessionEvent.MembershipsChanged, onMembershipsChanged);
|
||||
|
||||
mockRoom.getLiveTimeline().getState = jest.fn().mockReturnValue(makeMockRoomState([], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
expect(onMembershipsChanged).toHaveBeenCalled();
|
||||
});
|
||||
@ -763,7 +757,7 @@ describe("MatrixRTCSession", () => {
|
||||
mockRoom.getLiveTimeline().getState = jest
|
||||
.fn()
|
||||
.mockReturnValue(makeMockRoomState([membershipTemplate], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
// member2 re-joins which should trigger an immediate re-send
|
||||
const keysSentPromise2 = new Promise<EncryptionKeysEventContent>((resolve) => {
|
||||
@ -772,7 +766,7 @@ describe("MatrixRTCSession", () => {
|
||||
mockRoom.getLiveTimeline().getState = jest
|
||||
.fn()
|
||||
.mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
// but, that immediate resend is throttled so we need to wait a bit
|
||||
jest.advanceTimersByTime(1000);
|
||||
const { keys } = await keysSentPromise2;
|
||||
@ -825,7 +819,7 @@ describe("MatrixRTCSession", () => {
|
||||
mockRoom.getLiveTimeline().getState = jest
|
||||
.fn()
|
||||
.mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
await keysSentPromise2;
|
||||
|
||||
@ -879,7 +873,7 @@ describe("MatrixRTCSession", () => {
|
||||
sendEventMock.mockClear();
|
||||
|
||||
// these should be a no-op:
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
expect(sendEventMock).toHaveBeenCalledTimes(0);
|
||||
expect(sess!.statistics.counters.roomEventEncryptionKeysSent).toEqual(1);
|
||||
} finally {
|
||||
@ -933,7 +927,7 @@ describe("MatrixRTCSession", () => {
|
||||
sendEventMock.mockClear();
|
||||
|
||||
// this should be a no-op:
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
expect(sendEventMock).toHaveBeenCalledTimes(0);
|
||||
|
||||
// advance time to avoid key throttling
|
||||
@ -947,7 +941,7 @@ describe("MatrixRTCSession", () => {
|
||||
});
|
||||
|
||||
// this should re-send the key
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
await keysSentPromise2;
|
||||
|
||||
@ -1010,7 +1004,7 @@ describe("MatrixRTCSession", () => {
|
||||
mockRoom.getLiveTimeline().getState = jest
|
||||
.fn()
|
||||
.mockReturnValue(makeMockRoomState([membershipTemplate], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
jest.advanceTimersByTime(10000);
|
||||
|
||||
@ -1055,7 +1049,7 @@ describe("MatrixRTCSession", () => {
|
||||
);
|
||||
}
|
||||
|
||||
sess!.onMembershipUpdate();
|
||||
sess!.onRTCSessionMemberUpdate();
|
||||
|
||||
// advance time to avoid key throttling
|
||||
jest.advanceTimersByTime(10000);
|
||||
@ -1096,7 +1090,7 @@ describe("MatrixRTCSession", () => {
|
||||
mockRoom.getLiveTimeline().getState = jest
|
||||
.fn()
|
||||
.mockReturnValue(makeMockRoomState([membershipTemplate, member2], mockRoom.roomId));
|
||||
sess.onMembershipUpdate();
|
||||
sess.onRTCSessionMemberUpdate();
|
||||
|
||||
await new Promise((resolve) => {
|
||||
realSetTimeout(resolve);
|
||||
|
Reference in New Issue
Block a user