nativescript-matrix-sdk
Version:
Native Matrix SDK integration for NativeScript
269 lines (235 loc) • 8.82 kB
text/typescript
/**
* 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()
};
}
};