Use MatrixClientPeg::safeGet for strict typing (#10989)

This commit is contained in:
Michael Telatynski 2023-06-21 17:29:44 +01:00 committed by GitHub
parent d64018ce26
commit 9b5b053148
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 225 additions and 203 deletions

View file

@ -59,7 +59,7 @@ export default class IdentityAuthClient {
} }
private get matrixClient(): MatrixClient { private get matrixClient(): MatrixClient {
return this.tempClient ? this.tempClient : MatrixClientPeg.get(); return this.tempClient ? this.tempClient : MatrixClientPeg.safeGet();
} }
private writeToken(): void { private writeToken(): void {
@ -176,7 +176,7 @@ export default class IdentityAuthClient {
} }
public async registerForToken(check = true): Promise<string> { public async registerForToken(check = true): Promise<string> {
const hsOpenIdToken = await MatrixClientPeg.get().getOpenIdToken(); const hsOpenIdToken = await MatrixClientPeg.safeGet().getOpenIdToken();
// XXX: The spec is `token`, but we used `access_token` for a Sydent release. // XXX: The spec is `token`, but we used `access_token` for a Sydent release.
const { access_token: accessToken, token } = await this.matrixClient.registerWithIdentityServer(hsOpenIdToken); const { access_token: accessToken, token } = await this.matrixClient.registerWithIdentityServer(hsOpenIdToken);
const identityAccessToken = token ? token : accessToken; const identityAccessToken = token ? token : accessToken;

View file

@ -192,7 +192,7 @@ export default class LegacyCallHandler extends EventEmitter {
if (this.shouldObeyAssertedfIdentity()) { if (this.shouldObeyAssertedfIdentity()) {
const nativeUser = this.assertedIdentityNativeUsers.get(call.callId); const nativeUser = this.assertedIdentityNativeUsers.get(call.callId);
if (nativeUser) { if (nativeUser) {
const room = findDMForUser(MatrixClientPeg.get(), nativeUser); const room = findDMForUser(MatrixClientPeg.safeGet(), nativeUser);
if (room) return room.roomId; if (room) return room.roomId;
} }
} }
@ -214,7 +214,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
if (SettingsStore.getValue(UIFeature.Voip)) { if (SettingsStore.getValue(UIFeature.Voip)) {
MatrixClientPeg.get().on(CallEventHandlerEvent.Incoming, this.onCallIncoming); MatrixClientPeg.safeGet().on(CallEventHandlerEvent.Incoming, this.onCallIncoming);
} }
this.checkProtocols(CHECK_PROTOCOLS_ATTEMPTS); this.checkProtocols(CHECK_PROTOCOLS_ATTEMPTS);
@ -271,7 +271,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
public isForcedSilent(): boolean { public isForcedSilent(): boolean {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
return localNotificationsAreSilenced(cli); return localNotificationsAreSilenced(cli);
} }
@ -311,7 +311,7 @@ export default class LegacyCallHandler extends EventEmitter {
private async checkProtocols(maxTries: number): Promise<void> { private async checkProtocols(maxTries: number): Promise<void> {
try { try {
const protocols = await MatrixClientPeg.get().getThirdpartyProtocols(); const protocols = await MatrixClientPeg.safeGet().getThirdpartyProtocols();
if (protocols[PROTOCOL_PSTN] !== undefined) { if (protocols[PROTOCOL_PSTN] !== undefined) {
this.supportsPstnProtocol = Boolean(protocols[PROTOCOL_PSTN]); this.supportsPstnProtocol = Boolean(protocols[PROTOCOL_PSTN]);
@ -358,7 +358,7 @@ export default class LegacyCallHandler extends EventEmitter {
public async pstnLookup(phoneNumber: string): Promise<ThirdpartyLookupResponse[]> { public async pstnLookup(phoneNumber: string): Promise<ThirdpartyLookupResponse[]> {
try { try {
return await MatrixClientPeg.get().getThirdpartyUser( return await MatrixClientPeg.safeGet().getThirdpartyUser(
this.pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN, this.pstnSupportPrefixed ? PROTOCOL_PSTN_PREFIXED : PROTOCOL_PSTN,
{ {
"m.id.phone": phoneNumber, "m.id.phone": phoneNumber,
@ -372,7 +372,7 @@ export default class LegacyCallHandler extends EventEmitter {
public async sipVirtualLookup(nativeMxid: string): Promise<ThirdpartyLookupResponse[]> { public async sipVirtualLookup(nativeMxid: string): Promise<ThirdpartyLookupResponse[]> {
try { try {
return await MatrixClientPeg.get().getThirdpartyUser(PROTOCOL_SIP_VIRTUAL, { return await MatrixClientPeg.safeGet().getThirdpartyUser(PROTOCOL_SIP_VIRTUAL, {
native_mxid: nativeMxid, native_mxid: nativeMxid,
}); });
} catch (e) { } catch (e) {
@ -383,7 +383,7 @@ export default class LegacyCallHandler extends EventEmitter {
public async sipNativeLookup(virtualMxid: string): Promise<ThirdpartyLookupResponse[]> { public async sipNativeLookup(virtualMxid: string): Promise<ThirdpartyLookupResponse[]> {
try { try {
return await MatrixClientPeg.get().getThirdpartyUser(PROTOCOL_SIP_NATIVE, { return await MatrixClientPeg.safeGet().getThirdpartyUser(PROTOCOL_SIP_NATIVE, {
virtual_mxid: virtualMxid, virtual_mxid: virtualMxid,
}); });
} catch (e) { } catch (e) {
@ -394,7 +394,7 @@ export default class LegacyCallHandler extends EventEmitter {
private onCallIncoming = (call: MatrixCall): void => { private onCallIncoming = (call: MatrixCall): void => {
// if the runtime env doesn't do VoIP, stop here. // if the runtime env doesn't do VoIP, stop here.
if (!MatrixClientPeg.get().supportsVoip()) { if (!MatrixClientPeg.get()?.supportsVoip()) {
return; return;
} }
@ -415,7 +415,7 @@ export default class LegacyCallHandler extends EventEmitter {
// get ready to send encrypted events in the room, so if the user does answer // get ready to send encrypted events in the room, so if the user does answer
// the call, we'll be ready to send. NB. This is the protocol-level room ID not // the call, we'll be ready to send. NB. This is the protocol-level room ID not
// the mapped one: that's where we'll send the events. // the mapped one: that's where we'll send the events.
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const room = cli.getRoom(call.roomId); const room = cli.getRoom(call.roomId);
if (room) cli.prepareToEncrypt(room); if (room) cli.prepareToEncrypt(room);
}; };
@ -463,7 +463,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
public getAllActiveCallsForPip(roomId: string): MatrixCall[] { public getAllActiveCallsForPip(roomId: string): MatrixCall[] {
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.safeGet().getRoom(roomId);
if (room && WidgetLayoutStore.instance.hasMaximisedWidget(room)) { if (room && WidgetLayoutStore.instance.hasMaximisedWidget(room)) {
// This checks if there is space for the call view in the aux panel // This checks if there is space for the call view in the aux panel
// If there is no space any call should be displayed in PiP // If there is no space any call should be displayed in PiP
@ -570,7 +570,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
if ( if (
MatrixClientPeg.get().getTurnServers().length === 0 && MatrixClientPeg.safeGet().getTurnServers().length === 0 &&
SettingsStore.getValue("fallbackICEServerAllowed") === null SettingsStore.getValue("fallbackICEServerAllowed") === null
) { ) {
this.showICEFallbackPrompt(); this.showICEFallbackPrompt();
@ -638,7 +638,7 @@ export default class LegacyCallHandler extends EventEmitter {
// this if we want the actual, native room to exist (which we do). This is why it's // this if we want the actual, native room to exist (which we do). This is why it's
// important to only obey asserted identity in trusted environments, since anyone you're // important to only obey asserted identity in trusted environments, since anyone you're
// on a call with can cause you to send a room invite to someone. // on a call with can cause you to send a room invite to someone.
await ensureDMExists(MatrixClientPeg.get(), newNativeAssertedIdentity); await ensureDMExists(MatrixClientPeg.safeGet(), newNativeAssertedIdentity);
const newMappedRoomId = this.roomIdForCall(call); const newMappedRoomId = this.roomIdForCall(call);
logger.log(`Old room ID: ${mappedRoomId}, new room ID: ${newMappedRoomId}`); logger.log(`Old room ID: ${mappedRoomId}, new room ID: ${newMappedRoomId}`);
@ -678,7 +678,7 @@ export default class LegacyCallHandler extends EventEmitter {
switch (newState) { switch (newState) {
case CallState.Ringing: { case CallState.Ringing: {
const incomingCallPushRule = new PushProcessor(MatrixClientPeg.get()).getPushRuleById( const incomingCallPushRule = new PushProcessor(MatrixClientPeg.safeGet()).getPushRuleById(
RuleId.IncomingCall, RuleId.IncomingCall,
); );
const pushRuleEnabled = incomingCallPushRule?.enabled; const pushRuleEnabled = incomingCallPushRule?.enabled;
@ -825,7 +825,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
private showICEFallbackPrompt(): void { private showICEFallbackPrompt(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
Modal.createDialog( Modal.createDialog(
QuestionDialog, QuestionDialog,
{ {
@ -907,6 +907,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> { private async placeMatrixCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> {
const cli = MatrixClientPeg.safeGet();
const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId; const mappedRoomId = (await VoipUserMapper.sharedInstance().getOrCreateVirtualRoomForRoom(roomId)) || roomId;
logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId); logger.debug("Mapped real room " + roomId + " to room ID " + mappedRoomId);
@ -916,15 +917,15 @@ export default class LegacyCallHandler extends EventEmitter {
// in this queue, and since we're about to place a new call, they can only be events from // in this queue, and since we're about to place a new call, they can only be events from
// previous calls that are probably stale by now, so just cancel them. // previous calls that are probably stale by now, so just cancel them.
if (mappedRoomId !== roomId) { if (mappedRoomId !== roomId) {
const mappedRoom = MatrixClientPeg.get().getRoom(mappedRoomId); const mappedRoom = cli.getRoom(mappedRoomId);
if (mappedRoom?.getPendingEvents().length) { if (mappedRoom?.getPendingEvents().length) {
Resend.cancelUnsentEvents(mappedRoom); Resend.cancelUnsentEvents(mappedRoom);
} }
} }
const timeUntilTurnCresExpire = MatrixClientPeg.get().getTurnServersExpiry() - Date.now(); const timeUntilTurnCresExpire = cli.getTurnServersExpiry() - Date.now();
logger.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms"); logger.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms");
const call = MatrixClientPeg.get().createCall(mappedRoomId)!; const call = cli.createCall(mappedRoomId)!;
try { try {
this.addCallForRoom(roomId, call); this.addCallForRoom(roomId, call);
@ -953,6 +954,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
public async placeCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> { public async placeCall(roomId: string, type: CallType, transferee?: MatrixCall): Promise<void> {
const cli = MatrixClientPeg.safeGet();
// Pause current broadcast, if any // Pause current broadcast, if any
SdkContextClass.instance.voiceBroadcastPlaybacksStore.getCurrent()?.pause(); SdkContextClass.instance.voiceBroadcastPlaybacksStore.getCurrent()?.pause();
@ -969,7 +971,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
// if the runtime env doesn't do VoIP, whine. // if the runtime env doesn't do VoIP, whine.
if (!MatrixClientPeg.get().supportsVoip()) { if (!cli.supportsVoip()) {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("Calls are unsupported"), title: _t("Calls are unsupported"),
description: _t("You cannot place calls in this browser."), description: _t("You cannot place calls in this browser."),
@ -977,7 +979,7 @@ export default class LegacyCallHandler extends EventEmitter {
return; return;
} }
if (MatrixClientPeg.get().getSyncState() === SyncState.Error) { if (cli.getSyncState() === SyncState.Error) {
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: _t("Connectivity to the server has been lost"), title: _t("Connectivity to the server has been lost"),
description: _t("You cannot place calls without a connection to the server."), description: _t("You cannot place calls without a connection to the server."),
@ -994,7 +996,7 @@ export default class LegacyCallHandler extends EventEmitter {
return; return;
} }
const room = MatrixClientPeg.get().getRoom(roomId); const room = cli.getRoom(roomId);
if (!room) { if (!room) {
logger.error(`Room ${roomId} does not exist.`); logger.error(`Room ${roomId} does not exist.`);
return; return;
@ -1095,7 +1097,7 @@ export default class LegacyCallHandler extends EventEmitter {
nativeUserId = userId; nativeUserId = userId;
} }
const roomId = await ensureDMExists(MatrixClientPeg.get(), nativeUserId); const roomId = await ensureDMExists(MatrixClientPeg.safeGet(), nativeUserId);
if (!roomId) { if (!roomId) {
throw new Error("Failed to ensure DM exists for dialing number"); throw new Error("Failed to ensure DM exists for dialing number");
} }
@ -1135,7 +1137,7 @@ export default class LegacyCallHandler extends EventEmitter {
public async startTransferToMatrixID(call: MatrixCall, destination: string, consultFirst: boolean): Promise<void> { public async startTransferToMatrixID(call: MatrixCall, destination: string, consultFirst: boolean): Promise<void> {
if (consultFirst) { if (consultFirst) {
const dmRoomId = await ensureDMExists(MatrixClientPeg.get(), destination); const dmRoomId = await ensureDMExists(MatrixClientPeg.safeGet(), destination);
if (!dmRoomId) { if (!dmRoomId) {
logger.log("Failed to transfer call, could not ensure dm exists"); logger.log("Failed to transfer call, could not ensure dm exists");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
@ -1194,7 +1196,7 @@ export default class LegacyCallHandler extends EventEmitter {
} }
private async placeJitsiCall(roomId: string, type: CallType): Promise<void> { private async placeJitsiCall(roomId: string, type: CallType): Promise<void> {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
logger.info(`Place conference call in ${roomId}`); logger.info(`Place conference call in ${roomId}`);
dis.dispatch({ action: "appsDrawer", show: true }); dis.dispatch({ action: "appsDrawer", show: true });

View file

@ -278,7 +278,7 @@ export function handleInvalidStoreError(e: InvalidStoreError): Promise<void> | v
} }
}) })
.then(() => { .then(() => {
return MatrixClientPeg.get().store.deleteAllData(); return MatrixClientPeg.safeGet().store.deleteAllData();
}) })
.then(() => { .then(() => {
PlatformPeg.get()?.reload(); PlatformPeg.get()?.reload();
@ -541,8 +541,8 @@ export async function setLoggedIn(credentials: IMatrixClientCreds): Promise<Matr
* @returns {Promise} promise which resolves to the new MatrixClient once it has been started * @returns {Promise} promise which resolves to the new MatrixClient once it has been started
*/ */
export async function hydrateSession(credentials: IMatrixClientCreds): Promise<MatrixClient> { export async function hydrateSession(credentials: IMatrixClientCreds): Promise<MatrixClient> {
const oldUserId = MatrixClientPeg.get().getUserId(); const oldUserId = MatrixClientPeg.safeGet().getUserId();
const oldDeviceId = MatrixClientPeg.get().getDeviceId(); const oldDeviceId = MatrixClientPeg.safeGet().getDeviceId();
stopMatrixClient(); // unsets MatrixClientPeg.get() stopMatrixClient(); // unsets MatrixClientPeg.get()
localStorage.removeItem("mx_soft_logout"); localStorage.removeItem("mx_soft_logout");
@ -603,7 +603,7 @@ async function doSetLoggedIn(credentials: IMatrixClientCreds, clearStorageEnable
} }
MatrixClientPeg.replaceUsingCreds(credentials); MatrixClientPeg.replaceUsingCreds(credentials);
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
setSentryUser(credentials.userId); setSentryUser(credentials.userId);
@ -724,7 +724,7 @@ export function logout(): void {
PosthogAnalytics.instance.logout(); PosthogAnalytics.instance.logout();
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get()!.isGuest()) {
// logout doesn't work for guest sessions // logout doesn't work for guest sessions
// Also we sometimes want to re-log in a guest session if we abort the login. // Also we sometimes want to re-log in a guest session if we abort the login.
// defer until next tick because it calls a synchronous dispatch, and we are likely here from a dispatch. // defer until next tick because it calls a synchronous dispatch, and we are likely here from a dispatch.
@ -733,7 +733,7 @@ export function logout(): void {
} }
_isLoggingOut = true; _isLoggingOut = true;
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.get()!;
PlatformPeg.get()?.destroyPickleKey(client.getSafeUserId(), client.getDeviceId() ?? ""); PlatformPeg.get()?.destroyPickleKey(client.getSafeUserId(), client.getDeviceId() ?? "");
client.logout(true).then(onLoggedOut, (err) => { client.logout(true).then(onLoggedOut, (err) => {
// Just throwing an error here is going to be very unhelpful // Just throwing an error here is going to be very unhelpful

View file

@ -73,7 +73,7 @@ export interface IMatrixClientPeg {
*/ */
getHomeserverName(): string | null; getHomeserverName(): string | null;
get(): MatrixClient; get(): MatrixClient | null;
safeGet(): MatrixClient; safeGet(): MatrixClient;
unset(): void; unset(): void;
assign(): Promise<any>; assign(): Promise<any>;
@ -142,7 +142,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
// used if we tear it down & recreate it with a different store // used if we tear it down & recreate it with a different store
private currentClientCreds: IMatrixClientCreds | null = null; private currentClientCreds: IMatrixClientCreds | null = null;
public get(): MatrixClient { public get(): MatrixClient | null {
return this.matrixClient; return this.matrixClient;
} }

View file

@ -99,14 +99,14 @@ export default class MediaDeviceHandler extends EventEmitter {
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput"); const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput"); const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
await MatrixClientPeg.get().getMediaHandler().setAudioInput(audioDeviceId); await MatrixClientPeg.safeGet().getMediaHandler().setAudioInput(audioDeviceId);
await MatrixClientPeg.get().getMediaHandler().setVideoInput(videoDeviceId); await MatrixClientPeg.safeGet().getMediaHandler().setVideoInput(videoDeviceId);
await MediaDeviceHandler.updateAudioSettings(); await MediaDeviceHandler.updateAudioSettings();
} }
private static async updateAudioSettings(): Promise<void> { private static async updateAudioSettings(): Promise<void> {
await MatrixClientPeg.get().getMediaHandler().setAudioSettings({ await MatrixClientPeg.safeGet().getMediaHandler().setAudioSettings({
autoGainControl: MediaDeviceHandler.getAudioAutoGainControl(), autoGainControl: MediaDeviceHandler.getAudioAutoGainControl(),
echoCancellation: MediaDeviceHandler.getAudioEchoCancellation(), echoCancellation: MediaDeviceHandler.getAudioEchoCancellation(),
noiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression(), noiseSuppression: MediaDeviceHandler.getAudioNoiseSuppression(),
@ -125,7 +125,7 @@ export default class MediaDeviceHandler extends EventEmitter {
*/ */
public async setAudioInput(deviceId: string): Promise<void> { public async setAudioInput(deviceId: string): Promise<void> {
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId); SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
return MatrixClientPeg.get().getMediaHandler().setAudioInput(deviceId); return MatrixClientPeg.safeGet().getMediaHandler().setAudioInput(deviceId);
} }
/** /**
@ -135,7 +135,7 @@ export default class MediaDeviceHandler extends EventEmitter {
*/ */
public async setVideoInput(deviceId: string): Promise<void> { public async setVideoInput(deviceId: string): Promise<void> {
SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId); SettingsStore.setValue("webrtc_videoinput", null, SettingLevel.DEVICE, deviceId);
return MatrixClientPeg.get().getMediaHandler().setVideoInput(deviceId); return MatrixClientPeg.safeGet().getMediaHandler().setVideoInput(deviceId);
} }
public async setDevice(deviceId: string, kind: MediaDeviceKindEnum): Promise<void> { public async setDevice(deviceId: string, kind: MediaDeviceKindEnum): Promise<void> {

View file

@ -91,7 +91,7 @@ const msgTypeHandlers: Record<string, (event: MatrixEvent) => string | null> = {
return null; return null;
} }
return TextForEvent.textForEvent(event, MatrixClientPeg.get()); return TextForEvent.textForEvent(event, MatrixClientPeg.safeGet());
}, },
}; };
@ -111,13 +111,13 @@ class NotifierClass {
if (msgType && msgTypeHandlers.hasOwnProperty(msgType)) { if (msgType && msgTypeHandlers.hasOwnProperty(msgType)) {
return msgTypeHandlers[msgType](ev); return msgTypeHandlers[msgType](ev);
} }
return TextForEvent.textForEvent(ev, MatrixClientPeg.get()); return TextForEvent.textForEvent(ev, MatrixClientPeg.safeGet());
} }
// XXX: exported for tests // XXX: exported for tests
public displayPopupNotification(ev: MatrixEvent, room: Room): void { public displayPopupNotification(ev: MatrixEvent, room: Room): void {
const plaf = PlatformPeg.get(); const plaf = PlatformPeg.get();
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
if (!plaf) { if (!plaf) {
return; return;
} }
@ -215,7 +215,7 @@ class NotifierClass {
// XXX: Exported for tests // XXX: Exported for tests
public async playAudioNotification(ev: MatrixEvent, room: Room): Promise<void> { public async playAudioNotification(ev: MatrixEvent, room: Room): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
if (localNotificationsAreSilenced(cli)) { if (localNotificationsAreSilenced(cli)) {
return; return;
} }
@ -246,20 +246,21 @@ class NotifierClass {
} }
public start(): void { public start(): void {
MatrixClientPeg.get().on(RoomEvent.Timeline, this.onEvent); const cli = MatrixClientPeg.safeGet();
MatrixClientPeg.get().on(RoomEvent.Receipt, this.onRoomReceipt); cli.on(RoomEvent.Timeline, this.onEvent);
MatrixClientPeg.get().on(MatrixEventEvent.Decrypted, this.onEventDecrypted); cli.on(RoomEvent.Receipt, this.onRoomReceipt);
MatrixClientPeg.get().on(ClientEvent.Sync, this.onSyncStateChange); cli.on(MatrixEventEvent.Decrypted, this.onEventDecrypted);
cli.on(ClientEvent.Sync, this.onSyncStateChange);
this.toolbarHidden = false; this.toolbarHidden = false;
this.isSyncing = false; this.isSyncing = false;
} }
public stop(): void { public stop(): void {
if (MatrixClientPeg.get()) { if (MatrixClientPeg.get()) {
MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onEvent); MatrixClientPeg.get()!.removeListener(RoomEvent.Timeline, this.onEvent);
MatrixClientPeg.get().removeListener(RoomEvent.Receipt, this.onRoomReceipt); MatrixClientPeg.get()!.removeListener(RoomEvent.Receipt, this.onRoomReceipt);
MatrixClientPeg.get().removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted); MatrixClientPeg.get()!.removeListener(MatrixEventEvent.Decrypted, this.onEventDecrypted);
MatrixClientPeg.get().removeListener(ClientEvent.Sync, this.onSyncStateChange); MatrixClientPeg.get()!.removeListener(ClientEvent.Sync, this.onSyncStateChange);
} }
this.isSyncing = false; this.isSyncing = false;
} }
@ -400,7 +401,7 @@ class NotifierClass {
// wait for first non-cached sync to complete // wait for first non-cached sync to complete
if (![SyncState.Stopped, SyncState.Error].includes(state) && !data?.fromCache) { if (![SyncState.Stopped, SyncState.Error].includes(state) && !data?.fromCache) {
createLocalNotificationSettingsIfNeeded(MatrixClientPeg.get()); createLocalNotificationSettingsIfNeeded(MatrixClientPeg.safeGet());
} }
}; };
@ -413,9 +414,9 @@ class NotifierClass {
): void => { ): void => {
if (!data.liveEvent) return; // only notify for new things, not old. if (!data.liveEvent) return; // only notify for new things, not old.
if (!this.isSyncing) return; // don't alert for any messages initially if (!this.isSyncing) return; // don't alert for any messages initially
if (ev.getSender() === MatrixClientPeg.get().getUserId()) return; if (ev.getSender() === MatrixClientPeg.safeGet().getUserId()) return;
MatrixClientPeg.get().decryptEventIfNeeded(ev); MatrixClientPeg.safeGet().decryptEventIfNeeded(ev);
// If it's an encrypted event and the type is still 'm.room.encrypted', // If it's an encrypted event and the type is still 'm.room.encrypted',
// it hasn't yet been decrypted, so wait until it is. // it hasn't yet been decrypted, so wait until it is.
@ -473,14 +474,14 @@ class NotifierClass {
roomId = nativeRoomId; roomId = nativeRoomId;
} }
} }
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.safeGet().getRoom(roomId);
if (!room) { if (!room) {
// e.g we are in the process of joining a room. // e.g we are in the process of joining a room.
// Seen in the cypress lazy-loading test. // Seen in the cypress lazy-loading test.
return; return;
} }
const actions = MatrixClientPeg.get().getPushActionsForEvent(ev); const actions = MatrixClientPeg.safeGet().getPushActionsForEvent(ev);
if (actions?.notify) { if (actions?.notify) {
this.performCustomEventHandling(ev); this.performCustomEventHandling(ev);

View file

@ -97,12 +97,12 @@ class Presence {
const oldState = this.state; const oldState = this.state;
this.state = newState; this.state = newState;
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.safeGet().isGuest()) {
return; // don't try to set presence when a guest; it won't work. return; // don't try to set presence when a guest; it won't work.
} }
try { try {
await MatrixClientPeg.get().setPresence({ presence: this.state }); await MatrixClientPeg.safeGet().setPresence({ presence: this.state });
logger.info("Presence:", newState); logger.info("Presence:", newState);
} catch (err) { } catch (err) {
logger.error("Failed to set presence:", err); logger.error("Failed to set presence:", err);

View file

@ -131,7 +131,7 @@ export default class ScalarAuthClient {
private checkToken(token: string): Promise<string> { private checkToken(token: string): Promise<string> {
return this.getAccountName(token) return this.getAccountName(token)
.then((userId) => { .then((userId) => {
const me = MatrixClientPeg.get().getUserId(); const me = MatrixClientPeg.safeGet().getUserId();
if (userId !== me) { if (userId !== me) {
throw new Error("Scalar token is owned by someone else: " + me); throw new Error("Scalar token is owned by someone else: " + me);
} }
@ -157,7 +157,7 @@ export default class ScalarAuthClient {
const parsedImRestUrl = parseUrl(this.apiUrl); const parsedImRestUrl = parseUrl(this.apiUrl);
parsedImRestUrl.pathname = ""; parsedImRestUrl.pathname = "";
return startTermsFlow( return startTermsFlow(
MatrixClientPeg.get(), MatrixClientPeg.safeGet(),
[new Service(SERVICE_TYPES.IM, parsedImRestUrl.toString(), token)], [new Service(SERVICE_TYPES.IM, parsedImRestUrl.toString(), token)],
this.termsInteractionCallback, this.termsInteractionCallback,
).then(() => { ).then(() => {
@ -171,7 +171,7 @@ export default class ScalarAuthClient {
public registerForToken(): Promise<string> { public registerForToken(): Promise<string> {
// Get openid bearer token from the HS as the first part of our dance // Get openid bearer token from the HS as the first part of our dance
return MatrixClientPeg.get() return MatrixClientPeg.safeGet()
.getOpenIdToken() .getOpenIdToken()
.then((tokenObject) => { .then((tokenObject) => {
// Now we can send that to scalar and exchange it for a scalar token // Now we can send that to scalar and exchange it for a scalar token

View file

@ -411,7 +411,7 @@ function kickUser(event: MessageEvent<any>, roomId: string, userId: string): voi
} }
function setWidget(event: MessageEvent<any>, roomId: string | null): void { function setWidget(event: MessageEvent<any>, roomId: string | null): void {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const widgetId = event.data.widget_id; const widgetId = event.data.widget_id;
let widgetType = event.data.type; let widgetType = event.data.type;
const widgetUrl = event.data.url; const widgetUrl = event.data.url;
@ -535,7 +535,7 @@ function getRoomEncState(event: MessageEvent<any>, roomId: string): void {
sendError(event, _t("This room is not recognised.")); sendError(event, _t("This room is not recognised."));
return; return;
} }
const roomIsEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId); const roomIsEncrypted = MatrixClientPeg.safeGet().isRoomEncrypted(roomId);
sendResponse(event, roomIsEncrypted); sendResponse(event, roomIsEncrypted);
} }
@ -715,7 +715,7 @@ function returnStateEvent(event: MessageEvent<any>, roomId: string, eventType: s
async function getOpenIdToken(event: MessageEvent<any>): Promise<void> { async function getOpenIdToken(event: MessageEvent<any>): Promise<void> {
try { try {
const tokenObject = await MatrixClientPeg.get().getOpenIdToken(); const tokenObject = await MatrixClientPeg.safeGet().getOpenIdToken();
sendResponse(event, tokenObject); sendResponse(event, tokenObject);
} catch (ex) { } catch (ex) {
logger.warn("Unable to fetch openId token.", ex); logger.warn("Unable to fetch openId token.", ex);

View file

@ -99,7 +99,7 @@ async function getSecretStorageKey({
}: { }: {
keys: Record<string, ISecretStorageKeyInfo>; keys: Record<string, ISecretStorageKeyInfo>;
}): Promise<[string, Uint8Array]> { }): Promise<[string, Uint8Array]> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
let keyId = await cli.getDefaultSecretStorageKeyId(); let keyId = await cli.getDefaultSecretStorageKeyId();
let keyInfo!: ISecretStorageKeyInfo; let keyInfo!: ISecretStorageKeyInfo;
if (keyId) { if (keyId) {
@ -127,7 +127,7 @@ async function getSecretStorageKey({
} }
if (dehydrationCache.key) { if (dehydrationCache.key) {
if (await MatrixClientPeg.get().checkSecretStorageKey(dehydrationCache.key, keyInfo)) { if (await MatrixClientPeg.safeGet().checkSecretStorageKey(dehydrationCache.key, keyInfo)) {
cacheSecretStorageKey(keyId, keyInfo, dehydrationCache.key); cacheSecretStorageKey(keyId, keyInfo, dehydrationCache.key);
return [keyId, dehydrationCache.key]; return [keyId, dehydrationCache.key];
} }
@ -152,7 +152,7 @@ async function getSecretStorageKey({
keyInfo, keyInfo,
checkPrivateKey: async (input: KeyParams): Promise<boolean> => { checkPrivateKey: async (input: KeyParams): Promise<boolean> => {
const key = await inputToKey(input); const key = await inputToKey(input);
return MatrixClientPeg.get().checkSecretStorageKey(key, keyInfo); return MatrixClientPeg.safeGet().checkSecretStorageKey(key, keyInfo);
}, },
}, },
/* className= */ undefined, /* className= */ undefined,
@ -244,7 +244,7 @@ async function onSecretRequested(
deviceTrust: DeviceTrustLevel, deviceTrust: DeviceTrustLevel,
): Promise<string | undefined> { ): Promise<string | undefined> {
logger.log("onSecretRequested", userId, deviceId, requestId, name, deviceTrust); logger.log("onSecretRequested", userId, deviceId, requestId, name, deviceTrust);
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
if (userId !== client.getUserId()) { if (userId !== client.getUserId()) {
return; return;
} }
@ -324,9 +324,9 @@ export async function promptForBackupPassphrase(): Promise<Uint8Array> {
* @param {bool} [forceReset] Reset secret storage even if it's already set up * @param {bool} [forceReset] Reset secret storage even if it's already set up
*/ */
export async function accessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> { export async function accessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> {
const cli = MatrixClientPeg.get();
secretStorageBeingAccessed = true; secretStorageBeingAccessed = true;
try { try {
const cli = MatrixClientPeg.safeGet();
if (!(await cli.hasSecretStorageKey()) || forceReset) { if (!(await cli.hasSecretStorageKey()) || forceReset) {
// This dialog calls bootstrap itself after guiding the user through // This dialog calls bootstrap itself after guiding the user through
// passphrase creation. // passphrase creation.

View file

@ -52,7 +52,7 @@ export function eventTriggersUnreadCount(client: MatrixClient, ev: MatrixEvent):
} }
if (ev.isRedacted()) return false; if (ev.isRedacted()) return false;
return haveRendererForEvent(ev, false /* hidden messages should never trigger unread counts anyways */); return haveRendererForEvent(ev, client, false /* hidden messages should never trigger unread counts anyways */);
} }
export function doesRoomHaveUnreadMessages(room: Room): boolean { export function doesRoomHaveUnreadMessages(room: Room): boolean {

View file

@ -58,8 +58,9 @@ export default class VoipUserMapper {
const virtualUser = await this.getVirtualUserForRoom(roomId); const virtualUser = await this.getVirtualUserForRoom(roomId);
if (!virtualUser) return null; if (!virtualUser) return null;
const virtualRoomId = await ensureVirtualRoomExists(MatrixClientPeg.get(), virtualUser, roomId); const cli = MatrixClientPeg.safeGet();
MatrixClientPeg.get().setRoomAccountData(virtualRoomId!, VIRTUAL_ROOM_EVENT_TYPE, { const virtualRoomId = await ensureVirtualRoomExists(cli, virtualUser, roomId);
cli.setRoomAccountData(virtualRoomId!, VIRTUAL_ROOM_EVENT_TYPE, {
native_room: roomId, native_room: roomId,
}); });
@ -76,7 +77,7 @@ export default class VoipUserMapper {
const virtualUser = await this.getVirtualUserForRoom(roomId); const virtualUser = await this.getVirtualUserForRoom(roomId);
if (!virtualUser) return undefined; if (!virtualUser) return undefined;
return findDMForUser(MatrixClientPeg.get(), virtualUser); return findDMForUser(MatrixClientPeg.safeGet(), virtualUser);
} }
public nativeRoomForVirtualRoom(roomId: string): string | null { public nativeRoomForVirtualRoom(roomId: string): string | null {
@ -88,12 +89,13 @@ export default class VoipUserMapper {
return cachedNativeRoomId; return cachedNativeRoomId;
} }
const virtualRoom = MatrixClientPeg.get().getRoom(roomId); const cli = MatrixClientPeg.safeGet();
const virtualRoom = cli.getRoom(roomId);
if (!virtualRoom) return null; if (!virtualRoom) return null;
const virtualRoomEvent = virtualRoom.getAccountData(VIRTUAL_ROOM_EVENT_TYPE); const virtualRoomEvent = virtualRoom.getAccountData(VIRTUAL_ROOM_EVENT_TYPE);
if (!virtualRoomEvent || !virtualRoomEvent.getContent()) return null; if (!virtualRoomEvent || !virtualRoomEvent.getContent()) return null;
const nativeRoomID = virtualRoomEvent.getContent()["native_room"]; const nativeRoomID = virtualRoomEvent.getContent()["native_room"];
const nativeRoom = MatrixClientPeg.get().getRoom(nativeRoomID); const nativeRoom = cli.getRoom(nativeRoomID);
if (!nativeRoom || nativeRoom.getMyMembership() !== "join") return null; if (!nativeRoom || nativeRoom.getMyMembership() !== "join") return null;
return nativeRoomID; return nativeRoomID;
@ -112,7 +114,7 @@ export default class VoipUserMapper {
if (!roomCreateEvent || !roomCreateEvent.getContent()) return false; if (!roomCreateEvent || !roomCreateEvent.getContent()) return false;
// we only look at this for rooms we created (so inviters can't just cause rooms // we only look at this for rooms we created (so inviters can't just cause rooms
// to be invisible) // to be invisible)
if (roomCreateEvent.getSender() !== MatrixClientPeg.get().getUserId()) return false; if (roomCreateEvent.getSender() !== MatrixClientPeg.safeGet().getUserId()) return false;
const claimedNativeRoomId = roomCreateEvent.getContent()[VIRTUAL_ROOM_EVENT_TYPE]; const claimedNativeRoomId = roomCreateEvent.getContent()[VIRTUAL_ROOM_EVENT_TYPE];
return Boolean(claimedNativeRoomId); return Boolean(claimedNativeRoomId);
} }
@ -132,19 +134,20 @@ export default class VoipUserMapper {
} }
if (result[0].fields.is_virtual) { if (result[0].fields.is_virtual) {
const cli = MatrixClientPeg.safeGet();
const nativeUser = result[0].userid; const nativeUser = result[0].userid;
const nativeRoom = findDMForUser(MatrixClientPeg.get(), nativeUser); const nativeRoom = findDMForUser(cli, nativeUser);
if (nativeRoom) { if (nativeRoom) {
// It's a virtual room with a matching native room, so set the room account data. This // It's a virtual room with a matching native room, so set the room account data. This
// will make sure we know where how to map calls and also allow us know not to display // will make sure we know where how to map calls and also allow us know not to display
// it in the future. // it in the future.
MatrixClientPeg.get().setRoomAccountData(invitedRoom.roomId, VIRTUAL_ROOM_EVENT_TYPE, { cli.setRoomAccountData(invitedRoom.roomId, VIRTUAL_ROOM_EVENT_TYPE, {
native_room: nativeRoom.roomId, native_room: nativeRoom.roomId,
}); });
// also auto-join the virtual room if we have a matching native room // also auto-join the virtual room if we have a matching native room
// (possibly we should only join if we've also joined the native room, then we'd also have // (possibly we should only join if we've also joined the native room, then we'd also have
// to make sure we joined virtual rooms on joining a native one) // to make sure we joined virtual rooms on joining a native one)
MatrixClientPeg.get().joinRoom(invitedRoom.roomId); cli.joinRoom(invitedRoom.roomId);
// also put this room in the virtual room ID cache so isVirtualRoom return the right answer // also put this room in the virtual room ID cache so isVirtualRoom return the right answer
// in however long it takes for the echo of setAccountData to come down the sync // in however long it takes for the echo of setAccountData to come down the sync

View file

@ -72,14 +72,15 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
error: undefined, error: undefined,
}); });
let info: IKeyBackupInfo | undefined; let info: IKeyBackupInfo | undefined;
const cli = MatrixClientPeg.safeGet();
try { try {
await accessSecretStorage(async (): Promise<void> => { await accessSecretStorage(async (): Promise<void> => {
info = await MatrixClientPeg.get().prepareKeyBackupVersion(null /* random key */, { info = await cli.prepareKeyBackupVersion(null /* random key */, {
secureSecretStorage: true, secureSecretStorage: true,
}); });
info = await MatrixClientPeg.get().createKeyBackupVersion(info); info = await cli.createKeyBackupVersion(info);
}); });
await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup(); await cli.scheduleAllGroupSessionsForBackup();
this.setState({ this.setState({
phase: Phase.Done, phase: Phase.Done,
}); });
@ -90,7 +91,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
// disable without deleting, we'll enable on next app reload since // disable without deleting, we'll enable on next app reload since
// it is trusted. // it is trusted.
if (info?.version) { if (info?.version) {
MatrixClientPeg.get().deleteKeyBackupVersion(info.version); cli.deleteKeyBackupVersion(info.version);
} }
this.setState({ this.setState({
error: e, error: e,

View file

@ -110,7 +110,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
let passPhraseKeySelected: SecureBackupSetupMethod; let passPhraseKeySelected: SecureBackupSetupMethod;
const setupMethods = getSecureBackupSetupMethods(cli); const setupMethods = getSecureBackupSetupMethods(cli);
@ -157,7 +157,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
MatrixClientPeg.get().removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange); MatrixClientPeg.get()?.removeListener(CryptoEvent.KeyBackupStatus, this.onKeyBackupStatusChange);
} }
private getInitialPhase(): void { private getInitialPhase(): void {
@ -176,12 +176,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
private async fetchBackupInfo(): Promise<{ backupInfo?: IKeyBackupInfo; backupSigStatus?: TrustInfo }> { private async fetchBackupInfo(): Promise<{ backupInfo?: IKeyBackupInfo; backupSigStatus?: TrustInfo }> {
try { try {
const backupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); const cli = MatrixClientPeg.safeGet();
const backupInfo = await cli.getKeyBackupVersion();
const backupSigStatus = const backupSigStatus =
// we may not have started crypto yet, in which case we definitely don't trust the backup // we may not have started crypto yet, in which case we definitely don't trust the backup
backupInfo && MatrixClientPeg.get().isCryptoEnabled() backupInfo && cli.isCryptoEnabled() ? await cli.isKeyBackupTrusted(backupInfo) : null;
? await MatrixClientPeg.get().isKeyBackupTrusted(backupInfo)
: null;
const { forceReset } = this.props; const { forceReset } = this.props;
const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase; const phase = backupInfo && !forceReset ? Phase.Migrate : Phase.ChooseKeyPassphrase;
@ -204,7 +203,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
private async queryKeyUploadAuth(): Promise<void> { private async queryKeyUploadAuth(): Promise<void> {
try { try {
await MatrixClientPeg.get().uploadDeviceSigningKeys(undefined, {} as CrossSigningKeys); await MatrixClientPeg.safeGet().uploadDeviceSigningKeys(undefined, {} as CrossSigningKeys);
// We should never get here: the server should always require // We should never get here: the server should always require
// UI auth to upload device signing keys. If we do, we upload // UI auth to upload device signing keys. If we do, we upload
// no keys which would be a no-op. // no keys which would be a no-op.
@ -235,7 +234,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
private onChooseKeyPassphraseFormSubmit = async (): Promise<void> => { private onChooseKeyPassphraseFormSubmit = async (): Promise<void> => {
if (this.state.passPhraseKeySelected === SecureBackupSetupMethod.Key) { if (this.state.passPhraseKeySelected === SecureBackupSetupMethod.Key) {
this.recoveryKey = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(); this.recoveryKey = await MatrixClientPeg.safeGet().createRecoveryKeyFromPassphrase();
this.setState({ this.setState({
copied: false, copied: false,
downloaded: false, downloaded: false,
@ -286,11 +285,11 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
type: "m.login.password", type: "m.login.password",
identifier: { identifier: {
type: "m.id.user", type: "m.id.user",
user: MatrixClientPeg.get().getUserId(), user: MatrixClientPeg.safeGet().getSafeUserId(),
}, },
// TODO: Remove `user` once servers support proper UIA // TODO: Remove `user` once servers support proper UIA
// See https://github.com/matrix-org/synapse/issues/5665 // See https://github.com/matrix-org/synapse/issues/5665
user: MatrixClientPeg.get().getUserId(), user: MatrixClientPeg.safeGet().getSafeUserId(),
password: this.state.accountPassword, password: this.state.accountPassword,
}); });
} else { } else {
@ -311,7 +310,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
const { finished } = Modal.createDialog(InteractiveAuthDialog, { const { finished } = Modal.createDialog(InteractiveAuthDialog, {
title: _t("Setting up keys"), title: _t("Setting up keys"),
matrixClient: MatrixClientPeg.get(), matrixClient: MatrixClientPeg.safeGet(),
makeRequest, makeRequest,
aestheticsForStagePhases: { aestheticsForStagePhases: {
[SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics, [SSOAuthEntry.LOGIN_TYPE]: dialogAesthetics,
@ -331,7 +330,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
error: undefined, error: undefined,
}); });
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const { forceReset } = this.props; const { forceReset } = this.props;
@ -457,7 +456,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
if (this.state.passPhrase !== this.state.passPhraseConfirm) return; if (this.state.passPhrase !== this.state.passPhraseConfirm) return;
this.recoveryKey = await MatrixClientPeg.get().createRecoveryKeyFromPassphrase(this.state.passPhrase); this.recoveryKey = await MatrixClientPeg.safeGet().createRecoveryKeyFromPassphrase(this.state.passPhrase);
this.setState({ this.setState({
copied: false, copied: false,
downloaded: false, downloaded: false,
@ -544,7 +543,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
} }
private renderPhaseChooseKeyPassphrase(): JSX.Element { private renderPhaseChooseKeyPassphrase(): JSX.Element {
const setupMethods = getSecureBackupSetupMethods(MatrixClientPeg.get()); const setupMethods = getSecureBackupSetupMethods(MatrixClientPeg.safeGet());
const optionKey = setupMethods.includes(SecureBackupSetupMethod.Key) ? this.renderOptionKey() : null; const optionKey = setupMethods.includes(SecureBackupSetupMethod.Key) ? this.renderOptionKey() : null;
const optionPassphrase = setupMethods.includes(SecureBackupSetupMethod.Passphrase) const optionPassphrase = setupMethods.includes(SecureBackupSetupMethod.Passphrase)
? this.renderOptionPassphrase() ? this.renderOptionPassphrase()

View file

@ -70,8 +70,8 @@ export default class NewRecoveryMethodDialog extends React.PureComponent<IProps>
</p> </p>
); );
let content; let content: JSX.Element | undefined;
if (MatrixClientPeg.get().getKeyBackupEnabled()) { if (MatrixClientPeg.safeGet().getKeyBackupEnabled()) {
content = ( content = (
<div> <div>
{newMethodDetected} {newMethodDetected}

View file

@ -64,7 +64,7 @@ export class PlaybackQueue {
} }
public static forRoom(roomId: string): PlaybackQueue { public static forRoom(roomId: string): PlaybackQueue {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const room = cli.getRoom(roomId); const room = cli.getRoom(roomId);
if (!room) throw new Error("Unknown room"); if (!room) throw new Error("Unknown room");
if (PlaybackQueue.queues.has(room.roomId)) { if (PlaybackQueue.queues.has(room.roomId)) {

View file

@ -38,9 +38,9 @@ export default class NotifProvider extends AutocompleteProvider {
force = false, force = false,
limit = -1, limit = -1,
): Promise<ICompletion[]> { ): Promise<ICompletion[]> {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
if (!this.room.currentState.mayTriggerNotifOfType("room", client.credentials.userId!)) return []; if (!this.room.currentState.mayTriggerNotifOfType("room", client.getSafeUserId())) return [];
const { command, range } = this.getCurrentCommand(query, selection, force); const { command, range } = this.getCurrentCommand(query, selection, force);
if ( if (

View file

@ -65,7 +65,7 @@ export default class RoomProvider extends AutocompleteProvider {
} }
protected getRooms(): Room[] { protected getRooms(): Room[] {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
// filter out spaces here as they get their own autocomplete provider // filter out spaces here as they get their own autocomplete provider
return cli return cli

View file

@ -24,7 +24,7 @@ import RoomProvider from "./RoomProvider";
export default class SpaceProvider extends RoomProvider { export default class SpaceProvider extends RoomProvider {
protected getRooms(): Room[] { protected getRooms(): Room[] {
return MatrixClientPeg.get() return MatrixClientPeg.safeGet()
.getVisibleRooms(SettingsStore.getValue("feature_dynamic_room_predecessors")) .getVisibleRooms(SettingsStore.getValue("feature_dynamic_room_predecessors"))
.filter((r) => r.isSpaceRoom()); .filter((r) => r.isSpaceRoom());
} }

View file

@ -60,15 +60,13 @@ export default class UserProvider extends AutocompleteProvider {
shouldMatchWordsOnly: false, shouldMatchWordsOnly: false,
}); });
MatrixClientPeg.get().on(RoomEvent.Timeline, this.onRoomTimeline); MatrixClientPeg.safeGet().on(RoomEvent.Timeline, this.onRoomTimeline);
MatrixClientPeg.get().on(RoomStateEvent.Update, this.onRoomStateUpdate); MatrixClientPeg.safeGet().on(RoomStateEvent.Update, this.onRoomStateUpdate);
} }
public destroy(): void { public destroy(): void {
if (MatrixClientPeg.get()) { MatrixClientPeg.get()?.removeListener(RoomEvent.Timeline, this.onRoomTimeline);
MatrixClientPeg.get().removeListener(RoomEvent.Timeline, this.onRoomTimeline); MatrixClientPeg.get()?.removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
MatrixClientPeg.get().removeListener(RoomStateEvent.Update, this.onRoomStateUpdate);
}
} }
private onRoomTimeline = ( private onRoomTimeline = (
@ -155,7 +153,7 @@ export default class UserProvider extends AutocompleteProvider {
lastSpoken[event.getSender()!] = event.getTs(); lastSpoken[event.getSender()!] = event.getTs();
} }
const currentUserId = MatrixClientPeg.get().credentials.userId; const currentUserId = MatrixClientPeg.safeGet().credentials.userId;
this.users = this.room.getJoinedMembers().filter(({ userId }) => userId !== currentUserId); this.users = this.room.getJoinedMembers().filter(({ userId }) => userId !== currentUserId);
this.users = this.users.concat(this.room.getMembersWithMembership("invite")); this.users = this.users.concat(this.room.getMembersWithMembership("invite"));
@ -167,7 +165,7 @@ export default class UserProvider extends AutocompleteProvider {
public onUserSpoke(user: RoomMember | null): void { public onUserSpoke(user: RoomMember | null): void {
if (!this.users) return; if (!this.users) return;
if (!user) return; if (!user) return;
if (user.userId === MatrixClientPeg.get().credentials.userId) return; if (user.userId === MatrixClientPeg.safeGet().getSafeUserId()) return;
// Move the user that spoke to the front of the array // Move the user that spoke to the front of the array
this.users.splice( this.users.splice(

View file

@ -25,6 +25,7 @@ import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon"; import { M_BEACON_INFO } from "matrix-js-sdk/src/@types/beacon";
import { isSupportedReceiptType } from "matrix-js-sdk/src/utils"; import { isSupportedReceiptType } from "matrix-js-sdk/src/utils";
import { Optional } from "matrix-events-sdk"; import { Optional } from "matrix-events-sdk";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import shouldHideEvent from "../../shouldHideEvent"; import shouldHideEvent from "../../shouldHideEvent";
import { wantsDateSeparator } from "../../DateUtils"; import { wantsDateSeparator } from "../../DateUtils";
@ -73,6 +74,7 @@ const groupedStateEvents = [
export function shouldFormContinuation( export function shouldFormContinuation(
prevEvent: MatrixEvent | null, prevEvent: MatrixEvent | null,
mxEvent: MatrixEvent, mxEvent: MatrixEvent,
matrixClient: MatrixClient,
showHiddenEvents: boolean, showHiddenEvents: boolean,
timelineRenderingType?: TimelineRenderingType, timelineRenderingType?: TimelineRenderingType,
): boolean { ): boolean {
@ -110,7 +112,7 @@ export function shouldFormContinuation(
} }
// if we don't have tile for previous event then it was shown by showHiddenEvents and has no SenderProfile // if we don't have tile for previous event then it was shown by showHiddenEvents and has no SenderProfile
if (!haveRendererForEvent(prevEvent, showHiddenEvents)) return false; if (!haveRendererForEvent(prevEvent, matrixClient, showHiddenEvents)) return false;
return true; return true;
} }
@ -481,7 +483,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
return true; return true;
} }
if (!haveRendererForEvent(mxEv, this.showHiddenEvents)) { if (!haveRendererForEvent(mxEv, MatrixClientPeg.safeGet(), this.showHiddenEvents)) {
return false; // no tile = no show return false; // no tile = no show
} }
@ -736,6 +738,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
ret.push(dateSeparator); ret.push(dateSeparator);
} }
const cli = MatrixClientPeg.safeGet();
let lastInSection = true; let lastInSection = true;
if (nextEventWithTile) { if (nextEventWithTile) {
const nextEv = nextEventWithTile; const nextEv = nextEventWithTile;
@ -743,14 +746,14 @@ export default class MessagePanel extends React.Component<IProps, IState> {
lastInSection = lastInSection =
willWantDateSeparator || willWantDateSeparator ||
mxEv.getSender() !== nextEv.getSender() || mxEv.getSender() !== nextEv.getSender() ||
getEventDisplayInfo(MatrixClientPeg.safeGet(), nextEv, this.showHiddenEvents).isInfoMessage || getEventDisplayInfo(cli, nextEv, this.showHiddenEvents).isInfoMessage ||
!shouldFormContinuation(mxEv, nextEv, this.showHiddenEvents, this.context.timelineRenderingType); !shouldFormContinuation(mxEv, nextEv, cli, this.showHiddenEvents, this.context.timelineRenderingType);
} }
// is this a continuation of the previous message? // is this a continuation of the previous message?
const continuation = const continuation =
!wantsDateSeparator && !wantsDateSeparator &&
shouldFormContinuation(prevEvent, mxEv, this.showHiddenEvents, this.context.timelineRenderingType); shouldFormContinuation(prevEvent, mxEv, cli, this.showHiddenEvents, this.context.timelineRenderingType);
const eventId = mxEv.getId()!; const eventId = mxEv.getId()!;
const highlight = eventId === this.props.highlightedEventId; const highlight = eventId === this.props.highlightedEventId;

View file

@ -237,7 +237,7 @@ export const RoomSearchView = forwardRef<ScrollPanel, Props>(
continue; continue;
} }
if (!haveRendererForEvent(mxEv, roomContext.showHiddenEvents)) { if (!haveRendererForEvent(mxEv, client, roomContext.showHiddenEvents)) {
// XXX: can this ever happen? It will make the result count // XXX: can this ever happen? It will make the result count
// not match the displayed count. // not match the displayed count.
continue; continue;

View file

@ -1965,7 +1965,8 @@ class TimelinePanel extends React.Component<IProps, IState> {
!!ev.status || // local echo !!ev.status || // local echo
(ignoreOwn && ev.getSender() === myUserId); // own message (ignoreOwn && ev.getSender() === myUserId); // own message
const isWithoutTile = const isWithoutTile =
!haveRendererForEvent(ev, this.context?.showHiddenEvents) || shouldHideEvent(ev, this.context); !haveRendererForEvent(ev, MatrixClientPeg.safeGet(), this.context?.showHiddenEvents) ||
shouldHideEvent(ev, this.context);
if (isWithoutTile || !node) { if (isWithoutTile || !node) {
// don't start counting if the event should be ignored, // don't start counting if the event should be ignored,

View file

@ -75,7 +75,7 @@ export function createRedactEventDialog({
onFinished: async (proceed, reason): Promise<void> => { onFinished: async (proceed, reason): Promise<void> => {
if (!proceed) return; if (!proceed) return;
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const withRelTypes: Pick<IRedactOpts, "with_rel_types"> = {}; const withRelTypes: Pick<IRedactOpts, "with_rel_types"> = {};
// redact related events if this is a voice broadcast started event and // redact related events if this is a voice broadcast started event and

View file

@ -37,7 +37,7 @@ export function ManualDeviceKeyVerificationDialog({
device, device,
onFinished, onFinished,
}: IManualDeviceKeyVerificationDialogProps): JSX.Element { }: IManualDeviceKeyVerificationDialogProps): JSX.Element {
const mxClient = MatrixClientPeg.get(); const mxClient = MatrixClientPeg.safeGet();
const onLegacyFinished = useCallback( const onLegacyFinished = useCallback(
(confirm: boolean) => { (confirm: boolean) => {

View file

@ -203,9 +203,9 @@ export default class VerificationPanel extends React.PureComponent<IProps, IStat
private getDevice(): DeviceInfo | null { private getDevice(): DeviceInfo | null {
const deviceId = this.props.request?.otherDeviceId; const deviceId = this.props.request?.otherDeviceId;
const userId = MatrixClientPeg.get().getUserId(); const userId = MatrixClientPeg.safeGet().getUserId();
if (deviceId && userId) { if (deviceId && userId) {
return MatrixClientPeg.get().getStoredDevice(userId, deviceId); return MatrixClientPeg.safeGet().getStoredDevice(userId, deviceId);
} else { } else {
return null; return null;
} }

View file

@ -1166,7 +1166,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
let replyChain: JSX.Element | undefined; let replyChain: JSX.Element | undefined;
if ( if (
haveRendererForEvent(this.props.mxEvent, this.context.showHiddenEvents) && haveRendererForEvent(this.props.mxEvent, MatrixClientPeg.safeGet(), this.context.showHiddenEvents) &&
shouldDisplayReply(this.props.mxEvent) shouldDisplayReply(this.props.mxEvent)
) { ) {
replyChain = ( replyChain = (

View file

@ -27,6 +27,7 @@ import { shouldFormContinuation } from "../../structures/MessagePanel";
import { wantsDateSeparator } from "../../../DateUtils"; import { wantsDateSeparator } from "../../../DateUtils";
import LegacyCallEventGrouper, { buildLegacyCallEventGroupers } from "../../structures/LegacyCallEventGrouper"; import LegacyCallEventGrouper, { buildLegacyCallEventGroupers } from "../../structures/LegacyCallEventGrouper";
import { haveRendererForEvent } from "../../../events/EventTileFactory"; import { haveRendererForEvent } from "../../../events/EventTileFactory";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
interface IProps { interface IProps {
// a list of strings to be highlighted in the results // a list of strings to be highlighted in the results
@ -69,6 +70,7 @@ export default class SearchResultTile extends React.Component<IProps> {
const isTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps"); const isTwelveHour = SettingsStore.getValue("showTwelveHourTimestamps");
const alwaysShowTimestamps = SettingsStore.getValue("alwaysShowTimestamps"); const alwaysShowTimestamps = SettingsStore.getValue("alwaysShowTimestamps");
const cli = MatrixClientPeg.safeGet();
for (let j = 0; j < timeline.length; j++) { for (let j = 0; j < timeline.length; j++) {
const mxEv = timeline[j]; const mxEv = timeline[j];
let highlights: string[] | undefined; let highlights: string[] | undefined;
@ -77,14 +79,20 @@ export default class SearchResultTile extends React.Component<IProps> {
highlights = this.props.searchHighlights; highlights = this.props.searchHighlights;
} }
if (haveRendererForEvent(mxEv, this.context?.showHiddenEvents)) { if (haveRendererForEvent(mxEv, cli, this.context?.showHiddenEvents)) {
// do we need a date separator since the last event? // do we need a date separator since the last event?
const prevEv = timeline[j - 1]; const prevEv = timeline[j - 1];
// is this a continuation of the previous message? // is this a continuation of the previous message?
const continuation = const continuation =
prevEv && prevEv &&
!wantsDateSeparator(prevEv.getDate() || undefined, mxEv.getDate() || undefined) && !wantsDateSeparator(prevEv.getDate() || undefined, mxEv.getDate() || undefined) &&
shouldFormContinuation(prevEv, mxEv, this.context?.showHiddenEvents, TimelineRenderingType.Search); shouldFormContinuation(
prevEv,
mxEv,
cli,
this.context?.showHiddenEvents,
TimelineRenderingType.Search,
);
let lastInSection = true; let lastInSection = true;
const nextEv = timeline[j + 1]; const nextEv = timeline[j + 1];
@ -99,6 +107,7 @@ export default class SearchResultTile extends React.Component<IProps> {
!shouldFormContinuation( !shouldFormContinuation(
mxEv, mxEv,
nextEv, nextEv,
cli,
this.context?.showHiddenEvents, this.context?.showHiddenEvents,
TimelineRenderingType.Search, TimelineRenderingType.Search,
); );

View file

@ -51,7 +51,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
} }
public componentDidMount(): void { public componentDidMount(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
cli.on(ClientEvent.AccountData, this.onAccountData); cli.on(ClientEvent.AccountData, this.onAccountData);
cli.on(CryptoEvent.UserTrustStatusChanged, this.onStatusChanged); cli.on(CryptoEvent.UserTrustStatusChanged, this.onStatusChanged);
cli.on(CryptoEvent.KeysChanged, this.onStatusChanged); cli.on(CryptoEvent.KeysChanged, this.onStatusChanged);
@ -89,7 +89,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
}; };
private async getUpdatedStatus(): Promise<void> { private async getUpdatedStatus(): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const crypto = cli.getCrypto(); const crypto = cli.getCrypto();
if (!crypto) return; if (!crypto) return;
@ -127,7 +127,7 @@ export default class CrossSigningPanel extends React.PureComponent<{}, IState> {
private bootstrapCrossSigning = async ({ forceReset = false }): Promise<void> => { private bootstrapCrossSigning = async ({ forceReset = false }): Promise<void> => {
this.setState({ error: undefined }); this.setState({ error: undefined });
try { try {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
await cli.bootstrapCrossSigning({ await cli.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => { authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
const { finished } = Modal.createDialog(InteractiveAuthDialog, { const { finished } = Modal.createDialog(InteractiveAuthDialog, {

View file

@ -89,7 +89,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
this.setState({ busy: true }); this.setState({ busy: true });
try { try {
const room = await MatrixClientPeg.get().joinRoom(this.state.newList); const room = await MatrixClientPeg.safeGet().joinRoom(this.state.newList);
await Mjolnir.sharedInstance().subscribeToList(room.roomId); await Mjolnir.sharedInstance().subscribeToList(room.roomId);
this.setState({ newList: "" }); // this will also cause the new rule to be rendered this.setState({ newList: "" }); // this will also cause the new rule to be rendered
} catch (e) { } catch (e) {
@ -125,7 +125,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
this.setState({ busy: true }); this.setState({ busy: true });
try { try {
await Mjolnir.sharedInstance().unsubscribeFromList(list.roomId); await Mjolnir.sharedInstance().unsubscribeFromList(list.roomId);
await MatrixClientPeg.get().leave(list.roomId); await MatrixClientPeg.safeGet().leave(list.roomId);
} catch (e) { } catch (e) {
logger.error(e); logger.error(e);
@ -139,7 +139,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
} }
private viewListRules(list: BanList): void { private viewListRules(list: BanList): void {
const room = MatrixClientPeg.get().getRoom(list.roomId); const room = MatrixClientPeg.safeGet().getRoom(list.roomId);
const name = room ? room.name : list.roomId; const name = room ? room.name : list.roomId;
const renderRules = (rules: ListRule[]): JSX.Element => { const renderRules = (rules: ListRule[]): JSX.Element => {
@ -210,7 +210,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
const tiles: JSX.Element[] = []; const tiles: JSX.Element[] = [];
for (const list of lists) { for (const list of lists) {
const room = MatrixClientPeg.get().getRoom(list.roomId); const room = MatrixClientPeg.safeGet().getRoom(list.roomId);
const name = room ? ( const name = room ? (
<span> <span>
{room.name} (<code>{list.roomId}</code>) {room.name} (<code>{list.roomId}</code>)

View file

@ -93,7 +93,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
const invitedRoomIds = new Set(this.getInvitedRooms().map((room) => room.roomId)); const invitedRoomIds = new Set(this.getInvitedRooms().map((room) => room.roomId));
this.state = { this.state = {
ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(), ignoredUserIds: MatrixClientPeg.safeGet().getIgnoredUsers(),
waitingUnignored: [], waitingUnignored: [],
managingInvites: false, managingInvites: false,
invitedRoomIds, invitedRoomIds,
@ -102,7 +102,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
private onAction = ({ action }: ActionPayload): void => { private onAction = ({ action }: ActionPayload): void => {
if (action === "ignore_state_changed") { if (action === "ignore_state_changed") {
const ignoredUserIds = MatrixClientPeg.get().getIgnoredUsers(); const ignoredUserIds = MatrixClientPeg.safeGet().getIgnoredUsers();
const newWaitingUnignored = this.state.waitingUnignored.filter((e) => ignoredUserIds.includes(e)); const newWaitingUnignored = this.state.waitingUnignored.filter((e) => ignoredUserIds.includes(e));
this.setState({ ignoredUserIds, waitingUnignored: newWaitingUnignored }); this.setState({ ignoredUserIds, waitingUnignored: newWaitingUnignored });
} }
@ -110,15 +110,15 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
public componentDidMount(): void { public componentDidMount(): void {
this.dispatcherRef = dis.register(this.onAction); this.dispatcherRef = dis.register(this.onAction);
MatrixClientPeg.get().on(RoomEvent.MyMembership, this.onMyMembership); MatrixClientPeg.safeGet().on(RoomEvent.MyMembership, this.onMyMembership);
MatrixClientPeg.get() MatrixClientPeg.safeGet()
.getVersions() .getVersions()
.then((versions) => this.setState({ versions })); .then((versions) => this.setState({ versions }));
} }
public componentWillUnmount(): void { public componentWillUnmount(): void {
if (this.dispatcherRef) dis.unregister(this.dispatcherRef); if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
MatrixClientPeg.get().removeListener(RoomEvent.MyMembership, this.onMyMembership); MatrixClientPeg.safeGet().removeListener(RoomEvent.MyMembership, this.onMyMembership);
} }
private onMyMembership = (room: Room, membership: string): void => { private onMyMembership = (room: Room, membership: string): void => {
@ -159,15 +159,15 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
if (index !== -1) { if (index !== -1) {
currentlyIgnoredUserIds.splice(index, 1); currentlyIgnoredUserIds.splice(index, 1);
this.setState(({ waitingUnignored }) => ({ waitingUnignored: [...waitingUnignored, userId] })); this.setState(({ waitingUnignored }) => ({ waitingUnignored: [...waitingUnignored, userId] }));
MatrixClientPeg.get().setIgnoredUsers(currentlyIgnoredUserIds); MatrixClientPeg.safeGet().setIgnoredUsers(currentlyIgnoredUserIds);
} }
}; };
private getInvitedRooms = (): Room[] => { private getInvitedRooms = (): Room[] => {
return MatrixClientPeg.get() return MatrixClientPeg.safeGet()
.getRooms() .getRooms()
.filter((r) => { .filter((r) => {
return r.hasMembershipState(MatrixClientPeg.get().getUserId()!, "invite"); return r.hasMembershipState(MatrixClientPeg.safeGet().getUserId()!, "invite");
}); });
}; };
@ -180,7 +180,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
const invitedRoomIdsValues = Array.from(this.state.invitedRoomIds); const invitedRoomIdsValues = Array.from(this.state.invitedRoomIds);
// Execute all acceptances/rejections sequentially // Execute all acceptances/rejections sequentially
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli); const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
for (let i = 0; i < invitedRoomIdsValues.length; i++) { for (let i = 0; i < invitedRoomIdsValues.length; i++) {
const roomId = invitedRoomIdsValues[i]; const roomId = invitedRoomIdsValues[i];
@ -298,7 +298,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
); );
let warning; let warning;
if (!privateShouldBeEncrypted(MatrixClientPeg.get())) { if (!privateShouldBeEncrypted(MatrixClientPeg.safeGet())) {
warning = ( warning = (
<div className="mx_SecurityUserSettingsTab_warning"> <div className="mx_SecurityUserSettingsTab_warning">
{_t( {_t(

View file

@ -75,7 +75,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
this.checkRequestIsPending(); this.checkRequestIsPending();
if (request.isSelfVerification) { if (request.isSelfVerification) {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const device = request.otherDeviceId ? await cli.getDevice(request.otherDeviceId) : null; const device = request.otherDeviceId ? await cli.getDevice(request.otherDeviceId) : null;
const ip = device?.last_seen_ip; const ip = device?.last_seen_ip;
this.setState({ this.setState({
@ -113,7 +113,7 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
ToastStore.sharedInstance().dismissToast(this.props.toastKey); ToastStore.sharedInstance().dismissToast(this.props.toastKey);
const { request } = this.props; const { request } = this.props;
// no room id for to_device requests // no room id for to_device requests
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
try { try {
if (request.roomId) { if (request.roomId) {
dis.dispatch<ViewRoomPayload>({ dis.dispatch<ViewRoomPayload>({
@ -165,12 +165,12 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
}); });
} }
} else { } else {
const client = MatrixClientPeg.safeGet();
const userId = request.otherUserId; const userId = request.otherUserId;
const roomId = request.roomId; const roomId = request.roomId;
description = roomId ? userLabelForEventRoom(MatrixClientPeg.get(), userId, roomId) : userId; description = roomId ? userLabelForEventRoom(client, userId, roomId) : userId;
// for legacy to_device verification requests // for legacy to_device verification requests
if (description === userId) { if (description === userId) {
const client = MatrixClientPeg.get();
const user = client.getUser(userId); const user = client.getUser(userId);
if (user && user.displayName) { if (user && user.displayName) {
description = _t("%(name)s (%(userId)s)", { name: user.displayName, userId }); description = _t("%(name)s (%(userId)s)", { name: user.displayName, userId });

View file

@ -38,7 +38,7 @@ export class Media {
// Per above, this constructor signature can be whatever is helpful for you. // Per above, this constructor signature can be whatever is helpful for you.
public constructor(private prepared: IPreparedMedia, client?: MatrixClient) { public constructor(private prepared: IPreparedMedia, client?: MatrixClient) {
this.client = client ?? MatrixClientPeg.get(); this.client = client ?? MatrixClientPeg.safeGet();
if (!this.client) { if (!this.client) {
throw new Error("No possible MatrixClient for media resolution. Please provide one or log in."); throw new Error("No possible MatrixClient for media resolution. Please provide one or log in.");
} }

View file

@ -300,7 +300,7 @@ export function renderTile(
showHiddenEvents: boolean, showHiddenEvents: boolean,
cli?: MatrixClient, cli?: MatrixClient,
): Optional<JSX.Element> { ): Optional<JSX.Element> {
cli = cli ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing cli = cli ?? MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing
const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); const factory = pickFactory(props.mxEvent, cli, showHiddenEvents);
if (!factory) return undefined; if (!factory) return undefined;
@ -378,7 +378,7 @@ export function renderReplyTile(
showHiddenEvents: boolean, showHiddenEvents: boolean,
cli?: MatrixClient, cli?: MatrixClient,
): Optional<JSX.Element> { ): Optional<JSX.Element> {
cli = cli ?? MatrixClientPeg.get(); // because param defaults don't do the correct thing cli = cli ?? MatrixClientPeg.safeGet(); // because param defaults don't do the correct thing
const factory = pickFactory(props.mxEvent, cli, showHiddenEvents); const factory = pickFactory(props.mxEvent, cli, showHiddenEvents);
if (!factory) return undefined; if (!factory) return undefined;
@ -426,7 +426,11 @@ export function isMessageEvent(ev: MatrixEvent): boolean {
); );
} }
export function haveRendererForEvent(mxEvent: MatrixEvent, showHiddenEvents: boolean): boolean { export function haveRendererForEvent(
mxEvent: MatrixEvent,
matrixClient: MatrixClient,
showHiddenEvents: boolean,
): boolean {
// Only show "Message deleted" tile for plain message events, encrypted events, // Only show "Message deleted" tile for plain message events, encrypted events,
// and state events as they'll likely still contain enough keys to be relevant. // and state events as they'll likely still contain enough keys to be relevant.
if (mxEvent.isRedacted() && !mxEvent.isEncrypted() && !isMessageEvent(mxEvent) && !mxEvent.isState()) { if (mxEvent.isRedacted() && !mxEvent.isEncrypted() && !isMessageEvent(mxEvent) && !mxEvent.isState()) {
@ -436,14 +440,13 @@ export function haveRendererForEvent(mxEvent: MatrixEvent, showHiddenEvents: boo
// No tile for replacement events since they update the original tile // No tile for replacement events since they update the original tile
if (mxEvent.isRelation(RelationType.Replace)) return false; if (mxEvent.isRelation(RelationType.Replace)) return false;
const cli = MatrixClientPeg.get(); const handler = pickFactory(mxEvent, matrixClient, showHiddenEvents);
const handler = pickFactory(mxEvent, cli, showHiddenEvents);
if (!handler) return false; if (!handler) return false;
if (handler === TextualEventFactory) { if (handler === TextualEventFactory) {
return hasText(mxEvent, cli, showHiddenEvents); return hasText(mxEvent, matrixClient, showHiddenEvents);
} else if (handler === STATE_EVENT_TILE_TYPES.get(EventType.RoomCreate)) { } else if (handler === STATE_EVENT_TILE_TYPES.get(EventType.RoomCreate)) {
const dynamicPredecessorsEnabled = SettingsStore.getValue("feature_dynamic_room_predecessors"); const dynamicPredecessorsEnabled = SettingsStore.getValue("feature_dynamic_room_predecessors");
const predecessor = cli.getRoom(mxEvent.getRoomId())?.findPredecessor(dynamicPredecessorsEnabled); const predecessor = matrixClient.getRoom(mxEvent.getRoomId())?.findPredecessor(dynamicPredecessorsEnabled);
return Boolean(predecessor); return Boolean(predecessor);
} else if ( } else if (
ElementCall.CALL_EVENT_TYPE.names.some((eventType) => handler === STATE_EVENT_TILE_TYPES.get(eventType)) ElementCall.CALL_EVENT_TYPE.names.some((eventType) => handler === STATE_EVENT_TILE_TYPES.get(eventType))

View file

@ -69,7 +69,7 @@ export default class EventIndex extends EventEmitter {
* Register event listeners that are necessary for the event index to work. * Register event listeners that are necessary for the event index to work.
*/ */
public registerListeners(): void { public registerListeners(): void {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
client.on(ClientEvent.Sync, this.onSync); client.on(ClientEvent.Sync, this.onSync);
client.on(RoomEvent.Timeline, this.onRoomTimeline); client.on(RoomEvent.Timeline, this.onRoomTimeline);
@ -96,7 +96,7 @@ export default class EventIndex extends EventEmitter {
public async addInitialCheckpoints(): Promise<void> { public async addInitialCheckpoints(): Promise<void> {
const indexManager = PlatformPeg.get()?.getEventIndexingManager(); const indexManager = PlatformPeg.get()?.getEventIndexingManager();
if (!indexManager) return; if (!indexManager) return;
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const rooms = client.getRooms(); const rooms = client.getRooms();
const isRoomEncrypted = (room: Room): boolean => { const isRoomEncrypted = (room: Room): boolean => {
@ -200,7 +200,7 @@ export default class EventIndex extends EventEmitter {
): Promise<void> => { ): Promise<void> => {
if (!room) return; // notification timeline, we'll get this event again with a room specific timeline if (!room) return; // notification timeline, we'll get this event again with a room specific timeline
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
// We only index encrypted rooms locally. // We only index encrypted rooms locally.
if (!client.isRoomEncrypted(ev.getRoomId()!)) return; if (!client.isRoomEncrypted(ev.getRoomId()!)) return;
@ -220,7 +220,7 @@ export default class EventIndex extends EventEmitter {
}; };
private onRoomStateEvent = async (ev: MatrixEvent, state: RoomState): Promise<void> => { private onRoomStateEvent = async (ev: MatrixEvent, state: RoomState): Promise<void> => {
if (!MatrixClientPeg.get().isRoomEncrypted(state.roomId)) return; if (!MatrixClientPeg.safeGet().isRoomEncrypted(state.roomId)) return;
if (ev.getType() === EventType.RoomEncryption && !(await this.isRoomIndexed(state.roomId))) { if (ev.getType() === EventType.RoomEncryption && !(await this.isRoomIndexed(state.roomId))) {
logger.log("EventIndex: Adding a checkpoint for a newly encrypted room", state.roomId); logger.log("EventIndex: Adding a checkpoint for a newly encrypted room", state.roomId);
@ -254,7 +254,7 @@ export default class EventIndex extends EventEmitter {
*/ */
private onTimelineReset = async (room: Room | undefined): Promise<void> => { private onTimelineReset = async (room: Room | undefined): Promise<void> => {
if (!room) return; if (!room) return;
if (!MatrixClientPeg.get().isRoomEncrypted(room.roomId)) return; if (!MatrixClientPeg.safeGet().isRoomEncrypted(room.roomId)) return;
logger.log("EventIndex: Adding a checkpoint because of a limited timeline", room.roomId); logger.log("EventIndex: Adding a checkpoint because of a limited timeline", room.roomId);
@ -364,7 +364,7 @@ export default class EventIndex extends EventEmitter {
private async addRoomCheckpoint(roomId: string, fullCrawl = false): Promise<void> { private async addRoomCheckpoint(roomId: string, fullCrawl = false): Promise<void> {
const indexManager = PlatformPeg.get()?.getEventIndexingManager(); const indexManager = PlatformPeg.get()?.getEventIndexingManager();
if (!indexManager) return; if (!indexManager) return;
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const room = client.getRoom(roomId); const room = client.getRoom(roomId);
if (!room) return; if (!room) return;
@ -410,7 +410,7 @@ export default class EventIndex extends EventEmitter {
private async crawlerFunc(): Promise<void> { private async crawlerFunc(): Promise<void> {
let cancelled = false; let cancelled = false;
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const indexManager = PlatformPeg.get()?.getEventIndexingManager(); const indexManager = PlatformPeg.get()?.getEventIndexingManager();
if (!indexManager) return; if (!indexManager) return;
@ -707,7 +707,7 @@ export default class EventIndex extends EventEmitter {
fromEvent?: string, fromEvent?: string,
direction: string = EventTimeline.BACKWARDS, direction: string = EventTimeline.BACKWARDS,
): Promise<MatrixEvent[]> { ): Promise<MatrixEvent[]> {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const indexManager = PlatformPeg.get()?.getEventIndexingManager(); const indexManager = PlatformPeg.get()?.getEventIndexingManager();
if (!indexManager) return []; if (!indexManager) return [];
@ -942,7 +942,7 @@ export default class EventIndex extends EventEmitter {
return null; return null;
} }
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
if (this.currentCheckpoint !== null) { if (this.currentCheckpoint !== null) {
return client.getRoom(this.currentCheckpoint.roomId); return client.getRoom(this.currentCheckpoint.roomId);
@ -966,7 +966,7 @@ export default class EventIndex extends EventEmitter {
crawlingRooms.add(this.currentCheckpoint.roomId); crawlingRooms.add(this.currentCheckpoint.roomId);
} }
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const rooms = client.getRooms(); const rooms = client.getRooms();
const isRoomEncrypted = (room: Room): boolean => { const isRoomEncrypted = (room: Room): boolean => {

View file

@ -55,7 +55,7 @@ export class IntegrationManagers {
public startWatching(): void { public startWatching(): void {
this.stopWatching(); this.stopWatching();
this.client = MatrixClientPeg.get(); this.client = MatrixClientPeg.safeGet();
this.client.on(ClientEvent.AccountData, this.onAccountData); this.client.on(ClientEvent.AccountData, this.onAccountData);
this.client.on(ClientEvent.ClientWellKnown, this.setupHomeserverManagers); this.client.on(ClientEvent.ClientWellKnown, this.setupHomeserverManagers);
this.compileManagers(); this.compileManagers();

View file

@ -197,7 +197,7 @@ export const options: Opts = {
case Type.RoomAlias: case Type.RoomAlias:
case Type.UserId: case Type.UserId:
default: { default: {
return tryTransformEntityToPermalink(MatrixClientPeg.get(), href) ?? ""; return tryTransformEntityToPermalink(MatrixClientPeg.safeGet(), href) ?? "";
} }
} }
}, },

View file

@ -70,7 +70,7 @@ export class BanList {
public async banEntity(kind: string, entity: string, reason: string): Promise<any> { public async banEntity(kind: string, entity: string, reason: string): Promise<any> {
const type = ruleTypeToStable(kind); const type = ruleTypeToStable(kind);
if (!type) return; // unknown rule type if (!type) return; // unknown rule type
await MatrixClientPeg.get().sendStateEvent( await MatrixClientPeg.safeGet().sendStateEvent(
this._roomId, this._roomId,
type, type,
{ {
@ -87,7 +87,7 @@ export class BanList {
const type = ruleTypeToStable(kind); const type = ruleTypeToStable(kind);
if (!type) return; // unknown rule type if (!type) return; // unknown rule type
// Empty state event is effectively deleting it. // Empty state event is effectively deleting it.
await MatrixClientPeg.get().sendStateEvent(this._roomId, type, {}, "rule:" + entity); await MatrixClientPeg.safeGet().sendStateEvent(this._roomId, type, {}, "rule:" + entity);
this._rules = this._rules.filter((r) => { this._rules = this._rules.filter((r) => {
if (r.kind !== ruleTypeToStable(kind)) return true; if (r.kind !== ruleTypeToStable(kind)) return true;
if (r.entity !== entity) return true; if (r.entity !== entity) return true;
@ -98,7 +98,7 @@ export class BanList {
public updateList(): void { public updateList(): void {
this._rules = []; this._rules = [];
const room = MatrixClientPeg.get().getRoom(this._roomId); const room = MatrixClientPeg.safeGet().getRoom(this._roomId);
if (!room) return; if (!room) return;
for (const eventType of ALL_RULE_TYPES) { for (const eventType of ALL_RULE_TYPES) {

View file

@ -67,7 +67,7 @@ export class Mjolnir {
public setup(): void { public setup(): void {
if (!MatrixClientPeg.get()) return; if (!MatrixClientPeg.get()) return;
this.updateLists(SettingsStore.getValue("mjolnirRooms")); this.updateLists(SettingsStore.getValue("mjolnirRooms"));
MatrixClientPeg.get().on(RoomStateEvent.Events, this.onEvent); MatrixClientPeg.get()!.on(RoomStateEvent.Events, this.onEvent);
} }
public stop(): void { public stop(): void {
@ -81,14 +81,13 @@ export class Mjolnir {
this.dispatcherRef = null; this.dispatcherRef = null;
} }
if (!MatrixClientPeg.get()) return; MatrixClientPeg.get()?.removeListener(RoomStateEvent.Events, this.onEvent);
MatrixClientPeg.get().removeListener(RoomStateEvent.Events, this.onEvent);
} }
public async getOrCreatePersonalList(): Promise<BanList> { public async getOrCreatePersonalList(): Promise<BanList> {
let personalRoomId = SettingsStore.getValue("mjolnirPersonalRoom"); let personalRoomId = SettingsStore.getValue("mjolnirPersonalRoom");
if (!personalRoomId) { if (!personalRoomId) {
const resp = await MatrixClientPeg.get().createRoom({ const resp = await MatrixClientPeg.safeGet().createRoom({
name: _t("My Ban List"), name: _t("My Ban List"),
topic: _t("This is your list of users/servers you have blocked - don't leave the room!"), topic: _t("This is your list of users/servers you have blocked - don't leave the room!"),
preset: Preset.PrivateChat, preset: Preset.PrivateChat,

View file

@ -189,7 +189,7 @@ export class ProxiedModuleApi implements ModuleApi {
roomId = getCachedRoomIDForAlias(parts.roomIdOrAlias); roomId = getCachedRoomIDForAlias(parts.roomIdOrAlias);
if (!roomId) { if (!roomId) {
// alias resolution failed // alias resolution failed
const result = await MatrixClientPeg.get().getRoomIdForAlias(parts.roomIdOrAlias); const result = await MatrixClientPeg.safeGet().getRoomIdForAlias(parts.roomIdOrAlias);
roomId = result.room_id; roomId = result.room_id;
if (!servers) servers = result.servers; // use provided servers first, if available if (!servers) servers = result.servers; // use provided servers first, if available
} }

View file

@ -165,7 +165,7 @@ function getDeviceContext(client: MatrixClient): DeviceContext {
} }
async function getContexts(): Promise<Contexts> { async function getContexts(): Promise<Contexts> {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
return { return {
user: getUserContext(client), user: getUserContext(client),
crypto: await getCryptoContext(client), crypto: await getCryptoContext(client),

View file

@ -611,7 +611,7 @@ export default class SettingsStore {
} }
private static migrateHiddenReadReceipts(): void { private static migrateHiddenReadReceipts(): void {
if (MatrixClientPeg.get().isGuest()) return; // not worth it if (MatrixClientPeg.safeGet().isGuest()) return; // not worth it
// We wait for the first sync to ensure that the user's existing account data has loaded, as otherwise // We wait for the first sync to ensure that the user's existing account data has loaded, as otherwise
// getValue() for an account-level setting like sendReadReceipts will return `null`. // getValue() for an account-level setting like sendReadReceipts will return `null`.

View file

@ -28,7 +28,7 @@ import { SettingLevel } from "../SettingLevel";
// default action on this rule is dont_notify, but it could be something else // default action on this rule is dont_notify, but it could be something else
export function isPushNotifyDisabled(): boolean { export function isPushNotifyDisabled(): boolean {
// Return the value of the master push rule as a default // Return the value of the master push rule as a default
const processor = new PushProcessor(MatrixClientPeg.get()); const processor = new PushProcessor(MatrixClientPeg.safeGet());
const masterRule = processor.getPushRuleById(".m.rule.master"); const masterRule = processor.getPushRuleById(".m.rule.master");
if (!masterRule) { if (!masterRule) {

View file

@ -23,7 +23,7 @@ import { getLocalNotificationAccountDataEventType } from "../utils/notifications
const onAccept = (): void => { const onAccept = (): void => {
Notifier.setEnabled(true); Notifier.setEnabled(true);
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const eventType = getLocalNotificationAccountDataEventType(cli.deviceId!); const eventType = getLocalNotificationAccountDataEventType(cli.deviceId!);
cli.setAccountData(eventType, { cli.setAccountData(eventType, {
is_silenced: false, is_silenced: false,

View file

@ -67,7 +67,7 @@ interface Props {
export function IncomingCallToast({ callEvent }: Props): JSX.Element { export function IncomingCallToast({ callEvent }: Props): JSX.Element {
const roomId = callEvent.getRoomId()!; const roomId = callEvent.getRoomId()!;
const room = MatrixClientPeg.get().getRoom(roomId) ?? undefined; const room = MatrixClientPeg.safeGet().getRoom(roomId) ?? undefined;
const call = useCall(roomId); const call = useCall(roomId);
const dismissToast = useCallback((): void => { const dismissToast = useCallback((): void => {

View file

@ -92,7 +92,7 @@ export default class IncomingLegacyCallToast extends React.Component<IProps, ISt
}; };
public render(): React.ReactNode { public render(): React.ReactNode {
const room = MatrixClientPeg.get().getRoom(this.roomId); const room = MatrixClientPeg.safeGet().getRoom(this.roomId);
const isVoice = this.props.call.type === CallType.Voice; const isVoice = this.props.call.type === CallType.Voice;
const callForcedSilent = LegacyCallHandler.instance.isForcedSilent(); const callForcedSilent = LegacyCallHandler.instance.isForcedSilent();

View file

@ -32,7 +32,7 @@ function toastKey(deviceId: string): string {
} }
export const showToast = async (deviceId: string): Promise<void> => { export const showToast = async (deviceId: string): Promise<void> => {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const onAccept = (): void => { const onAccept = (): void => {
DeviceListener.sharedInstance().dismissUnverifiedSessions([deviceId]); DeviceListener.sharedInstance().dismissUnverifiedSessions([deviceId]);

View file

@ -101,7 +101,7 @@ export function getEventDisplayInfo(
// source tile when there's no regular tile for an event and also for // source tile when there's no regular tile for an event and also for
// replace relations (which otherwise would display as a confusing // replace relations (which otherwise would display as a confusing
// duplicate of the thing they are replacing). // duplicate of the thing they are replacing).
if (hideEvent || !haveRendererForEvent(mxEvent, showHiddenEvents)) { if (hideEvent || !haveRendererForEvent(mxEvent, matrixClient, showHiddenEvents)) {
// forcefully ask for a factory for a hidden event (hidden event setting is checked internally) // forcefully ask for a factory for a hidden event (hidden event setting is checked internally)
factory = pickFactory(mxEvent, matrixClient, showHiddenEvents, true); factory = pickFactory(mxEvent, matrixClient, showHiddenEvents, true);
if (factory === JSONEventFactory) { if (factory === JSONEventFactory) {

View file

@ -429,11 +429,12 @@ export default class HTMLExporter extends Exporter {
true, true,
); );
if (this.cancelled) return this.cleanUp(); if (this.cancelled) return this.cleanUp();
if (!haveRendererForEvent(event, false)) continue; if (!haveRendererForEvent(event, this.room.client, false)) continue;
content += this.needsDateSeparator(event, prevEvent) ? this.getDateSeparator(event) : ""; content += this.needsDateSeparator(event, prevEvent) ? this.getDateSeparator(event) : "";
const shouldBeJoined = const shouldBeJoined =
!this.needsDateSeparator(event, prevEvent) && shouldFormContinuation(prevEvent, event, false); !this.needsDateSeparator(event, prevEvent) &&
shouldFormContinuation(prevEvent, event, this.room.client, false);
const body = await this.createMessageBody(event, shouldBeJoined); const body = await this.createMessageBody(event, shouldBeJoined);
this.totalSize += Buffer.byteLength(body); this.totalSize += Buffer.byteLength(body);
content += body; content += body;

View file

@ -93,7 +93,7 @@ export default class JSONExporter extends Exporter {
true, true,
); );
if (this.cancelled) return this.cleanUp(); if (this.cancelled) return this.cleanUp();
if (!haveRendererForEvent(event, false)) continue; if (!haveRendererForEvent(event, this.room.client, false)) continue;
this.messages.push(await this.getJSONString(event)); this.messages.push(await this.getJSONString(event));
} }
return this.createJSONString(); return this.createJSONString();

View file

@ -120,7 +120,7 @@ export default class PlainTextExporter extends Exporter {
true, true,
); );
if (this.cancelled) return this.cleanUp(); if (this.cancelled) return this.cleanUp();
if (!haveRendererForEvent(event, false)) continue; if (!haveRendererForEvent(event, this.room.client, false)) continue;
const textForEvent = await this.plainTextForEvent(event); const textForEvent = await this.plainTextForEvent(event);
content += textForEvent && `${new Date(event.getTs()).toLocaleString()} - ${textForEvent}\n`; content += textForEvent && `${new Date(event.getTs()).toLocaleString()} - ${textForEvent}\n`;
} }

View file

@ -41,7 +41,7 @@ export const useVoiceBroadcastPlayback = (
toggle(): void; toggle(): void;
room: Room; room: Room;
} => { } => {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const room = client.getRoom(playback.infoEvent.getRoomId()); const room = client.getRoom(playback.infoEvent.getRoomId());
if (!room) { if (!room) {

View file

@ -58,7 +58,7 @@ export const useVoiceBroadcastRecording = (
stopRecording(): void; stopRecording(): void;
toggleRecording(): void; toggleRecording(): void;
} => { } => {
const client = MatrixClientPeg.get(); const client = MatrixClientPeg.safeGet();
const roomId = recording.infoEvent.getRoomId(); const roomId = recording.infoEvent.getRoomId();
const room = client.getRoom(roomId); const room = client.getRoom(roomId);

View file

@ -149,7 +149,7 @@ export class CapabilityText {
return { primary: _t("The above, but in any room you are joined or invited to as well") }; return { primary: _t("The above, but in any room you are joined or invited to as well") };
} else { } else {
const roomId = getTimelineRoomIDFromCapability(capability); const roomId = getTimelineRoomIDFromCapability(capability);
const room = MatrixClientPeg.get().getRoom(roomId); const room = MatrixClientPeg.safeGet().getRoom(roomId);
return { return {
primary: _t( primary: _t(
"The above, but in <Room /> as well", "The above, but in <Room /> as well",

View file

@ -62,7 +62,7 @@ export class Jitsi {
} }
public start(): void { public start(): void {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
cli.on(ClientEvent.ClientWellKnown, this.update); cli.on(ClientEvent.ClientWellKnown, this.update);
// call update initially in case we missed the first WellKnown.client event and for if no well-known present // call update initially in case we missed the first WellKnown.client event and for if no well-known present
this.update(cli.getClientWellKnown()); this.update(cli.getClientWellKnown());

View file

@ -43,7 +43,7 @@ function getWidgetBuildUrl(roomId: string): string | undefined {
return SdkConfig.get().widget_build_url; return SdkConfig.get().widget_build_url;
} }
const wellKnown = getCallBehaviourWellKnown(MatrixClientPeg.get()); const wellKnown = getCallBehaviourWellKnown(MatrixClientPeg.safeGet());
if (isDm && wellKnown?.ignore_dm) { if (isDm && wellKnown?.ignore_dm) {
return undefined; return undefined;
} }
@ -56,7 +56,7 @@ export function isManagedHybridWidgetEnabled(roomId: string): boolean {
} }
export async function addManagedHybridWidget(roomId: string): Promise<void> { export async function addManagedHybridWidget(roomId: string): Promise<void> {
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.safeGet();
const room = cli.getRoom(roomId); const room = cli.getRoom(roomId);
if (!room) { if (!room) {
return; return;

View file

@ -81,13 +81,13 @@ describe("Unread", () => {
it("returns false for an event without a renderer", () => { it("returns false for an event without a renderer", () => {
mocked(haveRendererForEvent).mockReturnValue(false); mocked(haveRendererForEvent).mockReturnValue(false);
expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(false); expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(false);
expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, false); expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, client, false);
}); });
it("returns true for an event with a renderer", () => { it("returns true for an event with a renderer", () => {
mocked(haveRendererForEvent).mockReturnValue(true); mocked(haveRendererForEvent).mockReturnValue(true);
expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(true); expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(true);
expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, false); expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, client, false);
}); });
it("returns false for beacon locations", () => { it("returns false for beacon locations", () => {

View file

@ -29,6 +29,7 @@ import RoomContext, { TimelineRenderingType } from "../../../src/contexts/RoomCo
import DMRoomMap from "../../../src/utils/DMRoomMap"; import DMRoomMap from "../../../src/utils/DMRoomMap";
import * as TestUtilsMatrix from "../../test-utils"; import * as TestUtilsMatrix from "../../test-utils";
import { import {
createTestClient,
getMockClientWithEventEmitter, getMockClientWithEventEmitter,
makeBeaconInfoEvent, makeBeaconInfoEvent,
mockClientMethodsEvents, mockClientMethodsEvents,
@ -773,16 +774,17 @@ describe("shouldFormContinuation", () => {
msg: "And here's another message in the main timeline after the thread root", msg: "And here's another message in the main timeline after the thread root",
}); });
expect(shouldFormContinuation(message1, message2, false)).toEqual(true); const client = createTestClient();
expect(shouldFormContinuation(message2, threadRoot, false)).toEqual(true); expect(shouldFormContinuation(message1, message2, client, false)).toEqual(true);
expect(shouldFormContinuation(threadRoot, message3, false)).toEqual(true); expect(shouldFormContinuation(message2, threadRoot, client, false)).toEqual(true);
expect(shouldFormContinuation(threadRoot, message3, client, false)).toEqual(true);
const thread = { const thread = {
length: 1, length: 1,
replyToEvent: {}, replyToEvent: {},
} as unknown as Thread; } as unknown as Thread;
jest.spyOn(threadRoot, "getThread").mockReturnValue(thread); jest.spyOn(threadRoot, "getThread").mockReturnValue(thread);
expect(shouldFormContinuation(message2, threadRoot, false)).toEqual(false); expect(shouldFormContinuation(message2, threadRoot, client, false)).toEqual(false);
expect(shouldFormContinuation(threadRoot, message3, false)).toEqual(false); expect(shouldFormContinuation(threadRoot, message3, client, false)).toEqual(false);
}); });
}); });

View file

@ -28,7 +28,7 @@ jest.mock("../../../../../src/SecurityManager", () => ({
describe("CreateKeyBackupDialog", () => { describe("CreateKeyBackupDialog", () => {
beforeEach(() => { beforeEach(() => {
MatrixClientPeg.get = () => createTestClient(); MatrixClientPeg.safeGet = MatrixClientPeg.get = () => createTestClient();
}); });
it("should display the spinner when creating backup", () => { it("should display the spinner when creating backup", () => {
@ -42,7 +42,7 @@ describe("CreateKeyBackupDialog", () => {
it("should display the error message when backup creation failed", async () => { it("should display the error message when backup creation failed", async () => {
const matrixClient = createTestClient(); const matrixClient = createTestClient();
mocked(matrixClient.scheduleAllGroupSessionsForBackup).mockRejectedValue("my error"); mocked(matrixClient.scheduleAllGroupSessionsForBackup).mockRejectedValue("my error");
MatrixClientPeg.get = () => matrixClient; MatrixClientPeg.safeGet = MatrixClientPeg.get = () => matrixClient;
const { asFragment } = render(<CreateKeyBackupDialog onFinished={jest.fn()} />); const { asFragment } = render(<CreateKeyBackupDialog onFinished={jest.fn()} />);

View file

@ -95,8 +95,8 @@ describe("<RoomPreviewBar />", () => {
beforeEach(() => { beforeEach(() => {
stubClient(); stubClient();
MatrixClientPeg.get().getUserId = jest.fn().mockReturnValue(userId); MatrixClientPeg.get()!.getUserId = jest.fn().mockReturnValue(userId);
MatrixClientPeg.get().getSafeUserId = jest.fn().mockReturnValue(userId); MatrixClientPeg.get()!.getSafeUserId = jest.fn().mockReturnValue(userId);
MatrixClientPeg.safeGet().getUserId = jest.fn().mockReturnValue(userId); MatrixClientPeg.safeGet().getUserId = jest.fn().mockReturnValue(userId);
MatrixClientPeg.safeGet().getSafeUserId = jest.fn().mockReturnValue(userId); MatrixClientPeg.safeGet().getSafeUserId = jest.fn().mockReturnValue(userId);
}); });