@toast-studios/asset-manager
Version:
A React Native asset management library with intelligent caching and loading strategies
198 lines (197 loc) • 7.5 kB
JavaScript
"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