This commit is contained in:
Timo 2024-09-09 17:23:04 +02:00
parent ab457be4bb
commit f3404fbbf3
18 changed files with 121 additions and 129 deletions

View File

@ -77,9 +77,7 @@ export const App: FC<AppProps> = ({ history }) => {
setLoaded(true); setLoaded(true);
await widget?.api.sendContentLoaded(); await widget?.api.sendContentLoaded();
}) })
.catch((e) => { .catch(logger.error);
logger.error(e);
});
}); });
const errorPage = <CrashView />; const errorPage = <CrashView />;

View File

@ -399,7 +399,7 @@ export class PosthogAnalytics {
if (this.identificationPromise) { if (this.identificationPromise) {
// only make calls to posthog after the identification is done // only make calls to posthog after the identification is done
this.identificationPromise.then(doCapture).catch((e) => { this.identificationPromise.then(doCapture, (e) => {
logger.error("Failed to identify user for tracking", e); logger.error("Failed to identify user for tracking", e);
}); });
} else { } else {

View File

@ -43,8 +43,7 @@ export class PosthogSpanProcessor implements SpanProcessor {
public onStart(span: Span): void { public onStart(span: Span): void {
// Hack: Yield to allow attributes to be set before processing // Hack: Yield to allow attributes to be set before processing
Promise.resolve() try {
.then(() => {
switch (span.name) { switch (span.name) {
case "matrix.groupCallMembership": case "matrix.groupCallMembership":
this.onGroupCallMembershipStart(span); this.onGroupCallMembershipStart(span);
@ -53,10 +52,10 @@ export class PosthogSpanProcessor implements SpanProcessor {
this.onSummaryReportStart(span); this.onSummaryReportStart(span);
return; return;
} }
}) } catch (e) {
.catch((e) => { // log to avoid tripping @typescript-eslint/no-unused-vars
// noop logger.debug(e);
}); }
} }
public onEnd(span: ReadableSpan): void { public onEnd(span: ReadableSpan): void {

View File

@ -58,9 +58,8 @@ export function useInteractiveLogin(
password, password,
}), }),
stateUpdated: (): void => {}, stateUpdated: (): void => {},
requestEmailToken: async (): Promise<{ sid: string }> => { requestEmailToken: async (): Promise<{ sid: string }> =>
return Promise.resolve({ sid: "" }); Promise.resolve({ sid: "" }),
},
}); });
// XXX: This claims to return an IAuthData which contains none of these // XXX: This claims to return an IAuthData which contains none of these

View File

@ -106,9 +106,8 @@ export const useInteractiveRegistration = (
}); });
} }
}, },
requestEmailToken: async (): Promise<{ sid: string }> => { requestEmailToken: async (): Promise<{ sid: string }> =>
return Promise.resolve({ sid: "dummy" }); Promise.resolve({ sid: "dummy" }),
},
}); });
// XXX: This claims to return an IAuthData which contains none of these // XXX: This claims to return an IAuthData which contains none of these

View File

@ -22,7 +22,7 @@ import {
} from "./ConfigOptions"; } from "./ConfigOptions";
export class Config { export class Config {
private static internalInstance: Config; private static internalInstance: Config | undefined;
public static get(): ConfigOptions { public static get(): ConfigOptions {
if (!this.internalInstance?.config) if (!this.internalInstance?.config)
@ -31,22 +31,22 @@ export class Config {
} }
public static async init(): Promise<void> { public static async init(): Promise<void> {
if (Config.internalInstance?.initPromise) { if (!Config.internalInstance?.initPromise) {
return Config.internalInstance.initPromise; const internalInstance = new Config();
} Config.internalInstance = internalInstance;
Config.internalInstance = new Config();
Config.internalInstance.initPromise = downloadConfig("../config.json").then( Config.internalInstance.initPromise = downloadConfig(
(config) => { "../config.json",
Config.internalInstance.config = { ...DEFAULT_CONFIG, ...config }; ).then((config) => {
}, internalInstance.config = { ...DEFAULT_CONFIG, ...config };
); });
}
return Config.internalInstance.initPromise; return Config.internalInstance.initPromise;
} }
/** /**
* This is a alternative initializer that does not load anything * This is a alternative initializer that does not load anything
* from a hosted config file but instead just initializes the conifg using the * from a hosted config file but instead just initializes the config using the
* default config. * default config.
* *
* It is supposed to only be used in tests. (It is executed in `vite.setup.js`) * It is supposed to only be used in tests. (It is executed in `vite.setup.js`)

View File

@ -60,19 +60,20 @@ export class MatrixKeyProvider extends BaseKeyProvider {
encryptionKeyIndex: number, encryptionKeyIndex: number,
participantId: string, participantId: string,
): void => { ): void => {
createKeyMaterialFromBuffer(encryptionKey) createKeyMaterialFromBuffer(encryptionKey).then(
.then((keyMaterial) => { (keyMaterial) => {
this.onSetEncryptionKey(keyMaterial, participantId, encryptionKeyIndex); this.onSetEncryptionKey(keyMaterial, participantId, encryptionKeyIndex);
logger.debug( logger.debug(
`Sent new key to livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, `Sent new key to livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`,
); );
}) },
.catch((e) => { (e) => {
logger.error( logger.error(
`Failed to create key material from buffer for livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`, `Failed to create key material from buffer for livekit room=${this.rtcSession?.room.roomId} participantId=${participantId} encryptionKeyIndex=${encryptionKeyIndex}`,
e, e,
); );
}); },
);
}; };
} }

View File

@ -41,6 +41,7 @@ import {
} from "react"; } from "react";
import useMeasure from "react-use-measure"; import useMeasure from "react-use-measure";
import classNames from "classnames"; import classNames from "classnames";
import { logger } from "matrix-js-sdk/src/logger";
import styles from "./Grid.module.css"; import styles from "./Grid.module.css";
import { useMergedRefs } from "../useMergedRefs"; import { useMergedRefs } from "../useMergedRefs";
@ -362,7 +363,7 @@ export function Grid<
// Because we're using react-spring in imperative mode, we're responsible for // Because we're using react-spring in imperative mode, we're responsible for
// firing animations manually whenever the tiles array updates // firing animations manually whenever the tiles array updates
useEffect(() => { useEffect(() => {
void springRef.start(); springRef.start().forEach((p) => void p.catch(logger.error));
}, [placedTiles, springRef]); }, [placedTiles, springRef]);
const animateDraggedTile = ( const animateDraggedTile = (
@ -372,7 +373,7 @@ export function Grid<
const { tileId, tileX, tileY } = dragState.current!; const { tileId, tileX, tileY } = dragState.current!;
const tile = placedTiles.find((t) => t.id === tileId)!; const tile = placedTiles.find((t) => t.id === tileId)!;
void springRef.current springRef.current
.find((c) => (c.item as Tile<TileModel>).id === tileId) .find((c) => (c.item as Tile<TileModel>).id === tileId)
?.start( ?.start(
endOfGesture endOfGesture
@ -399,7 +400,8 @@ export function Grid<
((key): boolean => ((key): boolean =>
key === "zIndex" || key === "x" || key === "y"), key === "zIndex" || key === "x" || key === "y"),
}, },
); )
.catch(logger.error);
if (endOfGesture) if (endOfGesture)
callback({ callback({

View File

@ -133,14 +133,15 @@ export class Initializer {
// config // config
if (this.loadStates.config === LoadState.None) { if (this.loadStates.config === LoadState.None) {
this.loadStates.config = LoadState.Loading; this.loadStates.config = LoadState.Loading;
Config.init() Config.init().then(
.then(() => { () => {
this.loadStates.config = LoadState.Loaded; this.loadStates.config = LoadState.Loaded;
this.initStep(resolve); this.initStep(resolve);
}) },
.catch((e) => { (e) => {
logger.error("Failed to load config", e); logger.error("Failed to load config", e);
}); },
);
} }
//sentry (only initialize after the config is ready) //sentry (only initialize after the config is ready)

View File

@ -49,14 +49,18 @@ export function useOpenIDSFU(
const activeFocus = useActiveLivekitFocus(rtcSession); const activeFocus = useActiveLivekitFocus(rtcSession);
useEffect(() => { useEffect(() => {
(async (): Promise<void> => { if (activeFocus) {
const sfuConfig = activeFocus getSFUConfigWithOpenID(client, activeFocus).then(
? await getSFUConfigWithOpenID(client, activeFocus) (sfuConfig) => {
: undefined;
setSFUConfig(sfuConfig); setSFUConfig(sfuConfig);
})().catch((e) => { },
(e) => {
logger.error("Failed to get SFU config", e); logger.error("Failed to get SFU config", e);
}); },
);
} else {
setSFUConfig(undefined);
}
}, [client, activeFocus]); }, [client, activeFocus]);
return sfuConfig; return sfuConfig;

View File

@ -180,14 +180,12 @@ export const GroupCallView: FC<Props> = ({
if (widget && preload && skipLobby) { if (widget && preload && skipLobby) {
// In preload mode without lobby we wait for a join action before entering // In preload mode without lobby we wait for a join action before entering
const onJoin = (ev: CustomEvent<IWidgetApiRequest>): void => { const onJoin = (ev: CustomEvent<IWidgetApiRequest>): void => {
defaultDeviceSetup(ev.detail.data as unknown as JoinCallData) (async (): Promise<void> => {
.catch((e) => { await defaultDeviceSetup(ev.detail.data as unknown as JoinCallData);
logger.error("Error setting up default devices", e); await enterRTCSession(rtcSession, perParticipantE2EE);
}) widget!.api.transport.reply(ev.detail, {});
.then(async () => enterRTCSession(rtcSession, perParticipantE2EE)) })().catch((e) => {
.then(() => widget!.api.transport.reply(ev.detail, {})) logger.error("Error joining RTC session", e);
.catch((e) => {
logger.error("Error entering RTC session", e);
}); });
}; };
widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin); widget.lazyActions.on(ElementWidgetActions.JoinCall, onJoin);
@ -196,13 +194,11 @@ export const GroupCallView: FC<Props> = ({
}; };
} else if (widget && !preload && skipLobby) { } else if (widget && !preload && skipLobby) {
// No lobby and no preload: we enter the rtc session right away // No lobby and no preload: we enter the rtc session right away
defaultDeviceSetup({ audioInput: null, videoInput: null }) (async (): Promise<void> => {
.catch((e) => { await defaultDeviceSetup({ audioInput: null, videoInput: null });
logger.error("Error setting up default devices", e); await enterRTCSession(rtcSession, perParticipantE2EE);
}) })().catch((e) => {
.then(async () => enterRTCSession(rtcSession, perParticipantE2EE)) logger.error("Error joining RTC session", e);
.catch((e) => {
logger.error("Error entering RTC session", e);
}); });
} }
}, [rtcSession, preload, skipLobby, perParticipantE2EE]); }, [rtcSession, preload, skipLobby, perParticipantE2EE]);

View File

@ -478,12 +478,14 @@ export const InCallView: FC<InCallViewProps> = ({
); );
const toggleScreensharing = useCallback(() => { const toggleScreensharing = useCallback(() => {
void localParticipant.setScreenShareEnabled(!isScreenShareEnabled, { localParticipant
.setScreenShareEnabled(!isScreenShareEnabled, {
audio: true, audio: true,
selfBrowserSurface: "include", selfBrowserSurface: "include",
surfaceSwitching: "include", surfaceSwitching: "include",
systemAudio: "include", systemAudio: "include",
}); })
.catch(logger.error);
}, [localParticipant, isScreenShareEnabled]); }, [localParticipant, isScreenShareEnabled]);
let footer: JSX.Element | null; let footer: JSX.Element | null;

View File

@ -69,11 +69,11 @@ export const RoomPage: FC = () => {
if (!loading && !authenticated && displayName && !widget) { if (!loading && !authenticated && displayName && !widget) {
setIsRegistering(true); setIsRegistering(true);
registerPasswordlessUser(displayName) registerPasswordlessUser(displayName)
.finally(() => {
setIsRegistering(false);
})
.catch((e) => { .catch((e) => {
logger.error("Failed to register passwordless user", e); logger.error("Failed to register passwordless user", e);
})
.finally(() => {
setIsRegistering(false);
}); });
} }
}, [ }, [

View File

@ -159,10 +159,9 @@ export const useLoadGroupCall = (
viaServers: string[], viaServers: string[],
onKnockSent: () => void, onKnockSent: () => void,
): Promise<Room> => { ): Promise<Room> => {
let joinedRoom: Room | null = null;
await client.knockRoom(roomId, { viaServers }); await client.knockRoom(roomId, { viaServers });
onKnockSent(); onKnockSent();
const invitePromise = new Promise<void>((resolve, reject) => { return await new Promise<Room>((resolve, reject) => {
client.on( client.on(
RoomEvent.MyMembership, RoomEvent.MyMembership,
(room, membership, prevMembership): void => { (room, membership, prevMembership): void => {
@ -172,14 +171,10 @@ export const useLoadGroupCall = (
membership === KnownMembership.Invite && membership === KnownMembership.Invite &&
prevMembership === KnownMembership.Knock prevMembership === KnownMembership.Knock
) { ) {
client client.joinRoom(room.roomId, { viaServers }).then((room) => {
.joinRoom(room.roomId, { viaServers })
.then((room) => {
joinedRoom = room;
logger.log("Auto-joined %s", room.roomId); logger.log("Auto-joined %s", room.roomId);
resolve(); resolve(room);
}) }, reject);
.catch((e) => reject(e));
} }
if (membership === KnownMembership.Ban) reject(bannedError()); if (membership === KnownMembership.Ban) reject(bannedError());
if (membership === KnownMembership.Leave) if (membership === KnownMembership.Leave)
@ -187,11 +182,6 @@ export const useLoadGroupCall = (
}, },
); );
}); });
await invitePromise;
if (!joinedRoom) {
throw new Error("Failed to join room after knocking.");
}
return joinedRoom;
}; };
const fetchOrCreateRoom = async (): Promise<Room> => { const fetchOrCreateRoom = async (): Promise<Room> => {

View File

@ -127,9 +127,14 @@ const widgetPostHangupProcedure = async (
// we need to wait until the callEnded event is tracked on posthog. // we need to wait until the callEnded event is tracked on posthog.
// Otherwise the iFrame gets killed before the callEnded event got tracked. // Otherwise the iFrame gets killed before the callEnded event got tracked.
await new Promise((resolve) => window.setTimeout(resolve, 10)); // 10ms await new Promise((resolve) => window.setTimeout(resolve, 10)); // 10ms
await widget.api.setAlwaysOnScreen(false);
PosthogAnalytics.instance.logout(); PosthogAnalytics.instance.logout();
try {
await widget.api.setAlwaysOnScreen(false);
} catch (e) {
logger.error("Failed to set call widget `alwaysOnScreen` to false", e);
}
// We send the hangup event after the memberships have been updated // We send the hangup event after the memberships have been updated
// calling leaveRTCSession. // calling leaveRTCSession.
// We need to wait because this makes the client hosting this widget killing the IFrame. // We need to wait because this makes the client hosting this widget killing the IFrame.

View File

@ -236,11 +236,7 @@ class IndexedDBLogStore {
return this.flushAgainPromise; return this.flushAgainPromise;
} }
// queue up a flush to occur immediately after the pending one completes. // queue up a flush to occur immediately after the pending one completes.
this.flushAgainPromise = this.flushPromise this.flushAgainPromise = this.flushPromise.then(this.flush).then(() => {
.then(async () => {
return this.flush();
})
.then(() => {
this.flushAgainPromise = undefined; this.flushAgainPromise = undefined;
}); });
return this.flushAgainPromise; return this.flushAgainPromise;

View File

@ -30,9 +30,8 @@ export function useWakeLock(): void {
// so we need to reacquire it on visibility changes // so we need to reacquire it on visibility changes
const onVisibilityChange = (): void => { const onVisibilityChange = (): void => {
if (document.visibilityState === "visible") { if (document.visibilityState === "visible") {
navigator.wakeLock navigator.wakeLock.request("screen").then(
.request("screen") (newLock) => {
.then((newLock) => {
lock = newLock; lock = newLock;
// Handle the edge case where this component unmounts before the // Handle the edge case where this component unmounts before the
// promise resolves // promise resolves
@ -40,10 +39,11 @@ export function useWakeLock(): void {
lock lock
.release() .release()
.catch((e) => logger.warn("Can't release wake lock", e)); .catch((e) => logger.warn("Can't release wake lock", e));
}) },
.catch((e) => { (e) => {
logger.warn("Can't acquire wake lock", e); logger.warn("Can't acquire wake lock", e);
}); },
);
} }
}; };

View File

@ -269,40 +269,40 @@ export async function createRoom(
}); });
// Wait for the room to arrive // Wait for the room to arrive
await new Promise<void>((resolve, reject) => { const roomId = await new Promise<string>((resolve, reject) => {
const onRoom = (room: Room): void => {
createPromise
.then((result) => {
if (room.roomId === result.room_id) {
resolve();
cleanUp();
}
})
.catch((e) => {
logger.error("Failed to wait for the room to arrive", e);
});
};
createPromise.catch((e) => { createPromise.catch((e) => {
reject(e); reject(e);
cleanUp(); cleanUp();
}); });
const onRoom = (room: Room): void => {
createPromise.then(
(result) => {
if (room.roomId === result.room_id) {
resolve(room.roomId);
cleanUp();
}
},
(e) => {
logger.error("Failed to wait for the room to arrive", e);
},
);
};
const cleanUp = (): void => { const cleanUp = (): void => {
client.off(ClientEvent.Room, onRoom); client.off(ClientEvent.Room, onRoom);
}; };
client.on(ClientEvent.Room, onRoom); client.on(ClientEvent.Room, onRoom);
}); });
const result = await createPromise; let password: string | undefined;
let password;
if (e2ee == E2eeType.SHARED_KEY) { if (e2ee == E2eeType.SHARED_KEY) {
password = secureRandomBase64Url(16); password = secureRandomBase64Url(16);
saveKeyForRoom(result.room_id, password); saveKeyForRoom(roomId, password);
} }
return { return {
roomId: result.room_id, roomId,
alias: e2ee ? undefined : fullAliasFromRoomName(name, client), alias: e2ee ? undefined : fullAliasFromRoomName(name, client),
password, password,
}; };