Matrix: fetch aliases only when needed

This commit is contained in:
Gustavo Madeira Santana
2026-03-12 08:54:25 +00:00
parent 5e6a6bc6a0
commit 4686eef1e8
3 changed files with 39 additions and 22 deletions

View File

@@ -76,6 +76,7 @@ export type MatrixMonitorHandlerParams = {
};
getRoomInfo: (
roomId: string,
opts?: { includeAliases?: boolean },
) => Promise<{ name?: string; canonicalAlias?: string; altAliases: string[] }>;
getMemberDisplayName: (roomId: string, userId: string) => Promise<string>;
};
@@ -256,15 +257,6 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
selfUserId,
});
const isRoom = !isDirectMessage;
let roomInfoPromise: Promise<{
name?: string;
canonicalAlias?: string;
altAliases: string[];
}> | null = null;
const getResolvedRoomInfo = async () => {
roomInfoPromise ??= getRoomInfo(roomId);
return await roomInfoPromise;
};
if (isRoom && groupPolicy === "disabled") {
return;
@@ -272,7 +264,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
const roomInfoForConfig =
isRoom && roomsConfig && Object.keys(roomsConfig).some((key) => key.trim().startsWith("#"))
? await getResolvedRoomInfo()
? await getRoomInfo(roomId, { includeAliases: true })
: undefined;
const roomAliasesForConfig = roomInfoForConfig
? [roomInfoForConfig.canonicalAlias ?? "", ...roomInfoForConfig.altAliases].filter(Boolean)
@@ -560,7 +552,7 @@ export function createMatrixRoomMessageHandler(params: MatrixMonitorHandlerParam
return;
}
const senderName = await getSenderName();
const roomInfo = isRoom ? await getResolvedRoomInfo() : undefined;
const roomInfo = isRoom ? await getRoomInfo(roomId) : undefined;
const roomName = roomInfo?.name;
const messageId = event.event_id ?? "";

View File

@@ -31,12 +31,14 @@ function createClientStub() {
}
describe("createMatrixRoomInfoResolver", () => {
it("caches room info and member display names", async () => {
it("caches room names and member display names, and loads aliases only on demand", async () => {
const client = createClientStub();
const resolver = createMatrixRoomInfoResolver(client);
await resolver.getRoomInfo("!room:example.org");
await resolver.getRoomInfo("!room:example.org");
await resolver.getRoomInfo("!room:example.org", { includeAliases: true });
await resolver.getRoomInfo("!room:example.org", { includeAliases: true });
await resolver.getMemberDisplayName("!room:example.org", "@alice:example.org");
await resolver.getMemberDisplayName("!room:example.org", "@alice:example.org");
@@ -57,6 +59,6 @@ describe("createMatrixRoomInfoResolver", () => {
}
await resolver.getMemberDisplayName("!room:example.org", "@user-0:example.org");
expect(client.getRoomStateEvent).toHaveBeenCalledTimes(6150);
expect(client.getRoomStateEvent).toHaveBeenCalledTimes(5124);
});
});

View File

@@ -20,17 +20,15 @@ function rememberBounded<T>(map: Map<string, T>, key: string, value: T, maxEntri
}
export function createMatrixRoomInfoResolver(client: MatrixClient) {
const roomInfoCache = new Map<string, MatrixRoomInfo>();
const roomNameCache = new Map<string, string | undefined>();
const roomAliasCache = new Map<string, Pick<MatrixRoomInfo, "canonicalAlias" | "altAliases">>();
const memberDisplayNameCache = new Map<string, string>();
const getRoomInfo = async (roomId: string): Promise<MatrixRoomInfo> => {
const cached = roomInfoCache.get(roomId);
if (cached) {
return cached;
const getRoomName = async (roomId: string): Promise<string | undefined> => {
if (roomNameCache.has(roomId)) {
return roomNameCache.get(roomId);
}
let name: string | undefined;
let canonicalAlias: string | undefined;
let altAliases: string[] = [];
try {
const nameState = await client.getRoomStateEvent(roomId, "m.room.name", "").catch(() => null);
if (nameState && typeof nameState.name === "string") {
@@ -39,6 +37,19 @@ export function createMatrixRoomInfoResolver(client: MatrixClient) {
} catch {
// ignore
}
rememberBounded(roomNameCache, roomId, name, MAX_TRACKED_ROOM_INFO);
return name;
};
const getRoomAliases = async (
roomId: string,
): Promise<Pick<MatrixRoomInfo, "canonicalAlias" | "altAliases">> => {
const cached = roomAliasCache.get(roomId);
if (cached) {
return cached;
}
let canonicalAlias: string | undefined;
let altAliases: string[] = [];
try {
const aliasState = await client
.getRoomStateEvent(roomId, "m.room.canonical_alias", "")
@@ -53,11 +64,23 @@ export function createMatrixRoomInfoResolver(client: MatrixClient) {
} catch {
// ignore
}
const info = { name, canonicalAlias, altAliases };
rememberBounded(roomInfoCache, roomId, info, MAX_TRACKED_ROOM_INFO);
const info = { canonicalAlias, altAliases };
rememberBounded(roomAliasCache, roomId, info, MAX_TRACKED_ROOM_INFO);
return info;
};
const getRoomInfo = async (
roomId: string,
opts: { includeAliases?: boolean } = {},
): Promise<MatrixRoomInfo> => {
const name = await getRoomName(roomId);
if (!opts.includeAliases) {
return { name, altAliases: [] };
}
const aliases = await getRoomAliases(roomId);
return { name, ...aliases };
};
const getMemberDisplayName = async (roomId: string, userId: string): Promise<string> => {
const cacheKey = `${roomId}:${userId}`;
const cached = memberDisplayNameCache.get(cacheKey);