UNPKG

@toast-studios/asset-manager

Version:

A React Native asset management library with intelligent caching and loading strategies

198 lines (197 loc) 7.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DeviceDetector = void 0; /** * Device capability detector and performance analyzer */ class DeviceDetector { /** * Get comprehensive device metrics with caching */ static async getDeviceMetrics() { const now = Date.now(); // Return cached metrics if still valid if (this.cachedMetrics && this.lastUpdateTime && now - this.lastUpdateTime < this.CACHE_DURATION) { return this.cachedMetrics; } try { // Try to get device info from React Native modules const deviceInfo = await this.getReactNativeDeviceInfo(); this.cachedMetrics = { totalMemory: deviceInfo.totalMemory, availableMemory: deviceInfo.totalMemory - deviceInfo.usedMemory, cpuCores: this.estimateCpuCores(deviceInfo), isLowEnd: this.isLowEndDevice(deviceInfo), batteryLevel: deviceInfo.batteryLevel, isCharging: deviceInfo.isCharging, thermalState: deviceInfo.thermalState, deviceType: this.detectDeviceType(deviceInfo), }; this.lastUpdateTime = now; } catch (error) { // Fallback to conservative estimates this.cachedMetrics = this.getConservativeDefaults(); this.lastUpdateTime = now; } return this.cachedMetrics; } /** * Get cached device metrics synchronously (returns defaults if not cached) */ static getDeviceMetricsSync() { return this.cachedMetrics || this.getConservativeDefaults(); } /** * Check if device is suitable for heavy asset downloads */ static async canHandleHeavyDownloads() { const metrics = await this.getDeviceMetrics(); return (!metrics.isLowEnd && metrics.availableMemory > 1024 * 1024 * 1024 && // >1GB available metrics.totalMemory > 3 * 1024 * 1024 * 1024 && // >3GB total (metrics.batteryLevel === undefined || metrics.batteryLevel > 20) && // >20% battery (metrics.thermalState === undefined || ['nominal', 'fair'].includes(metrics.thermalState))); } /** * Get optimal download concurrency based on device capabilities */ static async getOptimalConcurrency() { const metrics = await this.getDeviceMetrics(); if (metrics.isLowEnd) return 1; if (metrics.totalMemory < 3 * 1024 * 1024 * 1024) return 1; // <3GB if (metrics.totalMemory < 6 * 1024 * 1024 * 1024) return 2; // 3-6GB if (metrics.cpuCores <= 4) return 2; return Math.min(metrics.cpuCores / 2, 4); // Max 4 concurrent downloads } /** * Check if device should use conservative download settings */ static async shouldUseConservativeSettings() { const metrics = await this.getDeviceMetrics(); return (metrics.isLowEnd || metrics.totalMemory < 4 * 1024 * 1024 * 1024 || // <4GB (metrics.batteryLevel !== undefined && metrics.batteryLevel < 30) || (metrics.thermalState !== undefined && ['serious', 'critical'].includes(metrics.thermalState))); } /** * Invalidate cache to force fresh device metrics */ static invalidateCache() { this.cachedMetrics = undefined; this.lastUpdateTime = undefined; } /** * Get device info from React Native modules */ static async getReactNativeDeviceInfo() { var _a; try { // Try multiple sources for device info let deviceInfo = {}; // Try react-native-device-info try { const DeviceInfo = require('react-native-device-info'); deviceInfo = { totalMemory: await DeviceInfo.getTotalMemory(), usedMemory: await DeviceInfo.getUsedMemory(), batteryLevel: await DeviceInfo.getBatteryLevel(), isCharging: await DeviceInfo.isBatteryCharging(), deviceType: await DeviceInfo.getDeviceType(), isEmulator: await DeviceInfo.isEmulator(), cpuCount: (await ((_a = DeviceInfo.getProcessorCount) === null || _a === void 0 ? void 0 : _a.call(DeviceInfo))) || 4, }; } catch (e) { // Fallback approach } // Try platform-specific APIs if available if (!deviceInfo.totalMemory) { try { const { NativeModules } = require('react-native'); if (NativeModules.DeviceInfo) { const nativeInfo = await NativeModules.DeviceInfo.getDeviceInfo(); deviceInfo = { ...deviceInfo, ...nativeInfo }; } } catch (e) { // Ignore } } return deviceInfo; } catch (error) { throw new Error(`Failed to get device info: ${error}`); } } /** * Conservative device defaults for fallback */ static getConservativeDefaults() { return { totalMemory: 2 * 1024 * 1024 * 1024, availableMemory: 1024 * 1024 * 1024, cpuCores: 4, isLowEnd: true, deviceType: 'phone', }; } /** * Estimate CPU cores based on device info */ static estimateCpuCores(deviceInfo) { if (deviceInfo.cpuCount) return deviceInfo.cpuCount; // Estimate based on memory const totalMemoryGB = deviceInfo.totalMemory / (1024 * 1024 * 1024); if (totalMemoryGB < 3) return 4; if (totalMemoryGB < 6) return 6; if (totalMemoryGB < 8) return 8; return 8; // Cap at 8 for mobile devices } /** * Determine if device is low-end based on comprehensive metrics */ static isLowEndDevice(deviceInfo) { const memoryGB = deviceInfo.totalMemory / (1024 * 1024 * 1024); const cpuCores = this.estimateCpuCores(deviceInfo); // Multiple criteria for low-end detection return (memoryGB < 4 || // Less than 4GB RAM cpuCores <= 4 || // 4 or fewer CPU cores deviceInfo.isEmulator || // Emulator environments (deviceInfo.deviceType && ['tv'].includes(deviceInfo.deviceType)) // TV devices ); } /** * Detect device type from available info */ static detectDeviceType(deviceInfo) { if (deviceInfo.deviceType) { const type = deviceInfo.deviceType.toLowerCase(); if (['phone', 'handset'].includes(type)) return 'phone'; if (['tablet', 'pad'].includes(type)) return 'tablet'; if (['tv', 'television'].includes(type)) return 'tv'; } // Estimate based on memory - tablets usually have more RAM const memoryGB = deviceInfo.totalMemory / (1024 * 1024 * 1024); if (memoryGB > 6) return 'tablet'; return 'phone'; // Default assumption } } exports.DeviceDetector = DeviceDetector; DeviceDetector.CACHE_DURATION = 30000; // 30 seconds