From dc0d403660eea2836bf483f071b904ba7347773e Mon Sep 17 00:00:00 2001 From: Tasso Date: Mon, 10 Mar 2025 14:48:17 -0300 Subject: [PATCH 1/3] Split `CachedCollection` into subclasses --- .../models/client/models/CachedChatRoom.ts | 4 +- .../client/models/CachedChatSubscription.ts | 4 +- .../app/models/client/models/Permissions.ts | 4 +- .../lib/cachedCollections/CachedCollection.ts | 50 +++++++++++-------- .../client/lib/cachedCollections/index.ts | 2 +- .../PrivateSettingsCachedCollection.ts | 4 +- .../PublicSettingsCachedCollection.ts | 5 +- 7 files changed, 40 insertions(+), 33 deletions(-) diff --git a/apps/meteor/app/models/client/models/CachedChatRoom.ts b/apps/meteor/app/models/client/models/CachedChatRoom.ts index 784503a1b0afc..4daba5f7b08b3 100644 --- a/apps/meteor/app/models/client/models/CachedChatRoom.ts +++ b/apps/meteor/app/models/client/models/CachedChatRoom.ts @@ -2,9 +2,9 @@ import type { IOmnichannelRoom, IRoom, IRoomWithRetentionPolicy } from '@rocket. import { DEFAULT_SLA_CONFIG, LivechatPriorityWeight } from '@rocket.chat/core-typings'; import { CachedChatSubscription } from './CachedChatSubscription'; -import { CachedCollection } from '../../../../client/lib/cachedCollections/CachedCollection'; +import { PrivateCachedCollection } from '../../../../client/lib/cachedCollections/CachedCollection'; -class CachedChatRoom extends CachedCollection { +class CachedChatRoom extends PrivateCachedCollection { constructor() { super({ name: 'rooms' }); } diff --git a/apps/meteor/app/models/client/models/CachedChatSubscription.ts b/apps/meteor/app/models/client/models/CachedChatSubscription.ts index 28b55a70197d4..b7a50e1fa86e5 100644 --- a/apps/meteor/app/models/client/models/CachedChatSubscription.ts +++ b/apps/meteor/app/models/client/models/CachedChatSubscription.ts @@ -3,7 +3,7 @@ import { DEFAULT_SLA_CONFIG, LivechatPriorityWeight } from '@rocket.chat/core-ty import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts'; import { CachedChatRoom } from './CachedChatRoom'; -import { CachedCollection } from '../../../../client/lib/cachedCollections/CachedCollection'; +import { PrivateCachedCollection } from '../../../../client/lib/cachedCollections/CachedCollection'; declare module '@rocket.chat/core-typings' { interface ISubscription { @@ -12,7 +12,7 @@ declare module '@rocket.chat/core-typings' { } } -class CachedChatSubscription extends CachedCollection { +class CachedChatSubscription extends PrivateCachedCollection { constructor() { super({ name: 'subscriptions' }); } diff --git a/apps/meteor/app/models/client/models/Permissions.ts b/apps/meteor/app/models/client/models/Permissions.ts index 5793ab3e897de..18898d07e0b9f 100644 --- a/apps/meteor/app/models/client/models/Permissions.ts +++ b/apps/meteor/app/models/client/models/Permissions.ts @@ -1,8 +1,8 @@ import type { IPermission } from '@rocket.chat/core-typings'; -import { CachedCollection } from '../../../../client/lib/cachedCollections'; +import { PrivateCachedCollection } from '../../../../client/lib/cachedCollections'; -export const AuthzCachedCollection = new CachedCollection({ +export const AuthzCachedCollection = new PrivateCachedCollection({ name: 'permissions', eventType: 'notify-logged', }); diff --git a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts index 9e9e5107d3f2e..95387a1c5bb07 100644 --- a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts +++ b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts @@ -36,7 +36,7 @@ const hasUnserializedUpdatedAt = (record: T): record is T & { _updatedAt: Con localforage.config({ name: baseURI }); -export class CachedCollection { +export abstract class CachedCollection { private static MAX_CACHE_TIME = 60 * 60 * 24 * 30; public collection: MinimongoCollection; @@ -49,20 +49,17 @@ export class CachedCollection { protected version = 18; - protected userRelated: boolean; - protected updatedAt = new Date(0); protected log: (...args: any[]) => void; private timer: ReturnType; - constructor({ name, eventType = 'notify-user', userRelated = true }: { name: Name; eventType?: StreamNames; userRelated?: boolean }) { + constructor({ name, eventType = 'notify-user' }: { name: Name; eventType?: StreamNames }) { this.collection = new Mongo.Collection(null) as MinimongoCollection; this.name = name; this.eventType = eventType; - this.userRelated = userRelated; this.log = [getConfig(`debugCachedCollection-${this.name}`), getConfig('debugCachedCollection'), getConfig('debug')].includes('true') ? console.log.bind(console, `%cCachedCollection ${this.name}`, `color: navy; font-weight: bold;`) @@ -78,13 +75,7 @@ export class CachedCollection { return `${this.name}-changed`; } - getToken() { - if (this.userRelated === false) { - return undefined; - } - - return Accounts._storedLoginToken(); - } + protected abstract getToken(): unknown; private async loadFromCache() { const data = await localforage.getItem<{ version: number; token: unknown; records: unknown[]; updatedAt: Date | string }>(this.name); @@ -207,11 +198,7 @@ export class CachedCollection { this.log('saving cache (done)'); }); - clearCacheOnLogout() { - if (this.userRelated === true) { - void this.clearCache(); - } - } + abstract clearCacheOnLogout(): void; async clearCache() { this.log('clearing cache'); @@ -356,12 +343,33 @@ export class CachedCollection { private reconnectionComputation: Tracker.Computation | undefined; + public abstract listen(): void; +} + +export class PublicCachedCollection extends CachedCollection { + protected getToken() { + return undefined; + } + + clearCacheOnLogout() { + // do nothing + } + listen() { - if (!this.userRelated) { - void this.init(); - return; - } + void this.init(); + } +} +export class PrivateCachedCollection extends CachedCollection { + protected getToken() { + return Accounts._storedLoginToken(); + } + + clearCacheOnLogout() { + void this.clearCache(); + } + + listen() { if (process.env.NODE_ENV === 'test') { return; } diff --git a/apps/meteor/client/lib/cachedCollections/index.ts b/apps/meteor/client/lib/cachedCollections/index.ts index fb99c0d3feead..849e96c1cf5b2 100644 --- a/apps/meteor/client/lib/cachedCollections/index.ts +++ b/apps/meteor/client/lib/cachedCollections/index.ts @@ -1,2 +1,2 @@ -export { CachedCollection } from './CachedCollection'; +export { PrivateCachedCollection, PublicCachedCollection } from './CachedCollection'; export { CachedCollectionManager } from './CachedCollectionManager'; diff --git a/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts b/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts index 1b170c82e7d87..74cb76ac9002a 100644 --- a/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts +++ b/apps/meteor/client/lib/settings/PrivateSettingsCachedCollection.ts @@ -1,9 +1,9 @@ import type { ISetting } from '@rocket.chat/core-typings'; import { sdk } from '../../../app/utils/client/lib/SDKClient'; -import { CachedCollection } from '../cachedCollections'; +import { PrivateCachedCollection } from '../cachedCollections'; -class PrivateSettingsCachedCollection extends CachedCollection { +class PrivateSettingsCachedCollection extends PrivateCachedCollection { constructor() { super({ name: 'private-settings', diff --git a/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts b/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts index 6d01d13d96175..bc12c13997c22 100644 --- a/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts +++ b/apps/meteor/client/lib/settings/PublicSettingsCachedCollection.ts @@ -1,13 +1,12 @@ import type { ISetting } from '@rocket.chat/core-typings'; -import { CachedCollection } from '../cachedCollections'; +import { PublicCachedCollection } from '../cachedCollections/CachedCollection'; -class PublicSettingsCachedCollection extends CachedCollection { +class PublicSettingsCachedCollection extends PublicCachedCollection { constructor() { super({ name: 'public-settings', eventType: 'notify-all', - userRelated: false, }); } } From 069a70aded3f5d66880b2da22bee98b755b58aaf Mon Sep 17 00:00:00 2001 From: Tasso Date: Tue, 11 Mar 2025 17:33:10 -0300 Subject: [PATCH 2/3] Restrict accessors in `CachedCollection` --- .../app/models/client/models/CachedChatRoom.ts | 5 ++++- .../client/models/CachedChatSubscription.ts | 5 ++++- .../lib/cachedCollections/CachedCollection.ts | 18 +++++++++--------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/apps/meteor/app/models/client/models/CachedChatRoom.ts b/apps/meteor/app/models/client/models/CachedChatRoom.ts index 4daba5f7b08b3..ce09e9da0ee58 100644 --- a/apps/meteor/app/models/client/models/CachedChatRoom.ts +++ b/apps/meteor/app/models/client/models/CachedChatRoom.ts @@ -6,7 +6,10 @@ import { PrivateCachedCollection } from '../../../../client/lib/cachedCollection class CachedChatRoom extends PrivateCachedCollection { constructor() { - super({ name: 'rooms' }); + super({ + name: 'rooms', + eventType: 'notify-user', + }); } protected handleLoadFromServer(record: IRoom) { diff --git a/apps/meteor/app/models/client/models/CachedChatSubscription.ts b/apps/meteor/app/models/client/models/CachedChatSubscription.ts index b7a50e1fa86e5..077d3107b3e0f 100644 --- a/apps/meteor/app/models/client/models/CachedChatSubscription.ts +++ b/apps/meteor/app/models/client/models/CachedChatSubscription.ts @@ -14,7 +14,10 @@ declare module '@rocket.chat/core-typings' { class CachedChatSubscription extends PrivateCachedCollection { constructor() { - super({ name: 'subscriptions' }); + super({ + name: 'subscriptions', + eventType: 'notify-user', + }); } protected handleLoadFromServer(record: ISubscription) { diff --git a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts index 95387a1c5bb07..a15ea18190330 100644 --- a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts +++ b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts @@ -37,7 +37,7 @@ const hasUnserializedUpdatedAt = (record: T): record is T & { _updatedAt: Con localforage.config({ name: baseURI }); export abstract class CachedCollection { - private static MAX_CACHE_TIME = 60 * 60 * 24 * 30; + private static readonly MAX_CACHE_TIME = 60 * 60 * 24 * 30; public collection: MinimongoCollection; @@ -47,15 +47,15 @@ export abstract class CachedCollection { protected eventType: StreamNames; - protected version = 18; + private readonly version = 18; - protected updatedAt = new Date(0); + private updatedAt = new Date(0); protected log: (...args: any[]) => void; private timer: ReturnType; - constructor({ name, eventType = 'notify-user' }: { name: Name; eventType?: StreamNames }) { + constructor({ name, eventType }: { name: Name; eventType: StreamNames }) { this.collection = new Mongo.Collection(null) as MinimongoCollection; this.name = name; @@ -186,7 +186,7 @@ export abstract class CachedCollection { await this.save(); } - save = withDebouncing({ wait: 1000 })(async () => { + private save = withDebouncing({ wait: 1000 })(async () => { this.log('saving cache'); const data = this.collection.find().fetch(); await localforage.setItem(this.name, { @@ -200,13 +200,13 @@ export abstract class CachedCollection { abstract clearCacheOnLogout(): void; - async clearCache() { + protected async clearCache() { this.log('clearing cache'); await localforage.removeItem(this.name); this.collection.remove({}); } - async setupListener() { + protected async setupListener() { sdk.stream(this.eventType, [this.eventName], (async (action: 'removed' | 'changed', record: any) => { this.log('record received', action, record); await this.handleRecordEvent(action, record); @@ -232,7 +232,7 @@ export abstract class CachedCollection { await this.save(); } - trySync(delay = 10) { + private trySync(delay = 10) { clearTimeout(this.timer); // Wait for an empty queue to load data again and sync this.timer = setTimeout(async () => { @@ -243,7 +243,7 @@ export abstract class CachedCollection { }, delay); } - async sync() { + protected async sync() { if (!this.updatedAt || this.updatedAt.getTime() === 0 || Meteor.connection._outstandingMethodBlocks.length !== 0) { return false; } From fd6bb97a7fff43f15809129f222385f5acc4db3e Mon Sep 17 00:00:00 2001 From: Tasso Date: Tue, 11 Mar 2025 16:50:35 -0300 Subject: [PATCH 3/3] Remove base method `listen` --- .../meteor/client/lib/cachedCollections/CachedCollection.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts index a15ea18190330..c3903ff532c63 100644 --- a/apps/meteor/client/lib/cachedCollections/CachedCollection.ts +++ b/apps/meteor/client/lib/cachedCollections/CachedCollection.ts @@ -342,8 +342,6 @@ export abstract class CachedCollection { } private reconnectionComputation: Tracker.Computation | undefined; - - public abstract listen(): void; } export class PublicCachedCollection extends CachedCollection { @@ -354,10 +352,6 @@ export class PublicCachedCollection extends Ca clearCacheOnLogout() { // do nothing } - - listen() { - void this.init(); - } } export class PrivateCachedCollection extends CachedCollection {