1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-23 17:02:25 +03:00

Convert several internal maps to real maps

This commit is contained in:
Travis Ralston
2022-08-29 16:53:09 -06:00
parent 528e9343ae
commit 8716c1ab9b
10 changed files with 118 additions and 102 deletions

View File

@@ -32,8 +32,8 @@ import { ClientEvent, MatrixClient, RoomMember } from '../../../../src';
import { DeviceInfo, IDevice } from '../../../../src/crypto/deviceinfo';
import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning';
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
const ROOM_ID = '!ROOM:ID';

View File

@@ -34,7 +34,7 @@ import { IAbortablePromise, MatrixScheduler } from '../../../src';
const Olm = global.Olm;
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
const ROOM_ID = '!ROOM:ID';

View File

@@ -34,7 +34,7 @@ import { IRoomEncryption } from "../RoomList";
*
* @type {Object.<string, function(new: module:crypto/algorithms/base.EncryptionAlgorithm)>}
*/
export const ENCRYPTION_CLASSES: Record<string, new (params: IParams) => EncryptionAlgorithm> = {};
export const ENCRYPTION_CLASSES = new Map<string, new (params: IParams) => EncryptionAlgorithm>();
type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
@@ -44,7 +44,7 @@ type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
*
* @type {Object.<string, function(new: module:crypto/algorithms/base.DecryptionAlgorithm)>}
*/
export const DECRYPTION_CLASSES: Record<string, new (params: DecryptionClassParams) => DecryptionAlgorithm> = {};
export const DECRYPTION_CLASSES = new Map<string, new (params: DecryptionClassParams) => DecryptionAlgorithm>();
export interface IParams {
userId: string;
@@ -297,6 +297,6 @@ export function registerAlgorithm(
encryptor: new (params: IParams) => EncryptionAlgorithm,
decryptor: new (params: Omit<IParams, "deviceId">) => DecryptionAlgorithm,
): void {
ENCRYPTION_CLASSES[algorithm] = encryptor;
DECRYPTION_CLASSES[algorithm] = decryptor;
ENCRYPTION_CLASSES.set(algorithm, encryptor);
DECRYPTION_CLASSES.set(algorithm, decryptor);
}

View File

@@ -1191,7 +1191,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
class MegolmDecryption extends DecryptionAlgorithm {
// events which we couldn't decrypt due to unknown sessions / indexes: map from
// senderKey|sessionId to Set of MatrixEvents
private pendingEvents: Record<string, Map<string, Set<MatrixEvent>>> = {};
private pendingEvents = new Map<string, Map<string, Set<MatrixEvent>>>();
// this gets stubbed out by the unit tests.
private olmlib = olmlib;
@@ -1343,10 +1343,10 @@ class MegolmDecryption extends DecryptionAlgorithm {
const content = event.getWireContent();
const senderKey = content.sender_key;
const sessionId = content.session_id;
if (!this.pendingEvents[senderKey]) {
this.pendingEvents[senderKey] = new Map();
if (!this.pendingEvents.has(senderKey)) {
this.pendingEvents.set(senderKey, new Map<string, Set<MatrixEvent>>());
}
const senderPendingEvents = this.pendingEvents[senderKey];
const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents.has(sessionId)) {
senderPendingEvents.set(sessionId, new Set());
}
@@ -1364,7 +1364,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
const content = event.getWireContent();
const senderKey = content.sender_key;
const sessionId = content.session_id;
const senderPendingEvents = this.pendingEvents[senderKey];
const senderPendingEvents = this.pendingEvents.get(senderKey);
const pendingEvents = senderPendingEvents?.get(sessionId);
if (!pendingEvents) {
return;
@@ -1375,7 +1375,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
senderPendingEvents.delete(sessionId);
}
if (senderPendingEvents.size === 0) {
delete this.pendingEvents[senderKey];
this.pendingEvents.delete(senderKey);
}
}
@@ -1711,7 +1711,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
* @return {Boolean} whether all messages were successfully decrypted
*/
private async retryDecryption(senderKey: string, sessionId: string): Promise<boolean> {
const senderPendingEvents = this.pendingEvents[senderKey];
const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents) {
return true;
}
@@ -1732,16 +1732,16 @@ class MegolmDecryption extends DecryptionAlgorithm {
}));
// If decrypted successfully, they'll have been removed from pendingEvents
return !this.pendingEvents[senderKey]?.has(sessionId);
return !this.pendingEvents.get(senderKey)?.has(sessionId);
}
public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
const senderPendingEvents = this.pendingEvents[senderKey];
const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents) {
return true;
}
delete this.pendingEvents[senderKey];
this.pendingEvents.delete(senderKey);
await Promise.all([...senderPendingEvents].map(async ([_sessionId, pending]) => {
await Promise.all([...pending].map(async (ev) => {
@@ -1753,7 +1753,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
}));
}));
return !this.pendingEvents[senderKey];
return !this.pendingEvents.has(senderKey);
}
public async sendSharedHistoryInboundSessions(devicesByUser: Record<string, DeviceInfo[]>): Promise<void> {

View File

@@ -278,9 +278,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
private oneTimeKeyCheckInProgress = false;
// EncryptionAlgorithm instance for each room
private roomEncryptors: Record<string, EncryptionAlgorithm> = {};
private roomEncryptors = new Map<string, EncryptionAlgorithm>();
// map from algorithm to DecryptionAlgorithm instance, for each room
private roomDecryptors: Record<string, Record<string, DecryptionAlgorithm>> = {};
private roomDecryptors = new Map<string, Map<string, DecryptionAlgorithm>>();
private deviceKeys: Record<string, string> = {}; // type: key
@@ -422,7 +422,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
this.deviceList.on(CryptoEvent.UserCrossSigningUpdated, this.onDeviceListUserCrossSigningUpdated);
this.reEmitter.reEmit(this.deviceList, [CryptoEvent.DevicesUpdated, CryptoEvent.WillUpdateDevices]);
this.supportedAlgorithms = Object.keys(algorithms.DECRYPTION_CLASSES);
this.supportedAlgorithms = Array.from(algorithms.DECRYPTION_CLASSES.keys());
this.outgoingRoomKeyRequestManager = new OutgoingRoomKeyRequestManager(
baseApis, this.deviceId, this.cryptoStore,
@@ -2527,7 +2527,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
* This should not normally be necessary.
*/
public forceDiscardSession(roomId: string): void {
const alg = this.roomEncryptors[roomId];
const alg = this.roomEncryptors.get(roomId);
if (alg === undefined) throw new Error("Room not encrypted");
if (alg.forceDiscardSession === undefined) {
throw new Error("Room encryption algorithm doesn't support session discarding");
@@ -2580,7 +2580,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
// the encryption event would appear in both.
// If it's called more than twice though,
// it signals a bug on client or server.
const existingAlg = this.roomEncryptors[roomId];
const existingAlg = this.roomEncryptors.get(roomId);
if (existingAlg) {
return;
}
@@ -2594,7 +2594,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
storeConfigPromise = this.roomList.setRoomEncryption(roomId, config);
}
const AlgClass = algorithms.ENCRYPTION_CLASSES[config.algorithm];
const AlgClass = algorithms.ENCRYPTION_CLASSES.get(config.algorithm);
if (!AlgClass) {
throw new Error("Unable to encrypt with " + config.algorithm);
}
@@ -2608,7 +2608,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
roomId,
config,
});
this.roomEncryptors[roomId] = alg;
this.roomEncryptors.set(roomId, alg);
if (storeConfigPromise) {
await storeConfigPromise;
@@ -2640,7 +2640,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
public trackRoomDevices(roomId: string): Promise<void> {
const trackMembers = async () => {
// not an encrypted room
if (!this.roomEncryptors[roomId]) {
if (!this.roomEncryptors.has(roomId)) {
return;
}
const room = this.clientStore.getRoom(roomId);
@@ -2785,7 +2785,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
* @param {module:models/room} room the room the event is in
*/
public prepareToEncrypt(room: Room): void {
const alg = this.roomEncryptors[room.roomId];
const alg = this.roomEncryptors.get(room.roomId);
if (alg) {
alg.prepareToEncrypt(room);
}
@@ -2808,7 +2808,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
const roomId = event.getRoomId();
const alg = this.roomEncryptors[roomId];
const alg = this.roomEncryptors.get(roomId);
if (!alg) {
// MatrixClient has already checked that this room should be encrypted,
// so this is an unexpected situation.
@@ -3097,7 +3097,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
private getTrackedE2eRooms(): Room[] {
return this.clientStore.getRooms().filter((room) => {
// check for rooms with encryption enabled
const alg = this.roomEncryptors[room.roomId];
const alg = this.roomEncryptors.get(room.roomId);
if (!alg) {
return false;
}
@@ -3533,7 +3533,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
const roomId = member.roomId;
const alg = this.roomEncryptors[roomId];
const alg = this.roomEncryptors.get(roomId);
if (!alg) {
// not encrypting in this room
return;
@@ -3634,11 +3634,11 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
if (userId !== this.userId) {
if (!this.roomEncryptors[roomId]) {
if (!this.roomEncryptors.get(roomId)) {
logger.debug(`room key request for unencrypted room ${roomId}`);
return;
}
const encryptor = this.roomEncryptors[roomId];
const encryptor = this.roomEncryptors.get(roomId);
const device = this.deviceList.getStoredDevice(userId, deviceId);
if (!device) {
logger.debug(`Ignoring keyshare for unknown device ${userId}:${deviceId}`);
@@ -3674,12 +3674,12 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
// if we don't have a decryptor for this room/alg, we don't have
// the keys for the requested events, and can drop the requests.
if (!this.roomDecryptors[roomId]) {
if (!this.roomDecryptors.has(roomId)) {
logger.log(`room key request for unencrypted room ${roomId}`);
return;
}
const decryptor = this.roomDecryptors[roomId][alg];
const decryptor = this.roomDecryptors.get(roomId).get(alg);
if (!decryptor) {
logger.log(`room key request for unknown alg ${alg} in room ${roomId}`);
return;
@@ -3745,23 +3745,24 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
* unknown
*/
public getRoomDecryptor(roomId: string, algorithm: string): DecryptionAlgorithm {
let decryptors: Record<string, DecryptionAlgorithm>;
let decryptors: Map<string, DecryptionAlgorithm>;
let alg: DecryptionAlgorithm;
roomId = roomId || null;
if (roomId) {
decryptors = this.roomDecryptors[roomId];
decryptors = this.roomDecryptors.get(roomId);
if (!decryptors) {
this.roomDecryptors[roomId] = decryptors = {};
decryptors = new Map<string, DecryptionAlgorithm>();
this.roomDecryptors.set(roomId, decryptors);
}
alg = decryptors[algorithm];
alg = decryptors.get(algorithm);
if (alg) {
return alg;
}
}
const AlgClass = algorithms.DECRYPTION_CLASSES[algorithm];
const AlgClass = algorithms.DECRYPTION_CLASSES.get(algorithm);
if (!AlgClass) {
throw new algorithms.DecryptionError(
'UNKNOWN_ENCRYPTION_ALGORITHM',
@@ -3777,7 +3778,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
});
if (decryptors) {
decryptors[algorithm] = alg;
decryptors.set(algorithm, alg);
}
return alg;
}
@@ -3791,9 +3792,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
*/
private getRoomDecryptors(algorithm: string): DecryptionAlgorithm[] {
const decryptors = [];
for (const d of Object.values(this.roomDecryptors)) {
if (algorithm in d) {
decryptors.push(d[algorithm]);
for (const d of this.roomDecryptors.values()) {
if (d.has(algorithm)) {
decryptors.push(d.get(algorithm));
}
}
return decryptors;

View File

@@ -86,7 +86,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
private readonly displayPendingEvents: boolean;
private liveTimeline: EventTimeline;
private timelines: EventTimeline[];
private _eventIdToTimeline: Record<string, EventTimeline>;
private _eventIdToTimeline = new Map<string, EventTimeline>();
private filter?: Filter;
/**
@@ -138,7 +138,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
// just a list - *not* ordered.
this.timelines = [this.liveTimeline];
this._eventIdToTimeline = {};
this._eventIdToTimeline = new Map<string, EventTimeline>();
this.filter = opts.filter;
@@ -210,7 +210,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
* @return {module:models/event-timeline~EventTimeline} timeline
*/
public eventIdToTimeline(eventId: string): EventTimeline {
return this._eventIdToTimeline[eventId];
return this._eventIdToTimeline.get(eventId);
}
/**
@@ -220,10 +220,10 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
* @param {String} newEventId event ID of the replacement event
*/
public replaceEventId(oldEventId: string, newEventId: string): void {
const existingTimeline = this._eventIdToTimeline[oldEventId];
const existingTimeline = this._eventIdToTimeline.get(oldEventId);
if (existingTimeline) {
delete this._eventIdToTimeline[oldEventId];
this._eventIdToTimeline[newEventId] = existingTimeline;
this._eventIdToTimeline.delete(oldEventId);
this._eventIdToTimeline.set(newEventId, existingTimeline);
}
}
@@ -257,7 +257,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
if (resetAllTimelines) {
this.timelines = [newTimeline];
this._eventIdToTimeline = {};
this._eventIdToTimeline = new Map<string, EventTimeline>();
} else {
this.timelines.push(newTimeline);
}
@@ -288,7 +288,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
* the given event, or null if unknown
*/
public getTimelineForEvent(eventId: string): EventTimeline | null {
const res = this._eventIdToTimeline[eventId];
const res = this._eventIdToTimeline.get(eventId);
return (res === undefined) ? null : res;
}
@@ -450,7 +450,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
const event = events[i];
const eventId = event.getId();
const existingTimeline = this._eventIdToTimeline[eventId];
const existingTimeline = this._eventIdToTimeline.get(eventId);
if (!existingTimeline) {
// we don't know about this event yet. Just add it to the timeline.
@@ -601,7 +601,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
}
}
const timeline = this._eventIdToTimeline[event.getId()];
const timeline = this._eventIdToTimeline.get(event.getId());
if (timeline) {
if (duplicateStrategy === DuplicateStrategy.Replace) {
debuglog("EventTimelineSet.addLiveEvent: replacing duplicate event " + event.getId());
@@ -697,7 +697,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
roomState,
timelineWasEmpty,
});
this._eventIdToTimeline[eventId] = timeline;
this._eventIdToTimeline.set(eventId, timeline);
this.relations.aggregateParentEvent(event);
this.relations.aggregateChildEvent(event, this);
@@ -725,10 +725,10 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
newEventId: string,
): void {
// XXX: why don't we infer newEventId from localEvent?
const existingTimeline = this._eventIdToTimeline[oldEventId];
const existingTimeline = this._eventIdToTimeline.get(oldEventId);
if (existingTimeline) {
delete this._eventIdToTimeline[oldEventId];
this._eventIdToTimeline[newEventId] = existingTimeline;
this._eventIdToTimeline.delete(oldEventId);
this._eventIdToTimeline.set(newEventId, existingTimeline);
} else {
if (this.filter) {
if (this.filter.filterRoomTimeline([localEvent]).length) {
@@ -753,14 +753,14 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
* in this room.
*/
public removeEvent(eventId: string): MatrixEvent | null {
const timeline = this._eventIdToTimeline[eventId];
const timeline = this._eventIdToTimeline.get(eventId);
if (!timeline) {
return null;
}
const removed = timeline.removeEvent(eventId);
if (removed) {
delete this._eventIdToTimeline[eventId];
this._eventIdToTimeline.delete(eventId);
const data = {
timeline: timeline,
};
@@ -787,8 +787,8 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
return 0;
}
const timeline1 = this._eventIdToTimeline[eventId1];
const timeline2 = this._eventIdToTimeline[eventId2];
const timeline1 = this._eventIdToTimeline.get(eventId1);
const timeline2 = this._eventIdToTimeline.get(eventId2);
if (timeline1 === undefined) {
return null;

View File

@@ -26,7 +26,7 @@ import { logger } from '../logger';
import { VerificationRequest } from "../crypto/verification/request/VerificationRequest";
import { EVENT_VISIBILITY_CHANGE_TYPE, EventType, MsgType, RelationType } from "../@types/event";
import { Crypto, IEventDecryptionResult } from "../crypto";
import { deepSortedObjectEntries } from "../utils";
import { deepSortedObjectEntries, internaliseString } from "../utils";
import { RoomMember } from "./room-member";
import { Thread, ThreadEvent, EventHandlerMap as ThreadEventHandlerMap, THREAD_RELATION_TYPE } from "./thread";
import { IActionsObject } from '../pushprocessor';
@@ -37,14 +37,6 @@ import { EventStatus } from "./event-status";
export { EventStatus } from "./event-status";
const interns: Record<string, string> = {};
function intern(str: string): string {
if (!interns[str]) {
interns[str] = str;
}
return interns[str];
}
/* eslint-disable camelcase */
export interface IContent {
[key: string]: any;
@@ -326,17 +318,17 @@ export class MatrixEvent extends TypedEventEmitter<EmittedEvents, MatrixEventHan
// of space if we don't intern it.
["state_key", "type", "sender", "room_id", "membership"].forEach((prop) => {
if (typeof event[prop] !== "string") return;
event[prop] = intern(event[prop]);
event[prop] = internaliseString(event[prop]);
});
["membership", "avatar_url", "displayname"].forEach((prop) => {
if (typeof event.content?.[prop] !== "string") return;
event.content[prop] = intern(event.content[prop]);
event.content[prop] = internaliseString(event.content[prop]);
});
["rel_type"].forEach((prop) => {
if (typeof event.content?.["m.relates_to"]?.[prop] !== "string") return;
event.content["m.relates_to"][prop] = intern(event.content["m.relates_to"][prop]);
event.content["m.relates_to"][prop] = internaliseString(event.content["m.relates_to"][prop]);
});
this.txnId = event.txn_id || null;
@@ -796,6 +788,8 @@ export class MatrixEvent extends TypedEventEmitter<EmittedEvents, MatrixEventHan
// not a decryption error: log the whole exception as an error
// (and don't bother with a retry)
const re = options.isRetry ? 're' : '';
// For find results: this can produce "Error decrypting event (id=$ev)" and
// "Error redecrypting event (id=$ev)".
logger.error(
`Error ${re}decrypting event ` +
`(id=${this.getId()}): ${e.stack || e}`,

View File

@@ -23,14 +23,8 @@ import { Room } from "./room";
export class RelationsContainer {
// A tree of objects to access a set of related children for an event, as in:
// this.relations[parentEventId][relationType][relationEventType]
private relations: {
[parentEventId: string]: {
[relationType: RelationType | string]: {
[eventType: EventType | string]: Relations;
};
};
} = {};
// this.relations.get(parentEventId).get(relationType).get(relationEventType)
private relations = new Map<string, Map<RelationType | string, Map<EventType | string, Relations>>>();
constructor(private readonly client: MatrixClient, private readonly room?: Room) {
}
@@ -57,14 +51,15 @@ export class RelationsContainer {
relationType: RelationType | string,
eventType: EventType | string,
): Relations | undefined {
return this.relations[eventId]?.[relationType]?.[eventType];
return this.relations.get(eventId)?.get(relationType)?.get(eventType);
}
public getAllChildEventsForEvent(parentEventId: string): MatrixEvent[] {
const relationsForEvent = this.relations[parentEventId] ?? {};
const relationsForEvent = this.relations.get(parentEventId)
?? new Map<RelationType | string, Map<EventType | string, Relations>>();
const events: MatrixEvent[] = [];
for (const relationsRecord of Object.values(relationsForEvent)) {
for (const relations of Object.values(relationsRecord)) {
for (const relationsRecord of relationsForEvent.values()) {
for (const relations of relationsRecord.values()) {
events.push(...relations.getRelations());
}
}
@@ -79,11 +74,11 @@ export class RelationsContainer {
* @param {MatrixEvent} event The event to check as relation target.
*/
public aggregateParentEvent(event: MatrixEvent): void {
const relationsForEvent = this.relations[event.getId()];
const relationsForEvent = this.relations.get(event.getId());
if (!relationsForEvent) return;
for (const relationsWithRelType of Object.values(relationsForEvent)) {
for (const relationsWithEventType of Object.values(relationsWithRelType)) {
for (const relationsWithRelType of relationsForEvent.values()) {
for (const relationsWithEventType of relationsWithRelType.values()) {
relationsWithEventType.setTargetEvent(event);
}
}
@@ -123,23 +118,26 @@ export class RelationsContainer {
const { event_id: relatesToEventId, rel_type: relationType } = relation;
const eventType = event.getType();
let relationsForEvent = this.relations[relatesToEventId];
let relationsForEvent = this.relations.get(relatesToEventId);
if (!relationsForEvent) {
relationsForEvent = this.relations[relatesToEventId] = {};
relationsForEvent = new Map<RelationType | string, Map<EventType | string, Relations>>();
this.relations.set(relatesToEventId, relationsForEvent);
}
let relationsWithRelType = relationsForEvent[relationType];
let relationsWithRelType = relationsForEvent.get(relationType);
if (!relationsWithRelType) {
relationsWithRelType = relationsForEvent[relationType] = {};
relationsWithRelType = new Map<EventType | string, Relations>();
relationsForEvent.set(relationType, relationsWithRelType);
}
let relationsWithEventType = relationsWithRelType[eventType];
let relationsWithEventType = relationsWithRelType.get(eventType);
if (!relationsWithEventType) {
relationsWithEventType = relationsWithRelType[eventType] = new Relations(
relationsWithEventType = new Relations(
relationType,
eventType,
this.client,
);
relationsWithRelType.set(eventType, relationsWithEventType);
const room = this.room ?? timelineSet?.room;
const relatesToEvent = timelineSet?.findEventById(relatesToEventId)

View File

@@ -79,7 +79,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
public readonly reEmitter = new TypedReEmitter<EmittedEvents, EventHandlerMap>(this);
private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember
// stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys)
private displayNameToUserIds: Record<string, string[]> = {};
private displayNameToUserIds = new Map<string, string[]>();
private userIdsToDisplayNames: Record<string, string> = {};
private tokenToInvite: Record<string, MatrixEvent> = {}; // 3pid invite state_key to m.room.member invite
private joinedMemberCount: number = null; // cache of the number of joined members
@@ -709,7 +709,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
* @return {string[]} An array of user IDs or an empty array.
*/
public getUserIdsWithDisplayName(displayName: string): string[] {
return this.displayNameToUserIds[utils.removeHiddenChars(displayName)] || [];
return this.displayNameToUserIds.get(utils.removeHiddenChars(displayName)) ?? [];
}
/**
@@ -941,11 +941,11 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
// the lot.
const strippedOldName = utils.removeHiddenChars(oldName);
const existingUserIds = this.displayNameToUserIds[strippedOldName];
const existingUserIds = this.displayNameToUserIds.get(strippedOldName);
if (existingUserIds) {
// remove this user ID from this array
const filteredUserIDs = existingUserIds.filter((id) => id !== userId);
this.displayNameToUserIds[strippedOldName] = filteredUserIDs;
this.displayNameToUserIds.set(strippedOldName, filteredUserIDs);
}
}
@@ -954,10 +954,9 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
// an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
if (strippedDisplayname) {
if (!this.displayNameToUserIds[strippedDisplayname]) {
this.displayNameToUserIds[strippedDisplayname] = [];
}
this.displayNameToUserIds[strippedDisplayname].push(userId);
const arr = this.displayNameToUserIds.get(strippedDisplayname) ?? [];
arr.push(userId);
this.displayNameToUserIds.set(strippedDisplayname, arr);
}
}
}

View File

@@ -28,6 +28,30 @@ import { MatrixClient, MatrixEvent } from ".";
import { M_TIMESTAMP } from "./@types/location";
import { ReceiptType } from "./@types/read_receipts";
const interns = new Map<string, string>();
/**
* Internalises a string, reusing a known pointer or storing the pointer
* if needed for future strings.
* @param str The string to internalise.
* @returns The internalised string.
*/
export function internaliseString(str: string): string {
// Unwrap strings before entering the map, if we somehow got a wrapped
// string as our input. This should only happen from tests.
if ((str as unknown) instanceof String) {
str = str.toString();
}
// Check the map to see if we can store the value
if (!interns.has(str)) {
interns.set(str, str);
}
// Return any cached string reference
return interns.get(str);
}
/**
* Encode a dictionary of query parameters.
* Omits any undefined/null values.