diff --git a/src/AddThreepid.ts b/src/AddThreepid.ts index 399c0d9883..42c6068b87 100644 --- a/src/AddThreepid.ts +++ b/src/AddThreepid.ts @@ -16,18 +16,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { IAuthData, IRequestMsisdnTokenResponse, IRequestTokenResponse } from "matrix-js-sdk/src/matrix"; +import { IAuthData, IRequestMsisdnTokenResponse, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/matrix"; import { MatrixError, HTTPError } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import Modal from "./Modal"; import { _t, UserFriendlyError } from "./languageHandler"; import IdentityAuthClient from "./IdentityAuthClient"; import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryComponents"; import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog"; -function getIdServerDomain(): string { - const idBaseUrl = MatrixClientPeg.get().getIdentityServerUrl(true); +function getIdServerDomain(matrixClient: MatrixClient): string { + const idBaseUrl = matrixClient.getIdentityServerUrl(true); if (!idBaseUrl) { throw new UserFriendlyError("Identity server not set"); } @@ -55,11 +54,11 @@ export type Binding = { export default class AddThreepid { private sessionId: string; private submitUrl?: string; - private clientSecret: string; private bind = false; + private readonly clientSecret: string; - public constructor() { - this.clientSecret = MatrixClientPeg.get().generateClientSecret(); + public constructor(private readonly matrixClient: MatrixClient) { + this.clientSecret = matrixClient.generateClientSecret(); } /** @@ -70,7 +69,7 @@ export default class AddThreepid { */ public async addEmailAddress(emailAddress: string): Promise { try { - const res = await MatrixClientPeg.get().requestAdd3pidEmailToken(emailAddress, this.clientSecret, 1); + const res = await this.matrixClient.requestAdd3pidEmailToken(emailAddress, this.clientSecret, 1); this.sessionId = res.sid; return res; } catch (err) { @@ -90,12 +89,12 @@ export default class AddThreepid { */ public async bindEmailAddress(emailAddress: string): Promise { this.bind = true; - if (await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) { + if (await this.matrixClient.doesServerSupportSeparateAddAndBind()) { // For separate bind, request a token directly from the IS. const authClient = new IdentityAuthClient(); const identityAccessToken = (await authClient.getAccessToken()) ?? undefined; try { - const res = await MatrixClientPeg.get().requestEmailToken( + const res = await this.matrixClient.requestEmailToken( emailAddress, this.clientSecret, 1, @@ -126,7 +125,7 @@ export default class AddThreepid { */ public async addMsisdn(phoneCountry: string, phoneNumber: string): Promise { try { - const res = await MatrixClientPeg.get().requestAdd3pidMsisdnToken( + const res = await this.matrixClient.requestAdd3pidMsisdnToken( phoneCountry, phoneNumber, this.clientSecret, @@ -153,12 +152,12 @@ export default class AddThreepid { */ public async bindMsisdn(phoneCountry: string, phoneNumber: string): Promise { this.bind = true; - if (await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) { + if (await this.matrixClient.doesServerSupportSeparateAddAndBind()) { // For separate bind, request a token directly from the IS. const authClient = new IdentityAuthClient(); const identityAccessToken = (await authClient.getAccessToken()) ?? undefined; try { - const res = await MatrixClientPeg.get().requestMsisdnToken( + const res = await this.matrixClient.requestMsisdnToken( phoneCountry, phoneNumber, this.clientSecret, @@ -189,17 +188,17 @@ export default class AddThreepid { */ public async checkEmailLinkClicked(): Promise<[success?: boolean, result?: IAuthData | Error | null]> { try { - if (await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind()) { + if (await this.matrixClient.doesServerSupportSeparateAddAndBind()) { if (this.bind) { const authClient = new IdentityAuthClient(); const identityAccessToken = await authClient.getAccessToken(); if (!identityAccessToken) { throw new UserFriendlyError("No identity access token found"); } - await MatrixClientPeg.get().bindThreePid({ + await this.matrixClient.bindThreePid({ sid: this.sessionId, client_secret: this.clientSecret, - id_server: getIdServerDomain(), + id_server: getIdServerDomain(this.matrixClient), id_access_token: identityAccessToken, }); } else { @@ -233,7 +232,7 @@ export default class AddThreepid { }; const { finished } = Modal.createDialog(InteractiveAuthDialog, { title: _t("Add Email Address"), - matrixClient: MatrixClientPeg.get(), + matrixClient: this.matrixClient, authData: err.data, makeRequest: this.makeAddThreepidOnlyRequest, aestheticsForStagePhases: { @@ -245,11 +244,11 @@ export default class AddThreepid { } } } else { - await MatrixClientPeg.get().addThreePid( + await this.matrixClient.addThreePid( { sid: this.sessionId, client_secret: this.clientSecret, - id_server: getIdServerDomain(), + id_server: getIdServerDomain(this.matrixClient), }, this.bind, ); @@ -272,7 +271,7 @@ export default class AddThreepid { * @return {Promise} Response from /3pid/add call (in current spec, an empty object) */ private makeAddThreepidOnlyRequest = (auth?: { type: string; session?: string }): Promise<{}> => { - return MatrixClientPeg.get().addThreePidOnly({ + return this.matrixClient.addThreePidOnly({ sid: this.sessionId, client_secret: this.clientSecret, auth, @@ -291,18 +290,18 @@ export default class AddThreepid { msisdnToken: string, ): Promise<[success?: boolean, result?: IAuthData | Error | null] | undefined> { const authClient = new IdentityAuthClient(); - const supportsSeparateAddAndBind = await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind(); + const supportsSeparateAddAndBind = await this.matrixClient.doesServerSupportSeparateAddAndBind(); let result: { success: boolean } | MatrixError; if (this.submitUrl) { - result = await MatrixClientPeg.get().submitMsisdnTokenOtherUrl( + result = await this.matrixClient.submitMsisdnTokenOtherUrl( this.submitUrl, this.sessionId, this.clientSecret, msisdnToken, ); } else if (this.bind || !supportsSeparateAddAndBind) { - result = await MatrixClientPeg.get().submitMsisdnToken( + result = await this.matrixClient.submitMsisdnToken( this.sessionId, this.clientSecret, msisdnToken, @@ -317,10 +316,10 @@ export default class AddThreepid { if (supportsSeparateAddAndBind) { if (this.bind) { - await MatrixClientPeg.get().bindThreePid({ + await this.matrixClient.bindThreePid({ sid: this.sessionId, client_secret: this.clientSecret, - id_server: getIdServerDomain(), + id_server: getIdServerDomain(this.matrixClient), id_access_token: await authClient.getAccessToken(), }); } else { @@ -354,7 +353,7 @@ export default class AddThreepid { }; const { finished } = Modal.createDialog(InteractiveAuthDialog, { title: _t("Add Phone Number"), - matrixClient: MatrixClientPeg.get(), + matrixClient: this.matrixClient, authData: err.data, makeRequest: this.makeAddThreepidOnlyRequest, aestheticsForStagePhases: { @@ -366,11 +365,11 @@ export default class AddThreepid { } } } else { - await MatrixClientPeg.get().addThreePid( + await this.matrixClient.addThreePid( { sid: this.sessionId, client_secret: this.clientSecret, - id_server: getIdServerDomain(), + id_server: getIdServerDomain(this.matrixClient), }, this.bind, ); diff --git a/src/Resend.ts b/src/Resend.ts index 17e39a7e29..cbd43661c4 100644 --- a/src/Resend.ts +++ b/src/Resend.ts @@ -17,8 +17,8 @@ limitations under the License. import { MatrixEvent, EventStatus } from "matrix-js-sdk/src/models/event"; import { Room } from "matrix-js-sdk/src/models/room"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import dis from "./dispatcher/dispatcher"; export default class Resend { @@ -30,7 +30,7 @@ export default class Resend { return ev.status === EventStatus.NOT_SENT; }) .map(function (event: MatrixEvent) { - return Resend.resend(event); + return Resend.resend(room.client, event); }), ); } @@ -41,30 +41,28 @@ export default class Resend { return ev.status === EventStatus.NOT_SENT; }) .forEach(function (event: MatrixEvent) { - Resend.removeFromQueue(event); + Resend.removeFromQueue(room.client, event); }); } - public static resend(event: MatrixEvent): Promise { - const room = MatrixClientPeg.get().getRoom(event.getRoomId())!; - return MatrixClientPeg.get() - .resendEvent(event, room) - .then( - function (res) { - dis.dispatch({ - action: "message_sent", - event: event, - }); - }, - function (err: Error) { - // XXX: temporary logging to try to diagnose - // https://github.com/vector-im/element-web/issues/3148 - logger.log("Resend got send failure: " + err.name + "(" + err + ")"); - }, - ); + public static resend(client: MatrixClient, event: MatrixEvent): Promise { + const room = client.getRoom(event.getRoomId())!; + return client.resendEvent(event, room).then( + function (res) { + dis.dispatch({ + action: "message_sent", + event: event, + }); + }, + function (err: Error) { + // XXX: temporary logging to try to diagnose + // https://github.com/vector-im/element-web/issues/3148 + logger.log("Resend got send failure: " + err.name + "(" + err + ")"); + }, + ); } - public static removeFromQueue(event: MatrixEvent): void { - MatrixClientPeg.get().cancelPendingEvent(event); + public static removeFromQueue(client: MatrixClient, event: MatrixEvent): void { + client.cancelPendingEvent(event); } } diff --git a/src/RoomInvite.tsx b/src/RoomInvite.tsx index 4e84b4a48a..6c49de2090 100644 --- a/src/RoomInvite.tsx +++ b/src/RoomInvite.tsx @@ -22,7 +22,6 @@ import { logger } from "matrix-js-sdk/src/logger"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import MultiInviter, { CompletionStates } from "./utils/MultiInviter"; import Modal from "./Modal"; import { _t } from "./languageHandler"; @@ -115,7 +114,7 @@ export function inviteUsersToRoom( ): Promise { return inviteMultipleToRoom(client, roomId, userIds, sendSharedHistoryKeys, progressCallback) .then((result) => { - const room = MatrixClientPeg.get().getRoom(roomId)!; + const room = client.getRoom(roomId)!; showAnyInviteErrors(result.states, room, result.inviter); }) .catch((err) => { @@ -153,7 +152,7 @@ export function showAnyInviteErrors( } } - const cli = MatrixClientPeg.get(); + const cli = room.client; if (errorList.length > 0) { // React 16 doesn't let us use `errorList.join(
)` anymore, so this is our solution const description = ( diff --git a/src/Rooms.ts b/src/Rooms.ts index a79204995f..b92afbaa7f 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -46,7 +46,7 @@ export function getDisplayAliasForAliasSet(canonicalAlias: string | null, altAli export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise { let newTarget; if (isDirect) { - const guessedUserId = guessDMRoomTargetId(room, MatrixClientPeg.get().getUserId()!); + const guessedUserId = guessDMRoomTargetId(room, room.client.getSafeUserId()); newTarget = guessedUserId; } else { newTarget = null; diff --git a/src/Searching.ts b/src/Searching.ts index 25800c8e06..5ec128b0aa 100644 --- a/src/Searching.ts +++ b/src/Searching.ts @@ -25,20 +25,19 @@ import { import { IRoomEventFilter } from "matrix-js-sdk/src/filter"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { SearchResult } from "matrix-js-sdk/src/models/search-result"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { ISearchArgs } from "./indexing/BaseEventIndexManager"; import EventIndexPeg from "./indexing/EventIndexPeg"; -import { MatrixClientPeg } from "./MatrixClientPeg"; const SEARCH_LIMIT = 10; async function serverSideSearch( + client: MatrixClient, term: string, roomId?: string, abortSignal?: AbortSignal, ): Promise<{ response: ISearchResponse; query: ISearchRequestBody }> { - const client = MatrixClientPeg.get(); - const filter: IRoomEventFilter = { limit: SEARCH_LIMIT, }; @@ -66,12 +65,12 @@ async function serverSideSearch( } async function serverSideSearchProcess( + client: MatrixClient, term: string, roomId?: string, abortSignal?: AbortSignal, ): Promise { - const client = MatrixClientPeg.get(); - const result = await serverSideSearch(term, roomId, abortSignal); + const result = await serverSideSearch(client, term, roomId, abortSignal); // The js-sdk method backPaginateRoomEventsSearch() uses _query internally // so we're reusing the concept here since we want to delegate the @@ -96,12 +95,14 @@ function compareEvents(a: ISearchResult, b: ISearchResult): number { return 0; } -async function combinedSearch(searchTerm: string, abortSignal?: AbortSignal): Promise { - const client = MatrixClientPeg.get(); - +async function combinedSearch( + client: MatrixClient, + searchTerm: string, + abortSignal?: AbortSignal, +): Promise { // Create two promises, one for the local search, one for the // server-side search. - const serverSidePromise = serverSideSearch(searchTerm, undefined, abortSignal); + const serverSidePromise = serverSideSearch(client, searchTerm, undefined, abortSignal); const localPromise = localSearch(searchTerm); // Wait for both promises to resolve. @@ -198,7 +199,11 @@ export interface ISeshatSearchResults extends ISearchResults { serverSideNextBatch?: string; } -async function localSearchProcess(searchTerm: string, roomId?: string): Promise { +async function localSearchProcess( + client: MatrixClient, + searchTerm: string, + roomId?: string, +): Promise { const emptyResult = { results: [], highlights: [], @@ -216,14 +221,17 @@ async function localSearchProcess(searchTerm: string, roomId?: string): Promise< }, }; - const processedResult = MatrixClientPeg.get().processRoomEventsSearch(emptyResult, response); + const processedResult = client.processRoomEventsSearch(emptyResult, response); // Restore our encryption info so we can properly re-verify the events. restoreEncryptionInfo(processedResult.results); return processedResult; } -async function localPagination(searchResult: ISeshatSearchResults): Promise { +async function localPagination( + client: MatrixClient, + searchResult: ISeshatSearchResults, +): Promise { const eventIndex = EventIndexPeg.get(); const searchArgs = searchResult.seshatQuery; @@ -245,7 +253,7 @@ async function localPagination(searchResult: ISeshatSearchResults): Promise { +async function combinedPagination( + client: MatrixClient, + searchResult: ISeshatSearchResults, +): Promise { const eventIndex = EventIndexPeg.get(); - const client = MatrixClientPeg.get(); const searchArgs = searchResult.seshatQuery; const oldestEventFrom = searchResult.oldestEventFrom; @@ -588,31 +598,37 @@ async function combinedPagination(searchResult: ISeshatSearchResults): Promise { +function eventIndexSearch( + client: MatrixClient, + term: string, + roomId?: string, + abortSignal?: AbortSignal, +): Promise { let searchPromise: Promise; if (roomId !== undefined) { - if (MatrixClientPeg.get().isRoomEncrypted(roomId)) { + if (client.isRoomEncrypted(roomId)) { // The search is for a single encrypted room, use our local // search method. - searchPromise = localSearchProcess(term, roomId); + searchPromise = localSearchProcess(client, term, roomId); } else { // The search is for a single non-encrypted room, use the // server-side search. - searchPromise = serverSideSearchProcess(term, roomId, abortSignal); + searchPromise = serverSideSearchProcess(client, term, roomId, abortSignal); } } else { // Search across all rooms, combine a server side search and a // local search. - searchPromise = combinedSearch(term, abortSignal); + searchPromise = combinedSearch(client, term, abortSignal); } return searchPromise; } -function eventIndexSearchPagination(searchResult: ISeshatSearchResults): Promise { - const client = MatrixClientPeg.get(); - +function eventIndexSearchPagination( + client: MatrixClient, + searchResult: ISeshatSearchResults, +): Promise { const seshatQuery = searchResult.seshatQuery; const serverQuery = searchResult._query; @@ -622,36 +638,40 @@ function eventIndexSearchPagination(searchResult: ISeshatSearchResults): Promise return client.backPaginateRoomEventsSearch(searchResult); } else if (!serverQuery) { // This is a search in a encrypted room. Do a local pagination. - const promise = localPagination(searchResult); + const promise = localPagination(client, searchResult); searchResult.pendingRequest = promise; return promise; } else { // We have both queries around, this is a search across all rooms so a // combined pagination needs to be done. - const promise = combinedPagination(searchResult); + const promise = combinedPagination(client, searchResult); searchResult.pendingRequest = promise; return promise; } } -export function searchPagination(searchResult: ISearchResults): Promise { +export function searchPagination(client: MatrixClient, searchResult: ISearchResults): Promise { const eventIndex = EventIndexPeg.get(); - const client = MatrixClientPeg.get(); if (searchResult.pendingRequest) return searchResult.pendingRequest; if (eventIndex === null) return client.backPaginateRoomEventsSearch(searchResult); - else return eventIndexSearchPagination(searchResult); + else return eventIndexSearchPagination(client, searchResult); } -export default function eventSearch(term: string, roomId?: string, abortSignal?: AbortSignal): Promise { +export default function eventSearch( + client: MatrixClient, + term: string, + roomId?: string, + abortSignal?: AbortSignal, +): Promise { const eventIndex = EventIndexPeg.get(); if (eventIndex === null) { - return serverSideSearchProcess(term, roomId, abortSignal); + return serverSideSearchProcess(client, term, roomId, abortSignal); } else { - return eventIndexSearch(term, roomId, abortSignal); + return eventIndexSearch(client, term, roomId, abortSignal); } } diff --git a/src/Unread.ts b/src/Unread.ts index 25bf1c3529..3b1826b3a6 100644 --- a/src/Unread.ts +++ b/src/Unread.ts @@ -20,8 +20,8 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { M_BEACON } from "matrix-js-sdk/src/@types/beacon"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import shouldHideEvent from "./shouldHideEvent"; import { haveRendererForEvent } from "./events/EventTileFactory"; import SettingsStore from "./settings/SettingsStore"; @@ -30,11 +30,12 @@ import SettingsStore from "./settings/SettingsStore"; * Returns true if this event arriving in a room should affect the room's * count of unread messages * + * @param client The Matrix Client instance of the logged-in user * @param {Object} ev The event * @returns {boolean} True if the given event should affect the unread message count */ -export function eventTriggersUnreadCount(ev: MatrixEvent): boolean { - if (ev.getSender() === MatrixClientPeg.get().credentials.userId) { +export function eventTriggersUnreadCount(client: MatrixClient, ev: MatrixEvent): boolean { + if (ev.getSender() === client.getSafeUserId()) { return false; } @@ -83,7 +84,7 @@ export function doesRoomOrThreadHaveUnreadMessages(roomOrThread: Room | Thread): return false; } - const myUserId = MatrixClientPeg.get().getUserId()!; + const myUserId = roomOrThread.client.getSafeUserId(); // as we don't send RRs for our own messages, make sure we special case that // if *we* sent the last message into the room, we consider it not unread! @@ -107,7 +108,7 @@ export function doesRoomOrThreadHaveUnreadMessages(roomOrThread: Room | Thread): // that counts and we can stop looking because the user's read // this and everything before. return false; - } else if (isImportantEvent(ev)) { + } else if (isImportantEvent(roomOrThread.client, ev)) { // We've found a message that counts before we hit // the user's read receipt, so this room is definitely unread. return true; @@ -129,8 +130,8 @@ export function doesRoomOrThreadHaveUnreadMessages(roomOrThread: Room | Thread): * Given this event does not have a receipt, is it important enough to make * this room unread? */ -function isImportantEvent(event: MatrixEvent): boolean { - return !shouldHideEvent(event) && eventTriggersUnreadCount(event); +function isImportantEvent(client: MatrixClient, event: MatrixEvent): boolean { + return !shouldHideEvent(event) && eventTriggersUnreadCount(client, event); } /** diff --git a/src/WhoIsTyping.ts b/src/WhoIsTyping.ts index d4a43636ce..500d60e0b9 100644 --- a/src/WhoIsTyping.ts +++ b/src/WhoIsTyping.ts @@ -17,15 +17,14 @@ limitations under the License. import { Room } from "matrix-js-sdk/src/models/room"; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import { _t } from "./languageHandler"; export function usersTypingApartFromMeAndIgnored(room: Room): RoomMember[] { - return usersTyping(room, [MatrixClientPeg.get().getUserId()!].concat(MatrixClientPeg.get().getIgnoredUsers())); + return usersTyping(room, [room.client.getSafeUserId()].concat(room.client.getIgnoredUsers())); } export function usersTypingApartFromMe(room: Room): RoomMember[] { - return usersTyping(room, [MatrixClientPeg.get().getUserId()!]); + return usersTyping(room, [room.client.getSafeUserId()]); } /** diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 6798d6a444..fef5d26daf 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -625,7 +625,7 @@ export default class MatrixChat extends React.PureComponent { this.notifyNewScreen("forgot_password"); break; case "start_chat": - createRoom({ + createRoom(MatrixClientPeg.get(), { dmUserId: payload.user_id, }); break; @@ -1062,7 +1062,7 @@ export default class MatrixChat extends React.PureComponent { const [shouldCreate, opts] = await modal.finished; if (shouldCreate) { - createRoom(opts!); + createRoom(MatrixClientPeg.get(), opts!); } } @@ -1246,7 +1246,7 @@ export default class MatrixChat extends React.PureComponent { const welcomeUserRooms = DMRoomMap.shared().getDMRoomsForUserId(welcomeUserId); if (welcomeUserRooms.length === 0) { - const roomId = await createRoom({ + const roomId = await createRoom(MatrixClientPeg.get(), { dmUserId: snakedConfig.get("welcome_user_id"), // Only view the welcome user if we're NOT looking at a room andView: !this.state.currentRoomId, diff --git a/src/components/structures/RoomSearchView.tsx b/src/components/structures/RoomSearchView.tsx index 1249f4c47e..83a63387d5 100644 --- a/src/components/structures/RoomSearchView.tsx +++ b/src/components/structures/RoomSearchView.tsx @@ -181,7 +181,7 @@ export const RoomSearchView = forwardRef( } debuglog("requesting more search results"); - const searchPromise = searchPagination(results); + const searchPromise = searchPagination(client, results); return handleSearchResult(searchPromise); }; diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index eb1551cabf..786344e281 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -1621,7 +1621,7 @@ export class RoomView extends React.Component { const roomId = scope === SearchScope.Room ? this.getRoomId() : undefined; debuglog("sending search request"); const abortController = new AbortController(); - const promise = eventSearch(term, roomId, abortController.signal); + const promise = eventSearch(this.context.client!, term, roomId, abortController.signal); this.setState({ search: { diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 4e163a820f..aee94a1d8a 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -336,7 +336,7 @@ const SpaceSetupFirstRooms: React.FC<{ const filteredRoomNames = roomNames.map((name) => name.trim()).filter(Boolean); const roomIds = await Promise.all( filteredRoomNames.map((name) => { - return createRoom({ + return createRoom(space.client, { createOpts: { preset: isPublic ? Preset.PublicChat : Preset.PrivateChat, name, diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index bfa6b0f9d9..9fc7ca8110 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -201,7 +201,7 @@ export default class MessageContextMenu extends React.Component private onResendReactionsClick = (): void => { for (const reaction of this.getUnsentReactions()) { - Resend.resend(reaction); + Resend.resend(MatrixClientPeg.get(), reaction); } this.closeMenu(); }; diff --git a/src/components/views/dialogs/CreateSubspaceDialog.tsx b/src/components/views/dialogs/CreateSubspaceDialog.tsx index 19a4778914..ac152f1da6 100644 --- a/src/components/views/dialogs/CreateSubspaceDialog.tsx +++ b/src/components/views/dialogs/CreateSubspaceDialog.tsx @@ -79,7 +79,16 @@ const CreateSubspaceDialog: React.FC = ({ space, onAddExistingSpaceClick } try { - await createSpace(name, joinRule === JoinRule.Public, alias, topic, avatar, {}, { parentSpace, joinRule }); + await createSpace( + space.client, + name, + joinRule === JoinRule.Public, + alias, + topic, + avatar, + {}, + { parentSpace, joinRule }, + ); onFinished(true); } catch (e) { diff --git a/src/components/views/dialogs/SetEmailDialog.tsx b/src/components/views/dialogs/SetEmailDialog.tsx index bec380e66a..56c386b330 100644 --- a/src/components/views/dialogs/SetEmailDialog.tsx +++ b/src/components/views/dialogs/SetEmailDialog.tsx @@ -28,6 +28,7 @@ import ErrorDialog, { extractErrorMessageFromError } from "./ErrorDialog"; import QuestionDialog from "./QuestionDialog"; import BaseDialog from "./BaseDialog"; import EditableText from "../elements/EditableText"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; interface IProps { title: string; @@ -71,7 +72,7 @@ export default class SetEmailDialog extends React.Component { }); return; } - this.addThreepid = new AddThreepid(); + this.addThreepid = new AddThreepid(MatrixClientPeg.get()); this.addThreepid.addEmailAddress(emailAddress).then( () => { Modal.createDialog(QuestionDialog, { diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index 4cc643c25e..22f13178b3 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -417,12 +417,12 @@ export default class MessageActionBar extends React.PureComponent Resend.resend(tarEv)); + this.runActionOnFailedEv((tarEv) => Resend.resend(MatrixClientPeg.get(), tarEv)); }; private onCancelClick = (ev: ButtonEvent): void => { this.runActionOnFailedEv( - (tarEv) => Resend.removeFromQueue(tarEv), + (tarEv) => Resend.removeFromQueue(MatrixClientPeg.get(), tarEv), (testEv) => canCancel(testEv.status), ); }; diff --git a/src/components/views/settings/account/EmailAddresses.tsx b/src/components/views/settings/account/EmailAddresses.tsx index 37d8697d47..f698b0b331 100644 --- a/src/components/views/settings/account/EmailAddresses.tsx +++ b/src/components/views/settings/account/EmailAddresses.tsx @@ -181,7 +181,7 @@ export default class EmailAddresses extends React.Component { return; } - const task = new AddThreepid(); + const task = new AddThreepid(MatrixClientPeg.get()); this.setState({ verifying: true, continueDisabled: true, addTask: task }); task.addEmailAddress(email) diff --git a/src/components/views/settings/account/PhoneNumbers.tsx b/src/components/views/settings/account/PhoneNumbers.tsx index 33225f1759..ece9549d94 100644 --- a/src/components/views/settings/account/PhoneNumbers.tsx +++ b/src/components/views/settings/account/PhoneNumbers.tsx @@ -182,7 +182,7 @@ export default class PhoneNumbers extends React.Component { const phoneNumber = this.state.newPhoneNumber; const phoneCountry = this.state.phoneCountry; - const task = new AddThreepid(); + const task = new AddThreepid(MatrixClientPeg.get()); this.setState({ verifying: true, continueDisabled: true, addTask: task }); task.addMsisdn(phoneCountry, phoneNumber) diff --git a/src/components/views/settings/discovery/EmailAddresses.tsx b/src/components/views/settings/discovery/EmailAddresses.tsx index c848b1722c..1d1cac2d67 100644 --- a/src/components/views/settings/discovery/EmailAddresses.tsx +++ b/src/components/views/settings/discovery/EmailAddresses.tsx @@ -86,7 +86,7 @@ export class EmailAddress extends React.Component { const { medium, address } = this.props.email; - const task = new AddThreepid(); + const task = new AddThreepid(MatrixClientPeg.get()); this.setState({ verifying: true, continueDisabled: true, diff --git a/src/components/views/settings/discovery/PhoneNumbers.tsx b/src/components/views/settings/discovery/PhoneNumbers.tsx index 408573790a..69955e2e48 100644 --- a/src/components/views/settings/discovery/PhoneNumbers.tsx +++ b/src/components/views/settings/discovery/PhoneNumbers.tsx @@ -82,7 +82,7 @@ export class PhoneNumber extends React.Component { const { medium, address } = this.props.msisdn; - const task = new AddThreepid(); + const task = new AddThreepid(MatrixClientPeg.get()); this.setState({ verifying: true, continueDisabled: true, diff --git a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx index 97135c5804..e4ffd3ae5e 100644 --- a/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx +++ b/src/components/views/settings/tabs/room/SecurityRoomSettingsTab.tsx @@ -215,7 +215,7 @@ export default class SecurityRoomSettingsTab extends React.Component void; @@ -46,6 +47,9 @@ interface IState { } export default class HelpUserSettingsTab extends React.Component { + public static contextType = MatrixClientContext; + public context!: React.ContextType; + public constructor(props: IProps) { super(props); @@ -104,7 +108,7 @@ export default class HelpUserSettingsTab extends React.Component private onStartBotChat = (): void => { this.props.closeSettingsFn(); - createRoom({ + createRoom(this.context, { dmUserId: SdkConfig.get("welcome_user_id"), andView: true, }); diff --git a/src/components/views/spaces/SpaceCreateMenu.tsx b/src/components/views/spaces/SpaceCreateMenu.tsx index ded069778d..a6a4b1ba69 100644 --- a/src/components/views/spaces/SpaceCreateMenu.tsx +++ b/src/components/views/spaces/SpaceCreateMenu.tsx @@ -30,12 +30,13 @@ import { RoomType } from "matrix-js-sdk/src/@types/event"; import { ICreateRoomOpts } from "matrix-js-sdk/src/@types/requests"; import { HistoryVisibility, Preset, Visibility } from "matrix-js-sdk/src/@types/partials"; import { logger } from "matrix-js-sdk/src/logger"; +import { MatrixClient } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import AccessibleTooltipButton from "../elements/AccessibleTooltipButton"; import ContextMenu, { ChevronFace } from "../../structures/ContextMenu"; import createRoom, { IOpts as ICreateOpts } from "../../../createRoom"; -import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import MatrixClientContext, { useMatrixClientContext } from "../../../contexts/MatrixClientContext"; import SpaceBasicSettings, { SpaceAvatar } from "./SpaceBasicSettings"; import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; import Field from "../elements/Field"; @@ -43,8 +44,9 @@ import withValidation from "../elements/Validation"; import RoomAliasField from "../elements/RoomAliasField"; import { getKeyBindingsManager } from "../../../KeyBindingsManager"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; -import { MatrixClientPeg } from "../../../MatrixClientPeg"; + export const createSpace = async ( + client: MatrixClient, name: string, isPublic: boolean, alias?: string, @@ -53,12 +55,12 @@ export const createSpace = async ( createOpts: Partial = {}, otherOpts: Partial> = {}, ): Promise => { - return createRoom({ + return createRoom(client, { createOpts: { name, preset: isPublic ? Preset.PublicChat : Preset.PrivateChat, visibility: - isPublic && (await MatrixClientPeg.get().doesServerSupportUnstableFeature("org.matrix.msc3827.stable")) + isPublic && (await client.doesServerSupportUnstableFeature("org.matrix.msc3827.stable")) ? Visibility.Public : Visibility.Private, power_level_content_override: { @@ -208,6 +210,7 @@ export const SpaceCreateForm: React.FC = ({ const SpaceCreateMenu: React.FC<{ onFinished(): void; }> = ({ onFinished }) => { + const cli = useMatrixClientContext(); const [visibility, setVisibility] = useState(null); const [busy, setBusy] = useState(false); @@ -243,7 +246,7 @@ const SpaceCreateMenu: React.FC<{ } try { - await createSpace(name, visibility === Visibility.Public, alias, topic, avatar); + await createSpace(cli, name, visibility === Visibility.Public, alias, topic, avatar); onFinished(); } catch (e) { diff --git a/src/createRoom.ts b/src/createRoom.ts index 1001b262aa..16ca1593ad 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -28,7 +28,6 @@ import { } from "matrix-js-sdk/src/@types/partials"; import { logger } from "matrix-js-sdk/src/logger"; -import { MatrixClientPeg } from "./MatrixClientPeg"; import Modal, { IHandle } from "./Modal"; import { _t, UserFriendlyError } from "./languageHandler"; import dis from "./dispatcher/dispatcher"; @@ -82,6 +81,7 @@ const DEFAULT_EVENT_POWER_LEVELS = { /** * Create a new room, and switch to it. * + * @param client The Matrix Client instance to create the room with * @param {object=} opts parameters for creating the room * @param {string=} opts.dmUserId If specified, make this a DM room for this user and invite them * @param {object=} opts.createOpts set of options to pass to createRoom call. @@ -98,13 +98,12 @@ const DEFAULT_EVENT_POWER_LEVELS = { * @returns {Promise} which resolves to the room id, or null if the * action was aborted or failed. */ -export default async function createRoom(opts: IOpts): Promise { +export default async function createRoom(client: MatrixClient, opts: IOpts): Promise { opts = opts || {}; if (opts.spinner === undefined) opts.spinner = true; if (opts.guestAccess === undefined) opts.guestAccess = true; if (opts.encryption === undefined) opts.encryption = false; - const client = MatrixClientPeg.get(); if (client.isGuest()) { dis.dispatch({ action: "require_registration" }); return null; @@ -122,7 +121,7 @@ export default async function createRoom(opts: IOpts): Promise { createOpts.invite = [opts.dmUserId]; break; case "email": { - const isUrl = MatrixClientPeg.get().getIdentityServerUrl(true); + const isUrl = client.getIdentityServerUrl(true); if (!isUrl) { throw new UserFriendlyError( "Cannot invite user by email without an identity server. " + @@ -162,7 +161,7 @@ export default async function createRoom(opts: IOpts): Promise { }, users: { // Temporarily give ourselves the power to set up a widget - [client.getUserId()!]: 200, + [client.getSafeUserId()]: 200, }, }; } else if (opts.roomType === RoomType.UnstableCall) { @@ -176,7 +175,7 @@ export default async function createRoom(opts: IOpts): Promise { }, users: { // Temporarily give ourselves the power to set up a call - [client.getUserId()!]: 200, + [client.getSafeUserId()]: 200, }, }; } @@ -438,7 +437,7 @@ export async function ensureVirtualRoomExists( if (existingDMRoom) { roomId = existingDMRoom.roomId; } else { - roomId = await createRoom({ + roomId = await createRoom(client, { dmUserId: userId, spinner: false, andView: false, @@ -466,7 +465,7 @@ export async function ensureDMExists(client: MatrixClient, userId: string): Prom encryption = await canEncryptToAllUsers(client, [userId]); } - roomId = await createRoom({ encryption, dmUserId: userId, spinner: false, andView: false }); + roomId = await createRoom(client, { encryption, dmUserId: userId, spinner: false, andView: false }); if (!roomId) return null; await waitForMember(client, roomId, userId); } diff --git a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts index b6ee070c03..e0b7d4bd20 100644 --- a/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts +++ b/src/stores/room-list/algorithms/tag-sorting/RecentAlgorithm.ts @@ -95,7 +95,10 @@ const getLastTs = (r: Room, userId: string): number => { const ev = r.timeline[i]; if (!ev.getTs()) continue; // skip events that don't have timestamps (tests only?) - if ((ev.getSender() === userId && shouldCauseReorder(ev)) || Unread.eventTriggersUnreadCount(ev)) { + if ( + (ev.getSender() === userId && shouldCauseReorder(ev)) || + Unread.eventTriggersUnreadCount(r.client, ev) + ) { return ev.getTs(); } } diff --git a/src/utils/dm/startDm.ts b/src/utils/dm/startDm.ts index 782785bf62..f3731e117d 100644 --- a/src/utils/dm/startDm.ts +++ b/src/utils/dm/startDm.ts @@ -90,5 +90,5 @@ export async function startDm(client: MatrixClient, targets: Member[], showSpinn } createRoomOptions.spinner = showSpinner; - return createRoom(createRoomOptions); + return createRoom(client, createRoomOptions); } diff --git a/src/utils/space.tsx b/src/utils/space.tsx index fa480f6209..c2cc915507 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -82,7 +82,7 @@ export const showCreateNewRoom = async (space: Room, type?: RoomType): Promise { }); it("returns false when the event was sent by the current user", () => { - expect(eventTriggersUnreadCount(ourMessage)).toBe(false); + expect(eventTriggersUnreadCount(client, ourMessage)).toBe(false); // returned early before checking renderer expect(haveRendererForEvent).not.toHaveBeenCalled(); }); it("returns false for a redacted event", () => { - expect(eventTriggersUnreadCount(redactedEvent)).toBe(false); + expect(eventTriggersUnreadCount(client, redactedEvent)).toBe(false); // returned early before checking renderer expect(haveRendererForEvent).not.toHaveBeenCalled(); }); it("returns false for an event without a renderer", () => { mocked(haveRendererForEvent).mockReturnValue(false); - expect(eventTriggersUnreadCount(alicesMessage)).toBe(false); + expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(false); expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, false); }); it("returns true for an event with a renderer", () => { mocked(haveRendererForEvent).mockReturnValue(true); - expect(eventTriggersUnreadCount(alicesMessage)).toBe(true); + expect(eventTriggersUnreadCount(client, alicesMessage)).toBe(true); expect(haveRendererForEvent).toHaveBeenCalledWith(alicesMessage, false); }); it("returns false for beacon locations", () => { const beaconLocationEvent = makeBeaconEvent(aliceId); - expect(eventTriggersUnreadCount(beaconLocationEvent)).toBe(false); + expect(eventTriggersUnreadCount(client, beaconLocationEvent)).toBe(false); expect(haveRendererForEvent).not.toHaveBeenCalled(); }); @@ -112,7 +112,7 @@ describe("Unread", () => { type: eventType, sender: aliceId, }); - expect(eventTriggersUnreadCount(event)).toBe(false); + expect(eventTriggersUnreadCount(client, event)).toBe(false); expect(haveRendererForEvent).not.toHaveBeenCalled(); }, ); diff --git a/test/createRoom-test.ts b/test/createRoom-test.ts index a9387bfcdf..21ff75c5ca 100644 --- a/test/createRoom-test.ts +++ b/test/createRoom-test.ts @@ -43,7 +43,7 @@ describe("createRoom", () => { const createCallSpy = jest.spyOn(JitsiCall, "create"); const userId = client.getUserId()!; - const roomId = await createRoom({ roomType: RoomType.ElementVideo }); + const roomId = await createRoom(client, { roomType: RoomType.ElementVideo }); const [ [ @@ -75,7 +75,7 @@ describe("createRoom", () => { it("sets up Element video rooms correctly", async () => { const userId = client.getUserId()!; const createCallSpy = jest.spyOn(ElementCall, "create"); - const roomId = await createRoom({ roomType: RoomType.UnstableCall }); + const roomId = await createRoom(client, { roomType: RoomType.UnstableCall }); const userPower = client.createRoom.mock.calls[0][0].power_level_content_override?.users?.[userId]; const callPower = @@ -102,7 +102,7 @@ describe("createRoom", () => { const createJitsiCallSpy = jest.spyOn(JitsiCall, "create"); const createElementCallSpy = jest.spyOn(ElementCall, "create"); - await createRoom({}); + await createRoom(client, {}); expect(createJitsiCallSpy).not.toHaveBeenCalled(); expect(createElementCallSpy).not.toHaveBeenCalled(); @@ -113,7 +113,7 @@ describe("createRoom", () => { if (name === "feature_group_calls") return true; }); - await createRoom({}); + await createRoom(client, {}); const callPower = client.createRoom.mock.calls[0][0].power_level_content_override?.events?.[ElementCall.CALL_EVENT_TYPE.name]; @@ -129,7 +129,7 @@ describe("createRoom", () => { it("should upload avatar if one is passed", async () => { client.uploadContent.mockResolvedValue({ content_uri: "mxc://foobar" }); const avatar = new File([], "avatar.png"); - await createRoom({ avatar }); + await createRoom(client, { avatar }); expect(client.createRoom).toHaveBeenCalledWith( expect.objectContaining({ initial_state: expect.arrayContaining([