mirror of
https://github.com/vector-im/element-call.git
synced 2026-07-15 18:49:21 +00:00
Catch SDK sticky-events error instead of pre-flight check
This commit is contained in:
@@ -38,7 +38,6 @@ import { useAudioContext } from "../useAudioContext";
|
|||||||
import { ActiveCall } from "./InCallView";
|
import { ActiveCall } from "./InCallView";
|
||||||
import {
|
import {
|
||||||
flushPromises,
|
flushPromises,
|
||||||
mockConfig,
|
|
||||||
mockEmitter,
|
mockEmitter,
|
||||||
mockMatrixRoom,
|
mockMatrixRoom,
|
||||||
mockMatrixRoomMember,
|
mockMatrixRoomMember,
|
||||||
@@ -51,7 +50,6 @@ import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary";
|
|||||||
import { ElementWidgetActions, type WidgetHelpers } from "../widget";
|
import { ElementWidgetActions, type WidgetHelpers } from "../widget";
|
||||||
import { LazyEventEmitter } from "../LazyEventEmitter";
|
import { LazyEventEmitter } from "../LazyEventEmitter";
|
||||||
import { MatrixRTCTransportMissingError } from "../utils/errors";
|
import { MatrixRTCTransportMissingError } from "../utils/errors";
|
||||||
import { MatrixRTCMode } from "../config/ConfigOptions";
|
|
||||||
import { ProcessorProvider } from "../livekit/TrackProcessorContext";
|
import { ProcessorProvider } from "../livekit/TrackProcessorContext";
|
||||||
import { MediaDevicesContext } from "../MediaDevicesContext";
|
import { MediaDevicesContext } from "../MediaDevicesContext";
|
||||||
import { constant } from "../state/Behavior";
|
import { constant } from "../state/Behavior";
|
||||||
@@ -134,7 +132,6 @@ function createGroupCallView(
|
|||||||
widget: WidgetHelpers | null,
|
widget: WidgetHelpers | null,
|
||||||
joined = true,
|
joined = true,
|
||||||
options: {
|
options: {
|
||||||
doesServerSupportUnstableFeature?: (feature: string) => Promise<boolean>;
|
|
||||||
withErrorBoundary?: boolean;
|
withErrorBoundary?: boolean;
|
||||||
} = {},
|
} = {},
|
||||||
): {
|
): {
|
||||||
@@ -146,9 +143,6 @@ function createGroupCallView(
|
|||||||
getUserId: () => localRtcMember.userId,
|
getUserId: () => localRtcMember.userId,
|
||||||
getDeviceId: () => localRtcMember.deviceId,
|
getDeviceId: () => localRtcMember.deviceId,
|
||||||
getRoom: (rId) => (rId === roomId ? room : null),
|
getRoom: (rId) => (rId === roomId ? room : null),
|
||||||
doesServerSupportUnstableFeature:
|
|
||||||
options.doesServerSupportUnstableFeature ??
|
|
||||||
vi.fn().mockResolvedValue(true),
|
|
||||||
} as Partial<MatrixClient> as MatrixClient;
|
} as Partial<MatrixClient> as MatrixClient;
|
||||||
const room = mockMatrixRoom({
|
const room = mockMatrixRoom({
|
||||||
relations: {
|
relations: {
|
||||||
@@ -416,28 +410,37 @@ test.skip("GroupCallView shows errors that occur during joining", async () => {
|
|||||||
screen.getByText("Call is not supported");
|
screen.getByText("Call is not supported");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("shows StickyEventsRequiredError when matrix_2_0 is forced but homeserver lacks MSC4354", async () => {
|
test("translates UnsupportedStickyEventsEndpointError to the StickyEventsRequiredError screen", async () => {
|
||||||
mockConfig({ matrix_rtc_mode: MatrixRTCMode.Matrix_2_0 });
|
// Match the shape the SDK emits on
|
||||||
createGroupCallView(null, true, {
|
// MatrixRTCSessionEvent.MembershipManagerError when matrix_2_0 mode is
|
||||||
doesServerSupportUnstableFeature: vi.fn().mockResolvedValue(false),
|
// configured but the homeserver does not advertise MSC4354.
|
||||||
|
const stickyError = new Error("Server does not support the sticky events");
|
||||||
|
stickyError.name = "UnsupportedStickyEventsEndpointError";
|
||||||
|
|
||||||
|
const { rtcSession } = createGroupCallView(null, true, {
|
||||||
withErrorBoundary: true,
|
withErrorBoundary: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await act(() =>
|
||||||
|
rtcSession.emit(MatrixRTCSessionEvent.MembershipManagerError, stickyError),
|
||||||
|
);
|
||||||
|
|
||||||
await screen.findByText("Homeserver does not support Matrix 2.0 calls");
|
await screen.findByText("Homeserver does not support Matrix 2.0 calls");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("does not show StickyEventsRequiredError when homeserver supports MSC4354", async () => {
|
test("falls back to ConnectionLostError for unrecognised membership manager errors", async () => {
|
||||||
mockConfig({ matrix_rtc_mode: MatrixRTCMode.Matrix_2_0 });
|
const { rtcSession } = createGroupCallView(null, true, {
|
||||||
const { getByText } = createGroupCallView(null, true, {
|
|
||||||
doesServerSupportUnstableFeature: vi.fn().mockResolvedValue(true),
|
|
||||||
withErrorBoundary: true,
|
withErrorBoundary: true,
|
||||||
});
|
});
|
||||||
// Give the async support check a chance to resolve.
|
|
||||||
await flushPromises();
|
await act(() =>
|
||||||
expect(
|
rtcSession.emit(
|
||||||
screen.queryByText("Homeserver does not support Matrix 2.0 calls"),
|
MatrixRTCSessionEvent.MembershipManagerError,
|
||||||
).toBeNull();
|
new Error("something else broke"),
|
||||||
// The normal call UI (mocked ActiveCall) renders instead.
|
),
|
||||||
expect(getByText("Leave")).toBeInTheDocument();
|
);
|
||||||
|
|
||||||
|
await screen.findByText("Connection lost");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("user can reconnect after a membership manager error", async () => {
|
test("user can reconnect after a membership manager error", async () => {
|
||||||
|
|||||||
@@ -13,12 +13,7 @@ import {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from "react";
|
||||||
import {
|
import { type MatrixClient, JoinRule, type Room } from "matrix-js-sdk";
|
||||||
type MatrixClient,
|
|
||||||
JoinRule,
|
|
||||||
type Room,
|
|
||||||
UNSTABLE_MSC4354_STICKY_EVENTS,
|
|
||||||
} from "matrix-js-sdk";
|
|
||||||
import {
|
import {
|
||||||
Room as LivekitRoom,
|
Room as LivekitRoom,
|
||||||
isE2EESupported as isE2EESupportedBrowser,
|
isE2EESupported as isE2EESupportedBrowser,
|
||||||
@@ -75,8 +70,6 @@ import {
|
|||||||
StickyEventsRequiredError,
|
StickyEventsRequiredError,
|
||||||
UnknownCallError,
|
UnknownCallError,
|
||||||
} from "../utils/errors.ts";
|
} from "../utils/errors.ts";
|
||||||
import { Config } from "../config/Config.ts";
|
|
||||||
import { MatrixRTCMode } from "../config/ConfigOptions.ts";
|
|
||||||
import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx";
|
import { GroupCallErrorBoundary } from "./GroupCallErrorBoundary.tsx";
|
||||||
import { useTypedEventEmitter } from "../useEvents";
|
import { useTypedEventEmitter } from "../useEvents";
|
||||||
import { muteAllAudio$ } from "../state/MuteAllAudioModel.ts";
|
import { muteAllAudio$ } from "../state/MuteAllAudioModel.ts";
|
||||||
@@ -170,30 +163,21 @@ export const GroupCallView: FC<Props> = ({
|
|||||||
useTypedEventEmitter(
|
useTypedEventEmitter(
|
||||||
rtcSession,
|
rtcSession,
|
||||||
MatrixRTCSessionEvent.MembershipManagerError,
|
MatrixRTCSessionEvent.MembershipManagerError,
|
||||||
(error) => setExternalError(new ConnectionLostError()),
|
(error) => {
|
||||||
|
// The SDK throws this typed error when matrix_rtc_mode=matrix_2_0 is in
|
||||||
|
// effect but the homeserver does not advertise MSC4354 (sticky events).
|
||||||
|
// Surface the actual cause instead of a generic connection-lost screen.
|
||||||
|
if (
|
||||||
|
error instanceof Error &&
|
||||||
|
error.name === "UnsupportedStickyEventsEndpointError"
|
||||||
|
) {
|
||||||
|
setExternalError(new StickyEventsRequiredError());
|
||||||
|
} else {
|
||||||
|
setExternalError(new ConnectionLostError());
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the deployment pins matrix_rtc_mode=matrix_2_0 but this homeserver
|
|
||||||
// doesn't advertise MSC4354 (sticky events), the call will fail to connect
|
|
||||||
// with a generic "Connection lost" message. Surface the real cause up front.
|
|
||||||
useEffect(() => {
|
|
||||||
if (Config.get().matrix_rtc_mode !== MatrixRTCMode.Matrix_2_0) return;
|
|
||||||
let cancelled = false;
|
|
||||||
client
|
|
||||||
.doesServerSupportUnstableFeature(UNSTABLE_MSC4354_STICKY_EVENTS)
|
|
||||||
.then((supported) => {
|
|
||||||
if (!cancelled && !supported) {
|
|
||||||
setExternalError(new StickyEventsRequiredError());
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
logger.warn("Failed to check sticky-events homeserver support", e);
|
|
||||||
});
|
|
||||||
return (): void => {
|
|
||||||
cancelled = true;
|
|
||||||
};
|
|
||||||
}, [client]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Sanity check the room object
|
// Sanity check the room object
|
||||||
if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room)
|
if (client.getRoom(rtcSession.room.roomId) !== rtcSession.room)
|
||||||
|
|||||||
Reference in New Issue
Block a user