Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 6b46d6e

Browse files
authored
Add MatrixClientPeg::safeGet and use it in tests (#10985)
1 parent c47b587 commit 6b46d6e

File tree

88 files changed

+290
-226
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+290
-226
lines changed

src/MatrixClientPeg.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } fro
3838
import SecurityCustomisations from "./customisations/Security";
3939
import { SlidingSyncManager } from "./SlidingSyncManager";
4040
import CryptoStoreTooNewDialog from "./components/views/dialogs/CryptoStoreTooNewDialog";
41-
import { _t } from "./languageHandler";
41+
import { _t, UserFriendlyError } from "./languageHandler";
4242
import { SettingLevel } from "./settings/SettingLevel";
4343
import MatrixClientBackedController from "./settings/controllers/MatrixClientBackedController";
4444
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
@@ -49,7 +49,7 @@ export interface IMatrixClientCreds {
4949
identityServerUrl?: string;
5050
userId: string;
5151
deviceId?: string;
52-
accessToken: string;
52+
accessToken?: string;
5353
guest?: boolean;
5454
pickleKey?: string;
5555
freshLogin?: boolean;
@@ -71,9 +71,10 @@ export interface IMatrixClientPeg {
7171
*
7272
* @returns {string} The homeserver name, if present.
7373
*/
74-
getHomeserverName(): string;
74+
getHomeserverName(): string | null;
7575

7676
get(): MatrixClient;
77+
safeGet(): MatrixClient;
7778
unset(): void;
7879
assign(): Promise<any>;
7980
start(): Promise<any>;
@@ -134,7 +135,7 @@ class MatrixClientPegClass implements IMatrixClientPeg {
134135
initialSyncLimit: 20,
135136
};
136137

137-
private matrixClient: MatrixClient = null;
138+
private matrixClient: MatrixClient | null = null;
138139
private justRegisteredUserId: string | null = null;
139140

140141
// the credentials used to init the current client object.
@@ -145,6 +146,13 @@ class MatrixClientPegClass implements IMatrixClientPeg {
145146
return this.matrixClient;
146147
}
147148

149+
public safeGet(): MatrixClient {
150+
if (!this.matrixClient) {
151+
throw new UserFriendlyError("User is not logged in");
152+
}
153+
return this.matrixClient;
154+
}
155+
148156
public unset(): void {
149157
this.matrixClient = null;
150158

@@ -215,6 +223,10 @@ class MatrixClientPegClass implements IMatrixClientPeg {
215223
};
216224

217225
public async assign(): Promise<any> {
226+
if (!this.matrixClient) {
227+
throw new Error("createClient must be called first");
228+
}
229+
218230
for (const dbType of ["indexeddb", "memory"]) {
219231
try {
220232
const promise = this.matrixClient.store.startup();
@@ -275,6 +287,10 @@ class MatrixClientPegClass implements IMatrixClientPeg {
275287
* Attempt to initialize the crypto layer on a newly-created MatrixClient
276288
*/
277289
private async initClientCrypto(): Promise<void> {
290+
if (!this.matrixClient) {
291+
throw new Error("createClient must be called first");
292+
}
293+
278294
const useRustCrypto = SettingsStore.getValue("feature_rust_crypto");
279295

280296
// we want to make sure that the same crypto implementation is used throughout the lifetime of a device,
@@ -317,11 +333,15 @@ class MatrixClientPegClass implements IMatrixClientPeg {
317333
const opts = await this.assign();
318334

319335
logger.log(`MatrixClientPeg: really starting MatrixClient`);
320-
await this.get().startClient(opts);
336+
await this.matrixClient!.startClient(opts);
321337
logger.log(`MatrixClientPeg: MatrixClient started`);
322338
}
323339

324340
public getCredentials(): IMatrixClientCreds {
341+
if (!this.matrixClient) {
342+
throw new Error("createClient must be called first");
343+
}
344+
325345
let copiedCredentials: IMatrixClientCreds | null = this.currentClientCreds;
326346
if (this.currentClientCreds?.userId !== this.matrixClient?.credentials?.userId) {
327347
// cached credentials belong to a different user - don't use them
@@ -335,12 +355,14 @@ class MatrixClientPegClass implements IMatrixClientPeg {
335355
identityServerUrl: this.matrixClient.idBaseUrl,
336356
userId: this.matrixClient.getSafeUserId(),
337357
deviceId: this.matrixClient.getDeviceId() ?? undefined,
338-
accessToken: this.matrixClient.getAccessToken(),
358+
accessToken: this.matrixClient.getAccessToken() ?? undefined,
339359
guest: this.matrixClient.isGuest(),
340360
};
341361
}
342362

343-
public getHomeserverName(): string {
363+
public getHomeserverName(): string | null {
364+
if (!this.matrixClient) return null;
365+
344366
const matches = /^@[^:]+:(.+)$/.exec(this.matrixClient.getSafeUserId());
345367
if (matches === null || matches.length < 1) {
346368
throw new Error("Failed to derive homeserver name from user ID!");

src/Notifier.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ const msgTypeHandlers: Record<string, (event: MatrixEvent) => string | null> = {
9191
return null;
9292
}
9393

94-
return TextForEvent.textForEvent(event);
94+
return TextForEvent.textForEvent(event, MatrixClientPeg.get());
9595
},
9696
};
9797

@@ -111,7 +111,7 @@ class NotifierClass {
111111
if (msgType && msgTypeHandlers.hasOwnProperty(msgType)) {
112112
return msgTypeHandlers[msgType](ev);
113113
}
114-
return TextForEvent.textForEvent(ev);
114+
return TextForEvent.textForEvent(ev, MatrixClientPeg.get());
115115
}
116116

117117
// XXX: exported for tests

src/TextForEvent.tsx

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@typ
2222
import { EventType, MsgType } from "matrix-js-sdk/src/@types/event";
2323
import { M_POLL_START, M_POLL_END } from "matrix-js-sdk/src/@types/polls";
2424
import { PollStartEvent } from "matrix-js-sdk/src/extensible_events_v1/PollStartEvent";
25+
import { MatrixClient } from "matrix-js-sdk/src/matrix";
2526

2627
import { _t } from "./languageHandler";
2728
import * as Roles from "./Roles";
@@ -31,7 +32,6 @@ import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } f
3132
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
3233
import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases";
3334
import defaultDispatcher from "./dispatcher/dispatcher";
34-
import { MatrixClientPeg } from "./MatrixClientPeg";
3535
import { RoomSettingsTab } from "./components/views/dialogs/RoomSettingsDialog";
3636
import AccessibleButton, { ButtonEvent } from "./components/views/elements/AccessibleButton";
3737
import RightPanelStore from "./stores/right-panel/RightPanelStore";
@@ -40,16 +40,15 @@ import { ElementCall } from "./models/Call";
4040
import { textForVoiceBroadcastStoppedEvent, VoiceBroadcastInfoEventType } from "./voice-broadcast";
4141
import { getSenderName } from "./utils/event/getSenderName";
4242

43-
function getRoomMemberDisplayname(event: MatrixEvent, userId = event.getSender()): string {
44-
const client = MatrixClientPeg.get();
43+
function getRoomMemberDisplayname(client: MatrixClient, event: MatrixEvent, userId = event.getSender()): string {
4544
const roomId = event.getRoomId();
4645
const member = client.getRoom(roomId)?.getMember(userId!);
4746
return member?.name || member?.rawDisplayName || userId || _t("Someone");
4847
}
4948

50-
function textForCallEvent(event: MatrixEvent): () => string {
51-
const roomName = MatrixClientPeg.get().getRoom(event.getRoomId()!)?.name;
52-
const isSupported = MatrixClientPeg.get().supportsVoip();
49+
function textForCallEvent(event: MatrixEvent, client: MatrixClient): () => string {
50+
const roomName = client.getRoom(event.getRoomId()!)?.name;
51+
const isSupported = client.supportsVoip();
5352

5453
return isSupported
5554
? () => _t("Video call started in %(roomName)s.", { roomName })
@@ -60,11 +59,11 @@ function textForCallEvent(event: MatrixEvent): () => string {
6059
// any text to display at all. For this reason they return deferred values
6160
// to avoid the expense of looking up translations when they're not needed.
6261

63-
function textForCallInviteEvent(event: MatrixEvent): (() => string) | null {
62+
function textForCallInviteEvent(event: MatrixEvent, client: MatrixClient): (() => string) | null {
6463
const senderName = getSenderName(event);
6564
// FIXME: Find a better way to determine this from the event?
6665
const isVoice = !event.getContent().offer?.sdp?.includes("m=video");
67-
const isSupported = MatrixClientPeg.get().supportsVoip();
66+
const isSupported = client.supportsVoip();
6867

6968
// This ladder could be reduced down to a couple string variables, however other languages
7069
// can have a hard time translating those strings. In an effort to make translations easier
@@ -103,10 +102,15 @@ function getModification(prev?: string, value?: string): Modification {
103102
return Modification.None;
104103
}
105104

106-
function textForMemberEvent(ev: MatrixEvent, allowJSX: boolean, showHiddenEvents?: boolean): (() => string) | null {
105+
function textForMemberEvent(
106+
ev: MatrixEvent,
107+
client: MatrixClient,
108+
allowJSX: boolean,
109+
showHiddenEvents?: boolean,
110+
): (() => string) | null {
107111
// XXX: SYJS-16 "sender is sometimes null for join messages"
108-
const senderName = ev.sender?.name || getRoomMemberDisplayname(ev);
109-
const targetName = ev.target?.name || getRoomMemberDisplayname(ev, ev.getStateKey());
112+
const senderName = ev.sender?.name || getRoomMemberDisplayname(client, ev);
113+
const targetName = ev.target?.name || getRoomMemberDisplayname(client, ev, ev.getStateKey());
110114
const prevContent = ev.getPrevContent();
111115
const content = ev.getContent();
112116
const reason = content.reason;
@@ -269,7 +273,7 @@ const onViewJoinRuleSettingsClick = (): void => {
269273
});
270274
};
271275

272-
function textForJoinRulesEvent(ev: MatrixEvent, allowJSX: boolean): () => Renderable {
276+
function textForJoinRulesEvent(ev: MatrixEvent, client: MatrixClient, allowJSX: boolean): () => Renderable {
273277
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
274278
switch (ev.getContent().join_rule) {
275279
case JoinRule.Public:
@@ -361,7 +365,7 @@ function textForServerACLEvent(ev: MatrixEvent): (() => string) | null {
361365
return getText;
362366
}
363367

364-
function textForMessageEvent(ev: MatrixEvent): (() => string) | null {
368+
function textForMessageEvent(ev: MatrixEvent, client: MatrixClient): (() => string) | null {
365369
if (isLocationEvent(ev)) {
366370
return textForLocationEvent(ev);
367371
}
@@ -370,7 +374,7 @@ function textForMessageEvent(ev: MatrixEvent): (() => string) | null {
370374
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
371375
let message = ev.getContent().body;
372376
if (ev.isRedacted()) {
373-
message = textForRedactedPollAndMessageEvent(ev);
377+
message = textForRedactedPollAndMessageEvent(ev, client);
374378
}
375379

376380
if (ev.getContent().msgtype === MsgType.Emote) {
@@ -496,7 +500,7 @@ function textForHistoryVisibilityEvent(event: MatrixEvent): (() => string) | nul
496500
}
497501

498502
// Currently will only display a change if a user's power level is changed
499-
function textForPowerEvent(event: MatrixEvent): (() => string) | null {
503+
function textForPowerEvent(event: MatrixEvent, client: MatrixClient): (() => string) | null {
500504
const senderName = getSenderName(event);
501505
if (!event.getPrevContent()?.users || !event.getContent()?.users) {
502506
return null;
@@ -533,7 +537,7 @@ function textForPowerEvent(event: MatrixEvent): (() => string) | null {
533537
return;
534538
}
535539
if (to !== from) {
536-
const name = getRoomMemberDisplayname(event, userId);
540+
const name = getRoomMemberDisplayname(client, event, userId);
537541
diffs.push({ userId, name, from, to });
538542
}
539543
});
@@ -561,7 +565,7 @@ const onPinnedMessagesClick = (): void => {
561565
RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false);
562566
};
563567

564-
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): (() => Renderable) | null {
568+
function textForPinnedEvent(event: MatrixEvent, client: MatrixClient, allowJSX: boolean): (() => Renderable) | null {
565569
if (!SettingsStore.getValue("feature_pinning")) return null;
566570
const senderName = getSenderName(event);
567571
const roomId = event.getRoomId()!;
@@ -835,12 +839,12 @@ export function textForLocationEvent(event: MatrixEvent): () => string {
835839
});
836840
}
837841

838-
function textForRedactedPollAndMessageEvent(ev: MatrixEvent): string {
842+
function textForRedactedPollAndMessageEvent(ev: MatrixEvent, client: MatrixClient): string {
839843
let message = _t("Message deleted");
840844
const unsigned = ev.getUnsigned();
841845
const redactedBecauseUserId = unsigned?.redacted_because?.sender;
842846
if (redactedBecauseUserId && redactedBecauseUserId !== ev.getSender()) {
843-
const room = MatrixClientPeg.get().getRoom(ev.getRoomId());
847+
const room = client.getRoom(ev.getRoomId());
844848
const sender = room?.getMember(redactedBecauseUserId);
845849
message = _t("Message deleted by %(name)s", {
846850
name: sender?.name || redactedBecauseUserId,
@@ -850,12 +854,12 @@ function textForRedactedPollAndMessageEvent(ev: MatrixEvent): string {
850854
return message;
851855
}
852856

853-
function textForPollStartEvent(event: MatrixEvent): (() => string) | null {
857+
function textForPollStartEvent(event: MatrixEvent, client: MatrixClient): (() => string) | null {
854858
return () => {
855859
let message = "";
856860

857861
if (event.isRedacted()) {
858-
message = textForRedactedPollAndMessageEvent(event);
862+
message = textForRedactedPollAndMessageEvent(event, client);
859863
const senderDisplayName = event.sender?.name ?? event.getSender();
860864
message = senderDisplayName + ": " + message;
861865
} else {
@@ -879,7 +883,12 @@ function textForPollEndEvent(event: MatrixEvent): (() => string) | null {
879883
type Renderable = string | React.ReactNode | null;
880884

881885
interface IHandlers {
882-
[type: string]: (ev: MatrixEvent, allowJSX: boolean, showHiddenEvents?: boolean) => (() => Renderable) | null;
886+
[type: string]: (
887+
ev: MatrixEvent,
888+
client: MatrixClient,
889+
allowJSX: boolean,
890+
showHiddenEvents?: boolean,
891+
) => (() => Renderable) | null;
883892
}
884893

885894
const handlers: IHandlers = {
@@ -925,25 +934,39 @@ for (const evType of ElementCall.CALL_EVENT_TYPE.names) {
925934

926935
/**
927936
* Determines whether the given event has text to display.
937+
*
938+
* @param client The Matrix Client instance for the logged-in user
928939
* @param ev The event
929940
* @param showHiddenEvents An optional cached setting value for showHiddenEventsInTimeline
930941
* to avoid hitting the settings store
931942
*/
932-
export function hasText(ev: MatrixEvent, showHiddenEvents?: boolean): boolean {
943+
export function hasText(ev: MatrixEvent, client: MatrixClient, showHiddenEvents?: boolean): boolean {
933944
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
934-
return Boolean(handler?.(ev, false, showHiddenEvents));
945+
return Boolean(handler?.(ev, client, false, showHiddenEvents));
935946
}
936947

937948
/**
938949
* Gets the textual content of the given event.
950+
*
939951
* @param ev The event
952+
* @param client The Matrix Client instance for the logged-in user
940953
* @param allowJSX Whether to output rich JSX content
941954
* @param showHiddenEvents An optional cached setting value for showHiddenEventsInTimeline
942955
* to avoid hitting the settings store
943956
*/
944-
export function textForEvent(ev: MatrixEvent): string;
945-
export function textForEvent(ev: MatrixEvent, allowJSX: true, showHiddenEvents?: boolean): string | React.ReactNode;
946-
export function textForEvent(ev: MatrixEvent, allowJSX = false, showHiddenEvents?: boolean): string | React.ReactNode {
957+
export function textForEvent(ev: MatrixEvent, client: MatrixClient): string;
958+
export function textForEvent(
959+
ev: MatrixEvent,
960+
client: MatrixClient,
961+
allowJSX: true,
962+
showHiddenEvents?: boolean,
963+
): string | React.ReactNode;
964+
export function textForEvent(
965+
ev: MatrixEvent,
966+
client: MatrixClient,
967+
allowJSX = false,
968+
showHiddenEvents?: boolean,
969+
): string | React.ReactNode {
947970
const handler = (ev.isState() ? stateHandlers : handlers)[ev.getType()];
948-
return handler?.(ev, allowJSX, showHiddenEvents)?.() || "";
971+
return handler?.(ev, client, allowJSX, showHiddenEvents)?.() || "";
949972
}

src/components/structures/MessagePanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ class MainGrouper extends BaseGrouper {
13011301
public add({ event: ev, shouldShow }: EventAndShouldShow): void {
13021302
if (ev.getType() === EventType.RoomMember) {
13031303
// We can ignore any events that don't actually have a message to display
1304-
if (!hasText(ev, this.panel.showHiddenEvents)) return;
1304+
if (!hasText(ev, MatrixClientPeg.get(), this.panel.showHiddenEvents)) return;
13051305
}
13061306
this.readMarker = this.readMarker || this.panel.readMarkerForEvent(ev.getId()!, ev === this.lastShownEvent);
13071307
if (!this.panel.showHiddenEvents && !shouldShow) {

src/components/views/messages/MPollEndBody.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { M_TEXT } from "matrix-js-sdk/src/@types/extensible_events";
2020
import { logger } from "matrix-js-sdk/src/logger";
2121

2222
import { Icon as PollIcon } from "../../../../res/img/element-icons/room/composer/poll.svg";
23-
import MatrixClientContext from "../../../contexts/MatrixClientContext";
23+
import MatrixClientContext, { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
2424
import { _t } from "../../../languageHandler";
2525
import { textForEvent } from "../../../TextForEvent";
2626
import { Caption } from "../typography/Caption";
@@ -95,10 +95,11 @@ const usePollStartEvent = (event: MatrixEvent): { pollStartEvent?: MatrixEvent;
9595
};
9696

9797
export const MPollEndBody = React.forwardRef<any, IBodyProps>(({ mxEvent, ...props }, ref) => {
98+
const cli = useMatrixClientContext();
9899
const { pollStartEvent, isLoadingPollStartEvent } = usePollStartEvent(mxEvent);
99100

100101
if (!pollStartEvent) {
101-
const pollEndFallbackMessage = M_TEXT.findIn(mxEvent.getContent()) || textForEvent(mxEvent);
102+
const pollEndFallbackMessage = M_TEXT.findIn(mxEvent.getContent()) || textForEvent(mxEvent, cli);
102103
return (
103104
<>
104105
<PollIcon className="mx_MPollEndBody_icon" />

src/components/views/messages/TextualEvent.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { MatrixEvent } from "matrix-js-sdk/src/models/event";
1919

2020
import RoomContext from "../../../contexts/RoomContext";
2121
import * as TextForEvent from "../../../TextForEvent";
22+
import { MatrixClientPeg } from "../../../MatrixClientPeg";
2223

2324
interface IProps {
2425
mxEvent: MatrixEvent;
@@ -28,7 +29,12 @@ export default class TextualEvent extends React.Component<IProps> {
2829
public static contextType = RoomContext;
2930

3031
public render(): React.ReactNode {
31-
const text = TextForEvent.textForEvent(this.props.mxEvent, true, this.context?.showHiddenEvents);
32+
const text = TextForEvent.textForEvent(
33+
this.props.mxEvent,
34+
MatrixClientPeg.get(),
35+
true,
36+
this.context?.showHiddenEvents,
37+
);
3238
if (!text) return null;
3339
return <div className="mx_TextualEvent">{text}</div>;
3440
}

0 commit comments

Comments
 (0)