perf(notifications): memoize getNotificationType per push-rules object and room
Fixes #77 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
+37
-3
@@ -188,7 +188,11 @@ export const isMutedRule = (rule: IPushRule) =>
|
||||
export const findMutedRule = (overrideRules: IPushRule[], roomId: string) =>
|
||||
overrideRules.find((rule) => rule.rule_id === roomId && isMutedRule(rule));
|
||||
|
||||
export const getNotificationType = (mx: MatrixClient, roomId: string): NotificationType => {
|
||||
const computeNotificationType = (
|
||||
mx: MatrixClient,
|
||||
roomId: string,
|
||||
pushRulesContent: IPushRules | undefined,
|
||||
): NotificationType => {
|
||||
let roomPushRule: IPushRule | undefined;
|
||||
try {
|
||||
roomPushRule = mx.getRoomPushRule('global', roomId);
|
||||
@@ -197,8 +201,7 @@ export const getNotificationType = (mx: MatrixClient, roomId: string): Notificat
|
||||
}
|
||||
|
||||
if (!roomPushRule) {
|
||||
const overrideRules = mx.getAccountData(EventType.PushRules)?.getContent<IPushRules>()
|
||||
?.global?.override;
|
||||
const overrideRules = pushRulesContent?.global?.override;
|
||||
if (!overrideRules) return NotificationType.Default;
|
||||
|
||||
return findMutedRule(overrideRules, roomId) ? NotificationType.Mute : NotificationType.Default;
|
||||
@@ -208,6 +211,37 @@ export const getNotificationType = (mx: MatrixClient, roomId: string): Notificat
|
||||
return NotificationType.MentionsAndKeywords;
|
||||
};
|
||||
|
||||
// #77 — `getNotificationType` is called synchronously for every live timeline
|
||||
// event in every room, but its result only ever changes when the `m.push_rules`
|
||||
// account-data event updates. matrix-js-sdk replaces the stored account-data
|
||||
// `MatrixEvent`'s content wholesale on every `m.push_rules` update (see
|
||||
// `store.storeAccountDataEvents`), so keying a cache off that content object's
|
||||
// identity naturally invalidates itself on `ClientEvent.AccountData` without
|
||||
// needing an explicit listener here. A bursty sync backlog across many rooms
|
||||
// then hits this cache instead of re-running `getRoomPushRule` + a linear scan
|
||||
// of the override rules per event.
|
||||
const notificationTypeCache = new WeakMap<object, Map<string, NotificationType>>();
|
||||
// Stable key to use when there is no push-rules account data at all yet.
|
||||
const NO_PUSH_RULES_KEY: object = {};
|
||||
|
||||
export const getNotificationType = (mx: MatrixClient, roomId: string): NotificationType => {
|
||||
const pushRulesContent = mx.getAccountData(EventType.PushRules)?.getContent<IPushRules>();
|
||||
const cacheKey = pushRulesContent ?? NO_PUSH_RULES_KEY;
|
||||
|
||||
let roomCache = notificationTypeCache.get(cacheKey);
|
||||
if (!roomCache) {
|
||||
roomCache = new Map();
|
||||
notificationTypeCache.set(cacheKey, roomCache);
|
||||
}
|
||||
|
||||
const cached = roomCache.get(roomId);
|
||||
if (cached !== undefined) return cached;
|
||||
|
||||
const result = computeNotificationType(mx, roomId, pushRulesContent);
|
||||
roomCache.set(roomId, result);
|
||||
return result;
|
||||
};
|
||||
|
||||
const NOTIFICATION_EVENT_TYPES = [
|
||||
'm.room.create',
|
||||
'm.room.message',
|
||||
|
||||
Reference in New Issue
Block a user