From de16d347e9294f9f4771ca4bc950fcf1e8c1acb4 Mon Sep 17 00:00:00 2001 From: alunturner <56027671+alunturner@users.noreply.github.com> Date: Fri, 5 May 2023 17:08:07 +0100 Subject: [PATCH] Apply strictNullChecks to src/LegacyCallHandler.tsx (#10690) --- src/LegacyCallHandler.tsx | 52 ++++++++++++++++++++++++++------------- src/Typeguards.ts | 19 ++++++++++++++ 2 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 src/Typeguards.ts diff --git a/src/LegacyCallHandler.tsx b/src/LegacyCallHandler.tsx index bf0d09db29..0fd8a7f5b9 100644 --- a/src/LegacyCallHandler.tsx +++ b/src/LegacyCallHandler.tsx @@ -18,6 +18,7 @@ limitations under the License. */ import React from "react"; +import { MatrixError } from "matrix-js-sdk/src/matrix"; import { CallError, CallErrorCode, @@ -29,7 +30,7 @@ import { } from "matrix-js-sdk/src/webrtc/call"; import { logger } from "matrix-js-sdk/src/logger"; import EventEmitter from "events"; -import { RuleId, TweakName, Tweaks } from "matrix-js-sdk/src/@types/PushRules"; +import { RuleId, TweakName } from "matrix-js-sdk/src/@types/PushRules"; import { PushProcessor } from "matrix-js-sdk/src/pushprocessor"; import { SyncState } from "matrix-js-sdk/src/sync"; import { CallEventHandlerEvent } from "matrix-js-sdk/src/webrtc/callEventHandler"; @@ -65,6 +66,7 @@ import { getJoinedNonFunctionalMembers } from "./utils/room/getJoinedNonFunction import { localNotificationsAreSilenced } from "./utils/notifications"; import { SdkContextClass } from "./contexts/SDKContext"; import { showCantStartACallDialog } from "./voice-broadcast/utils/showCantStartACallDialog"; +import { isNotNull } from "./Typeguards"; export const PROTOCOL_PSTN = "m.protocol.pstn"; export const PROTOCOL_PSTN_PREFIXED = "im.vector.protocol.pstn"; @@ -582,7 +584,9 @@ export default class LegacyCallHandler extends EventEmitter { call.on(CallEvent.Hangup, () => { if (!mappedRoomId || !this.matchesCallForThisRoom(call)) return; - this.removeCallForRoom(mappedRoomId); + if (isNotNull(mappedRoomId)) { + this.removeCallForRoom(mappedRoomId); + } }); call.on(CallEvent.State, (newState: CallState, oldState: CallState) => { this.onCallStateChanged(newState, oldState, call); @@ -598,8 +602,10 @@ export default class LegacyCallHandler extends EventEmitter { this.pause(AudioID.Ringback); } - this.removeCallForRoom(mappedRoomId); - this.addCallForRoom(mappedRoomId, newCall); + if (isNotNull(mappedRoomId)) { + this.removeCallForRoom(mappedRoomId); + this.addCallForRoom(mappedRoomId, newCall); + } this.setCallListeners(newCall); this.setCallState(newCall, newCall.state); }); @@ -635,7 +641,7 @@ export default class LegacyCallHandler extends EventEmitter { const newMappedRoomId = this.roomIdForCall(call); logger.log(`Old room ID: ${mappedRoomId}, new room ID: ${newMappedRoomId}`); - if (newMappedRoomId && newMappedRoomId !== mappedRoomId) { + if (newMappedRoomId !== mappedRoomId && isNotNull(mappedRoomId) && isNotNull(newMappedRoomId)) { this.removeCallForRoom(mappedRoomId); mappedRoomId = newMappedRoomId; logger.log("Moving call to room " + mappedRoomId); @@ -675,8 +681,11 @@ export default class LegacyCallHandler extends EventEmitter { RuleId.IncomingCall, ); const pushRuleEnabled = incomingCallPushRule?.enabled; + // actions can be either Tweaks | PushRuleActionName, ie an object or a string type enum + // and we want to only run this check on the Tweaks const tweakSetToRing = incomingCallPushRule?.actions.some( - (action: Tweaks) => action.set_tweak === TweakName.Sound && action.value === "ring", + (action) => + typeof action !== "string" && action.set_tweak === TweakName.Sound && action.value === "ring", ); if (pushRuleEnabled && tweakSetToRing && !this.isForcedSilent()) { @@ -692,7 +701,10 @@ export default class LegacyCallHandler extends EventEmitter { } case CallState.Ended: { const hangupReason = call.hangupReason; - this.removeCallForRoom(mappedRoomId); + if (isNotNull(mappedRoomId)) { + this.removeCallForRoom(mappedRoomId); + } + if (oldState === CallState.InviteSent && call.hangupParty === CallParty.Remote) { this.play(AudioID.Busy); @@ -724,7 +736,9 @@ export default class LegacyCallHandler extends EventEmitter { this.play(AudioID.CallEnd); } - this.logCallStats(call, mappedRoomId); + if (isNotNull(mappedRoomId)) { + this.logCallStats(call, mappedRoomId); + } break; } } @@ -1081,13 +1095,15 @@ export default class LegacyCallHandler extends EventEmitter { const roomId = await ensureDMExists(MatrixClientPeg.get(), nativeUserId); - dis.dispatch({ - action: Action.ViewRoom, - room_id: roomId, - metricsTrigger: "WebDialPad", - }); + if (isNotNull(roomId)) { + dis.dispatch({ + action: Action.ViewRoom, + room_id: roomId, + metricsTrigger: "WebDialPad", + }); - await this.placeMatrixCall(roomId, CallType.Voice, transferee); + await this.placeMatrixCall(roomId, CallType.Voice, transferee); + } } public async startTransferToPhoneNumber( @@ -1183,9 +1199,11 @@ export default class LegacyCallHandler extends EventEmitter { // Prevent double clicking the call button const widget = WidgetStore.instance.getApps(roomId).find((app) => WidgetType.JITSI.matches(app.type)); if (widget) { - const room = client.getRoom(roomId); // If there already is a Jitsi widget, pin it - if (room) WidgetLayoutStore.instance.moveToContainer(room, widget, Container.Top); + const room = client.getRoom(roomId); + if (isNotNull(room)) { + WidgetLayoutStore.instance.moveToContainer(room, widget, Container.Top); + } return; } @@ -1193,7 +1211,7 @@ export default class LegacyCallHandler extends EventEmitter { await WidgetUtils.addJitsiWidget(roomId, type, "Jitsi", false); logger.log("Jitsi widget added"); } catch (e) { - if (e.errcode === "M_FORBIDDEN") { + if (e instanceof MatrixError && e.errcode === "M_FORBIDDEN") { Modal.createDialog(ErrorDialog, { title: _t("Permission Required"), description: _t("You do not have permission to start a conference call in this room"), diff --git a/src/Typeguards.ts b/src/Typeguards.ts new file mode 100644 index 0000000000..78869097c6 --- /dev/null +++ b/src/Typeguards.ts @@ -0,0 +1,19 @@ +/* +Copyright 2023 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +export function isNotNull(arg: T): arg is Exclude { + return arg !== null; +}