UNPKG

nativescript-matrix-sdk

Version:

Native Matrix SDK integration for NativeScript

269 lines (235 loc) 8.82 kB
/** * Optimization Registry * * This file provides a central registry for all optimization components, * enabling better management, initialization, and cleanup of optimizations. */ import { isAndroid, isIOS } from '@nativescript/core'; import { Logger } from './logger'; import { MatrixLRUCache, BatchOperationHandler, PaginationOptimizer, EventOptimizer } from './optimizations'; import { Clearable, MemoryCondition } from './memory-optimizer-base'; import { MatrixMemoryOptimizerAndroid } from '../platforms/android/matrix-memory-optimizer.android'; import { MatrixMemoryOptimizerIOS } from '../platforms/ios/matrix-memory-optimizer.ios'; import { MatrixError, MatrixErrorType } from './errors'; /** * Cache configuration for different resource types */ export interface CacheConfig { roomMessages: number; // Number of rooms to cache messages for chats: number; // Number of chats to cache userData: number; // Number of user data objects to cache media: number; // Number of media items to cache thumbnails: number; // Number of thumbnails to cache } /** * Interface for memory optimization methods */ export interface MemoryOptimizers { isMemoryLow: () => boolean; isMemoryCritical: () => boolean; } /** * Interface defining the structure of the optimizers export */ export interface Optimizers { cache: MatrixLRUCache<unknown>; batch: BatchOperationHandler; pagination: PaginationOptimizer; event: EventOptimizer; memory: MemoryOptimizers; } /** * Default cache configuration */ const DEFAULT_CACHE_CONFIG: CacheConfig = { roomMessages: 20, chats: 100, userData: 200, media: 50, thumbnails: 100 }; /** * Central registry for all optimization components */ export class OptimizationsRegistry { // Core optimizers public readonly cache: MatrixLRUCache<unknown>; public readonly roomCache: MatrixLRUCache<unknown>; public readonly userCache: MatrixLRUCache<unknown>; public readonly mediaCache: MatrixLRUCache<unknown>; public readonly thumbnailCache: MatrixLRUCache<unknown>; public readonly batch: BatchOperationHandler; public readonly pagination: PaginationOptimizer; public readonly event: EventOptimizer; // Platform-specific memory optimizer private readonly memoryOptimizer: MatrixMemoryOptimizerAndroid | MatrixMemoryOptimizerIOS; // Registry state private initialized = false; /** * Create the optimization registry */ constructor(cacheConfig: Partial<CacheConfig> = {}) { // Apply default cache config with overrides const config = { ...DEFAULT_CACHE_CONFIG, ...cacheConfig }; // Initialize optimizers this.cache = new MatrixLRUCache<unknown>(500); this.roomCache = new MatrixLRUCache<unknown>(config.roomMessages); this.userCache = new MatrixLRUCache<unknown>(config.userData); this.mediaCache = new MatrixLRUCache<unknown>(config.media); this.thumbnailCache = new MatrixLRUCache<unknown>(config.thumbnails); this.batch = new BatchOperationHandler(); this.pagination = new PaginationOptimizer(config.roomMessages); this.event = new EventOptimizer(); // Create platform-specific memory optimizer if (isAndroid) { this.memoryOptimizer = new MatrixMemoryOptimizerAndroid(); } else if (isIOS) { this.memoryOptimizer = new MatrixMemoryOptimizerIOS(); } else { throw new Error('Unsupported platform'); } Logger.info('[OptimizationsRegistry] Created with configuration'); } /** * Initialize the registry by registering caches with the memory optimizer */ public initialize(): void { if (this.initialized) { return; } try { // Register all caches with the memory optimizer this.registerCaches(); // Do an initial memory check to set baseline const initialCondition = this.memoryOptimizer.isMemoryLow() ? MemoryCondition.LOW : MemoryCondition.NORMAL; // Log initialization Logger.info(`[OptimizationsRegistry] Initialized with memory condition: ${initialCondition}`); this.initialized = true; } catch (error) { const errorMessage = 'Failed to initialize optimization registry'; Logger.error(`[OptimizationsRegistry] ${errorMessage}`, error); throw new MatrixError( errorMessage, MatrixErrorType.INITIALIZATION, error instanceof Error ? error : undefined, { component: 'OptimizationsRegistry' } ); } } /** * Pre-initialize with minimal setup for startup performance * This does a lightweight initialization without registering all caches */ public preInitialize(): void { if (this.initialized) { return; } try { // Just check memory status to initialize monitoring // This ensures we can start tracking memory usage early this.memoryOptimizer.isMemoryLow(); Logger.info(`[OptimizationsRegistry] Pre-initialized for startup performance`); } catch (error) { const errorMessage = 'Failed to pre-initialize optimization registry'; Logger.error(`[OptimizationsRegistry] ${errorMessage}`, error); // Don't throw here to prevent app startup failures // Just log the error and continue } } /** * Register all caches with the memory optimizer */ private registerCaches(): void { const memOpt = this.memoryOptimizer; // Register with different priorities memOpt.registerCache('general', this.cache, 5); memOpt.registerCache('thumbnail', this.thumbnailCache, 2); // First to clear memOpt.registerCache('media', this.mediaCache, 3); memOpt.registerCache('user', this.userCache, 7); memOpt.registerCache('room', this.roomCache, 8); // Last to clear Logger.debug('[OptimizationsRegistry] Registered caches with memory optimizer'); } /** * Check if memory usage is low * @returns true if memory is low */ public isMemoryLow(): boolean { try { return this.memoryOptimizer.isMemoryLow(); } catch (error) { Logger.error('[OptimizationsRegistry] Error checking memory status', error); // In case of error, assume memory is not low to prevent aggressive cleanup return false; } } /** * Check if memory usage is critical * @returns true if memory is critical */ public isMemoryCritical(): boolean { try { return this.memoryOptimizer.isMemoryCritical(); } catch (error) { Logger.error('[OptimizationsRegistry] Error checking critical memory status', error); // In case of error, assume memory is not critical to prevent aggressive cleanup return false; } } /** * Register a cache with the memory optimizer * @param name - Cache name * @param cache - Cache instance * @param priority - Cache priority (1-10, lower means cleared first) */ public registerCache(name: string, cache: Clearable, priority = 5): void { try { this.memoryOptimizer.registerCache(name, cache, priority); Logger.debug(`[OptimizationsRegistry] Registered cache: ${name} with priority ${priority}`); } catch (error) { Logger.error(`[OptimizationsRegistry] Failed to register cache: ${name}`, error); // Don't throw to prevent app failures } } /** * Clean up all optimizations */ public cleanup(): void { try { Logger.info('[OptimizationsRegistry] Cleaning up all optimizations'); // Clear all caches this.cache.clear(); this.roomCache.clear(); this.userCache.clear(); this.mediaCache.clear(); this.thumbnailCache.clear(); // Cancel any pending operations this.batch.cancelAll(); this.pagination.clearAll(); this.event.cancelAll(); // Clean up memory optimizer this.memoryOptimizer.cleanup(); this.initialized = false; Logger.info('[OptimizationsRegistry] Cleaned up'); } catch (error) { Logger.error('[OptimizationsRegistry] Error during cleanup', error); // Continue cleanup even if some parts fail // Still reset initialization state even if cleanup fails } } } // Export a singleton instance export const optimizationsRegistry = new OptimizationsRegistry(); // Re-export the optimizers from the registry for backwards compatibility export const optimizers: Optimizers = { cache: optimizationsRegistry.cache, batch: optimizationsRegistry.batch, pagination: optimizationsRegistry.pagination, event: optimizationsRegistry.event, get memory(): MemoryOptimizers { return { isMemoryLow: (): boolean => optimizationsRegistry.isMemoryLow(), isMemoryCritical: (): boolean => optimizationsRegistry.isMemoryCritical() }; } };