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 { DeviceInfo, IDevice } from '../../../../src/crypto/deviceinfo';
import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning'; import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning';
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2']; const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES['m.megolm.v1.aes-sha2']; const MegolmEncryption = algorithms.ENCRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
const ROOM_ID = '!ROOM:ID'; const ROOM_ID = '!ROOM:ID';

View File

@@ -34,7 +34,7 @@ import { IAbortablePromise, MatrixScheduler } from '../../../src';
const Olm = global.Olm; 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'; 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)>} * @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">; 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)>} * @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 { export interface IParams {
userId: string; userId: string;
@@ -297,6 +297,6 @@ export function registerAlgorithm(
encryptor: new (params: IParams) => EncryptionAlgorithm, encryptor: new (params: IParams) => EncryptionAlgorithm,
decryptor: new (params: Omit<IParams, "deviceId">) => DecryptionAlgorithm, decryptor: new (params: Omit<IParams, "deviceId">) => DecryptionAlgorithm,
): void { ): void {
ENCRYPTION_CLASSES[algorithm] = encryptor; ENCRYPTION_CLASSES.set(algorithm, encryptor);
DECRYPTION_CLASSES[algorithm] = decryptor; DECRYPTION_CLASSES.set(algorithm, decryptor);
} }

View File

@@ -1191,7 +1191,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
class MegolmDecryption extends DecryptionAlgorithm { class MegolmDecryption extends DecryptionAlgorithm {
// events which we couldn't decrypt due to unknown sessions / indexes: map from // events which we couldn't decrypt due to unknown sessions / indexes: map from
// senderKey|sessionId to Set of MatrixEvents // 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. // this gets stubbed out by the unit tests.
private olmlib = olmlib; private olmlib = olmlib;
@@ -1343,10 +1343,10 @@ class MegolmDecryption extends DecryptionAlgorithm {
const content = event.getWireContent(); const content = event.getWireContent();
const senderKey = content.sender_key; const senderKey = content.sender_key;
const sessionId = content.session_id; const sessionId = content.session_id;
if (!this.pendingEvents[senderKey]) { if (!this.pendingEvents.has(senderKey)) {
this.pendingEvents[senderKey] = new Map(); this.pendingEvents.set(senderKey, new Map<string, Set<MatrixEvent>>());
} }
const senderPendingEvents = this.pendingEvents[senderKey]; const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents.has(sessionId)) { if (!senderPendingEvents.has(sessionId)) {
senderPendingEvents.set(sessionId, new Set()); senderPendingEvents.set(sessionId, new Set());
} }
@@ -1364,7 +1364,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
const content = event.getWireContent(); const content = event.getWireContent();
const senderKey = content.sender_key; const senderKey = content.sender_key;
const sessionId = content.session_id; const sessionId = content.session_id;
const senderPendingEvents = this.pendingEvents[senderKey]; const senderPendingEvents = this.pendingEvents.get(senderKey);
const pendingEvents = senderPendingEvents?.get(sessionId); const pendingEvents = senderPendingEvents?.get(sessionId);
if (!pendingEvents) { if (!pendingEvents) {
return; return;
@@ -1375,7 +1375,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
senderPendingEvents.delete(sessionId); senderPendingEvents.delete(sessionId);
} }
if (senderPendingEvents.size === 0) { 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 * @return {Boolean} whether all messages were successfully decrypted
*/ */
private async retryDecryption(senderKey: string, sessionId: string): Promise<boolean> { private async retryDecryption(senderKey: string, sessionId: string): Promise<boolean> {
const senderPendingEvents = this.pendingEvents[senderKey]; const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents) { if (!senderPendingEvents) {
return true; return true;
} }
@@ -1732,16 +1732,16 @@ class MegolmDecryption extends DecryptionAlgorithm {
})); }));
// If decrypted successfully, they'll have been removed from pendingEvents // 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> { public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
const senderPendingEvents = this.pendingEvents[senderKey]; const senderPendingEvents = this.pendingEvents.get(senderKey);
if (!senderPendingEvents) { if (!senderPendingEvents) {
return true; return true;
} }
delete this.pendingEvents[senderKey]; this.pendingEvents.delete(senderKey);
await Promise.all([...senderPendingEvents].map(async ([_sessionId, pending]) => { await Promise.all([...senderPendingEvents].map(async ([_sessionId, pending]) => {
await Promise.all([...pending].map(async (ev) => { 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> { 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; private oneTimeKeyCheckInProgress = false;
// EncryptionAlgorithm instance for each room // 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 // 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 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.deviceList.on(CryptoEvent.UserCrossSigningUpdated, this.onDeviceListUserCrossSigningUpdated);
this.reEmitter.reEmit(this.deviceList, [CryptoEvent.DevicesUpdated, CryptoEvent.WillUpdateDevices]); 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( this.outgoingRoomKeyRequestManager = new OutgoingRoomKeyRequestManager(
baseApis, this.deviceId, this.cryptoStore, baseApis, this.deviceId, this.cryptoStore,
@@ -2527,7 +2527,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
* This should not normally be necessary. * This should not normally be necessary.
*/ */
public forceDiscardSession(roomId: string): void { 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 === undefined) throw new Error("Room not encrypted");
if (alg.forceDiscardSession === undefined) { if (alg.forceDiscardSession === undefined) {
throw new Error("Room encryption algorithm doesn't support session discarding"); 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. // the encryption event would appear in both.
// If it's called more than twice though, // If it's called more than twice though,
// it signals a bug on client or server. // it signals a bug on client or server.
const existingAlg = this.roomEncryptors[roomId]; const existingAlg = this.roomEncryptors.get(roomId);
if (existingAlg) { if (existingAlg) {
return; return;
} }
@@ -2594,7 +2594,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
storeConfigPromise = this.roomList.setRoomEncryption(roomId, config); storeConfigPromise = this.roomList.setRoomEncryption(roomId, config);
} }
const AlgClass = algorithms.ENCRYPTION_CLASSES[config.algorithm]; const AlgClass = algorithms.ENCRYPTION_CLASSES.get(config.algorithm);
if (!AlgClass) { if (!AlgClass) {
throw new Error("Unable to encrypt with " + config.algorithm); throw new Error("Unable to encrypt with " + config.algorithm);
} }
@@ -2608,7 +2608,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
roomId, roomId,
config, config,
}); });
this.roomEncryptors[roomId] = alg; this.roomEncryptors.set(roomId, alg);
if (storeConfigPromise) { if (storeConfigPromise) {
await storeConfigPromise; await storeConfigPromise;
@@ -2640,7 +2640,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
public trackRoomDevices(roomId: string): Promise<void> { public trackRoomDevices(roomId: string): Promise<void> {
const trackMembers = async () => { const trackMembers = async () => {
// not an encrypted room // not an encrypted room
if (!this.roomEncryptors[roomId]) { if (!this.roomEncryptors.has(roomId)) {
return; return;
} }
const room = this.clientStore.getRoom(roomId); 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 * @param {module:models/room} room the room the event is in
*/ */
public prepareToEncrypt(room: Room): void { public prepareToEncrypt(room: Room): void {
const alg = this.roomEncryptors[room.roomId]; const alg = this.roomEncryptors.get(room.roomId);
if (alg) { if (alg) {
alg.prepareToEncrypt(room); alg.prepareToEncrypt(room);
} }
@@ -2808,7 +2808,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
const roomId = event.getRoomId(); const roomId = event.getRoomId();
const alg = this.roomEncryptors[roomId]; const alg = this.roomEncryptors.get(roomId);
if (!alg) { if (!alg) {
// MatrixClient has already checked that this room should be encrypted, // MatrixClient has already checked that this room should be encrypted,
// so this is an unexpected situation. // so this is an unexpected situation.
@@ -3097,7 +3097,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
private getTrackedE2eRooms(): Room[] { private getTrackedE2eRooms(): Room[] {
return this.clientStore.getRooms().filter((room) => { return this.clientStore.getRooms().filter((room) => {
// check for rooms with encryption enabled // check for rooms with encryption enabled
const alg = this.roomEncryptors[room.roomId]; const alg = this.roomEncryptors.get(room.roomId);
if (!alg) { if (!alg) {
return false; return false;
} }
@@ -3533,7 +3533,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
const roomId = member.roomId; const roomId = member.roomId;
const alg = this.roomEncryptors[roomId]; const alg = this.roomEncryptors.get(roomId);
if (!alg) { if (!alg) {
// not encrypting in this room // not encrypting in this room
return; return;
@@ -3634,11 +3634,11 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
` for ${roomId} / ${body.session_id} (id ${req.requestId})`); ` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
if (userId !== this.userId) { if (userId !== this.userId) {
if (!this.roomEncryptors[roomId]) { if (!this.roomEncryptors.get(roomId)) {
logger.debug(`room key request for unencrypted room ${roomId}`); logger.debug(`room key request for unencrypted room ${roomId}`);
return; return;
} }
const encryptor = this.roomEncryptors[roomId]; const encryptor = this.roomEncryptors.get(roomId);
const device = this.deviceList.getStoredDevice(userId, deviceId); const device = this.deviceList.getStoredDevice(userId, deviceId);
if (!device) { if (!device) {
logger.debug(`Ignoring keyshare for unknown device ${userId}:${deviceId}`); 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 // 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. // 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}`); logger.log(`room key request for unencrypted room ${roomId}`);
return; return;
} }
const decryptor = this.roomDecryptors[roomId][alg]; const decryptor = this.roomDecryptors.get(roomId).get(alg);
if (!decryptor) { if (!decryptor) {
logger.log(`room key request for unknown alg ${alg} in room ${roomId}`); logger.log(`room key request for unknown alg ${alg} in room ${roomId}`);
return; return;
@@ -3745,23 +3745,24 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
* unknown * unknown
*/ */
public getRoomDecryptor(roomId: string, algorithm: string): DecryptionAlgorithm { public getRoomDecryptor(roomId: string, algorithm: string): DecryptionAlgorithm {
let decryptors: Record<string, DecryptionAlgorithm>; let decryptors: Map<string, DecryptionAlgorithm>;
let alg: DecryptionAlgorithm; let alg: DecryptionAlgorithm;
roomId = roomId || null; roomId = roomId || null;
if (roomId) { if (roomId) {
decryptors = this.roomDecryptors[roomId]; decryptors = this.roomDecryptors.get(roomId);
if (!decryptors) { 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) { if (alg) {
return alg; return alg;
} }
} }
const AlgClass = algorithms.DECRYPTION_CLASSES[algorithm]; const AlgClass = algorithms.DECRYPTION_CLASSES.get(algorithm);
if (!AlgClass) { if (!AlgClass) {
throw new algorithms.DecryptionError( throw new algorithms.DecryptionError(
'UNKNOWN_ENCRYPTION_ALGORITHM', 'UNKNOWN_ENCRYPTION_ALGORITHM',
@@ -3777,7 +3778,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
}); });
if (decryptors) { if (decryptors) {
decryptors[algorithm] = alg; decryptors.set(algorithm, alg);
} }
return alg; return alg;
} }
@@ -3791,9 +3792,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
*/ */
private getRoomDecryptors(algorithm: string): DecryptionAlgorithm[] { private getRoomDecryptors(algorithm: string): DecryptionAlgorithm[] {
const decryptors = []; const decryptors = [];
for (const d of Object.values(this.roomDecryptors)) { for (const d of this.roomDecryptors.values()) {
if (algorithm in d) { if (d.has(algorithm)) {
decryptors.push(d[algorithm]); decryptors.push(d.get(algorithm));
} }
} }
return decryptors; return decryptors;

View File

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

View File

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

View File

@@ -23,14 +23,8 @@ import { Room } from "./room";
export class RelationsContainer { export class RelationsContainer {
// A tree of objects to access a set of related children for an event, as in: // A tree of objects to access a set of related children for an event, as in:
// this.relations[parentEventId][relationType][relationEventType] // this.relations.get(parentEventId).get(relationType).get(relationEventType)
private relations: { private relations = new Map<string, Map<RelationType | string, Map<EventType | string, Relations>>>();
[parentEventId: string]: {
[relationType: RelationType | string]: {
[eventType: EventType | string]: Relations;
};
};
} = {};
constructor(private readonly client: MatrixClient, private readonly room?: Room) { constructor(private readonly client: MatrixClient, private readonly room?: Room) {
} }
@@ -57,14 +51,15 @@ export class RelationsContainer {
relationType: RelationType | string, relationType: RelationType | string,
eventType: EventType | string, eventType: EventType | string,
): Relations | undefined { ): Relations | undefined {
return this.relations[eventId]?.[relationType]?.[eventType]; return this.relations.get(eventId)?.get(relationType)?.get(eventType);
} }
public getAllChildEventsForEvent(parentEventId: string): MatrixEvent[] { 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[] = []; const events: MatrixEvent[] = [];
for (const relationsRecord of Object.values(relationsForEvent)) { for (const relationsRecord of relationsForEvent.values()) {
for (const relations of Object.values(relationsRecord)) { for (const relations of relationsRecord.values()) {
events.push(...relations.getRelations()); events.push(...relations.getRelations());
} }
} }
@@ -79,11 +74,11 @@ export class RelationsContainer {
* @param {MatrixEvent} event The event to check as relation target. * @param {MatrixEvent} event The event to check as relation target.
*/ */
public aggregateParentEvent(event: MatrixEvent): void { public aggregateParentEvent(event: MatrixEvent): void {
const relationsForEvent = this.relations[event.getId()]; const relationsForEvent = this.relations.get(event.getId());
if (!relationsForEvent) return; if (!relationsForEvent) return;
for (const relationsWithRelType of Object.values(relationsForEvent)) { for (const relationsWithRelType of relationsForEvent.values()) {
for (const relationsWithEventType of Object.values(relationsWithRelType)) { for (const relationsWithEventType of relationsWithRelType.values()) {
relationsWithEventType.setTargetEvent(event); relationsWithEventType.setTargetEvent(event);
} }
} }
@@ -123,23 +118,26 @@ export class RelationsContainer {
const { event_id: relatesToEventId, rel_type: relationType } = relation; const { event_id: relatesToEventId, rel_type: relationType } = relation;
const eventType = event.getType(); const eventType = event.getType();
let relationsForEvent = this.relations[relatesToEventId]; let relationsForEvent = this.relations.get(relatesToEventId);
if (!relationsForEvent) { 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) { 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) { if (!relationsWithEventType) {
relationsWithEventType = relationsWithRelType[eventType] = new Relations( relationsWithEventType = new Relations(
relationType, relationType,
eventType, eventType,
this.client, this.client,
); );
relationsWithRelType.set(eventType, relationsWithEventType);
const room = this.room ?? timelineSet?.room; const room = this.room ?? timelineSet?.room;
const relatesToEvent = timelineSet?.findEventById(relatesToEventId) 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); public readonly reEmitter = new TypedReEmitter<EmittedEvents, EventHandlerMap>(this);
private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember
// stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys) // 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 userIdsToDisplayNames: Record<string, string> = {};
private tokenToInvite: Record<string, MatrixEvent> = {}; // 3pid invite state_key to m.room.member invite 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 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. * @return {string[]} An array of user IDs or an empty array.
*/ */
public getUserIdsWithDisplayName(displayName: string): string[] { 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. // the lot.
const strippedOldName = utils.removeHiddenChars(oldName); const strippedOldName = utils.removeHiddenChars(oldName);
const existingUserIds = this.displayNameToUserIds[strippedOldName]; const existingUserIds = this.displayNameToUserIds.get(strippedOldName);
if (existingUserIds) { if (existingUserIds) {
// remove this user ID from this array // remove this user ID from this array
const filteredUserIDs = existingUserIds.filter((id) => id !== userId); 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); const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
// an empty stripped displayname (undefined/'') will be set to MXID in room-member.js // an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
if (strippedDisplayname) { if (strippedDisplayname) {
if (!this.displayNameToUserIds[strippedDisplayname]) { const arr = this.displayNameToUserIds.get(strippedDisplayname) ?? [];
this.displayNameToUserIds[strippedDisplayname] = []; arr.push(userId);
} this.displayNameToUserIds.set(strippedDisplayname, arr);
this.displayNameToUserIds[strippedDisplayname].push(userId);
} }
} }
} }

View File

@@ -28,6 +28,30 @@ import { MatrixClient, MatrixEvent } from ".";
import { M_TIMESTAMP } from "./@types/location"; import { M_TIMESTAMP } from "./@types/location";
import { ReceiptType } from "./@types/read_receipts"; 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. * Encode a dictionary of query parameters.
* Omits any undefined/null values. * Omits any undefined/null values.