UNPKG

@toast-studios/asset-manager

Version:

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

228 lines (227 loc) 9.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NetworkAwareStrategy = void 0; const index_1 = require("../types/index"); const DeviceDetector_1 = require("../utils/DeviceDetector"); /** * Network performance evaluator */ class NetworkEvaluator { static getOptimalQuality(conditions) { if (!conditions.isConnected) return index_1.AssetQuality.MEDIUM; const speed = conditions.speed || this.estimateSpeedFromType(conditions.type); const effectiveSpeed = speed * this.getPingMultiplier(conditions.ping); // High quality only on WiFi with good speed, more lenient for India if (effectiveSpeed >= this.QUALITY_SPEED_MAP[index_1.AssetQuality.HIGH] && (conditions.type === index_1.NetworkType.WIFI || conditions.type === index_1.NetworkType.CELLULAR)) { return index_1.AssetQuality.HIGH; } return index_1.AssetQuality.MEDIUM; } static shouldDownloadOnMetered(bundle) { return (bundle.isCritical || bundle.assets.some(a => a.priority <= index_1.DownloadPriority.HIGH)); } static estimateSpeedFromType(type) { switch (type) { case index_1.NetworkType.WIFI: return 8; // Reduced from 10 - more realistic for Indian WiFi case index_1.NetworkType.ETHERNET: return 20; // Reduced from 25 - more conservative case index_1.NetworkType.CELLULAR: return 6; // Increased from 4 - reflects current 4G/5G mix in India default: return 0.5; // Reduced from 1 - conservative for unknown connections } } static getPingMultiplier(ping) { if (!ping) return 1; if (ping < 100) return 1; if (ping < 200) return 0.95; // More lenient for Indian networks if (ping < 400) return 0.8; // Adjusted for typical Indian latencies if (ping < 600) return 0.6; // More forgiving return 0.4; // Minimum multiplier for very high ping } } NetworkEvaluator.QUALITY_SPEED_MAP = { [index_1.AssetQuality.MEDIUM]: 1.5, [index_1.AssetQuality.HIGH]: 5, // Reduced from 8 for typical 4G in India }; /** * Bundle scoring system */ class BundleScorer { static scoreBundle(bundle, optimalQuality) { let score = 0; // Critical bundles get priority boost if (bundle.isCritical) score += 1000; // Quality match scoring const qualityScore = this.getQualityScore(bundle, optimalQuality); score += qualityScore * 100; // Priority scoring (lower priority number = higher importance) const avgPriority = bundle.assets.reduce((sum, a) => sum + a.priority, 0) / bundle.assets.length; score += (5 - avgPriority) * 10; // Size penalty (prefer smaller bundles for faster initial load) const sizePenalty = Math.min(bundle.size / (1024 * 1024), 50); // Max 50MB penalty score -= sizePenalty; return score; } static getQualityScore(bundle, optimalQuality) { const qualityValues = { [index_1.AssetQuality.MEDIUM]: 1, [index_1.AssetQuality.HIGH]: 2, }; const optimalValue = qualityValues[optimalQuality]; const bundleQualities = bundle.assets.map(a => qualityValues[a.quality]); const bestMatch = bundleQualities.reduce((best, current) => Math.abs(current - optimalValue) < Math.abs(best - optimalValue) ? current : best); return Math.max(0, 3 - Math.abs(bestMatch - optimalValue)); } } /** * Configuration-driven network-aware strategy */ class NetworkAwareStrategy { constructor() { this.name = 'network-aware'; this.config = { maxConcurrentDownloads: { low: 1, medium: 2, high: 3 }, enableMeteredDownloads: false, prioritizeCritical: true, adaptToDevicePerformance: true, // Indian market specific settings lowEndDeviceSizeThreshold: 5 * 1024 * 1024, meteredConnectionConservative: true, }; // Initialize device metrics cache on construction DeviceDetector_1.DeviceDetector.getDeviceMetrics().catch(() => { // Ignore errors - will use fallback values }); } getOptimalQuality(conditions) { return NetworkEvaluator.getOptimalQuality(conditions); } prioritizeBundles(bundles, conditions) { const optimalQuality = this.getOptimalQuality(conditions); return [...bundles].sort((a, b) => { const scoreA = BundleScorer.scoreBundle(a, optimalQuality); const scoreB = BundleScorer.scoreBundle(b, optimalQuality); return scoreB - scoreA; // Higher score first }); } shouldDownload(bundle, conditions) { if (!conditions.isConnected) return false; if (bundle.isCritical) return true; // Check metered connection policy if (conditions.isMetered && !this.config.enableMeteredDownloads) { return NetworkEvaluator.shouldDownloadOnMetered(bundle); } // Check device performance constraints - more conservative for India if (this.config.adaptToDevicePerformance) { const deviceMetrics = DeviceDetector_1.DeviceDetector.getDeviceMetricsSync(); if (deviceMetrics.isLowEnd && bundle.size > this.config.lowEndDeviceSizeThreshold) { const avgPriority = bundle.assets.reduce((sum, a) => sum + a.priority, 0) / bundle.assets.length; return avgPriority <= index_1.DownloadPriority.MEDIUM; } } return true; } getMaxConcurrentDownloads(conditions) { const deviceMetrics = DeviceDetector_1.DeviceDetector.getDeviceMetricsSync(); let maxDownloads = this.config.maxConcurrentDownloads.medium; // Adjust based on device performance - more conservative for Indian market if (deviceMetrics.isLowEnd || deviceMetrics.totalMemory < 3 * 1024 * 1024 * 1024) { // <3GB maxDownloads = this.config.maxConcurrentDownloads.low; } else if (deviceMetrics.availableMemory > 6 * 1024 * 1024 * 1024) { // >6GB maxDownloads = this.config.maxConcurrentDownloads.high; } // Network condition adjustments - more conservative for Indian cellular if (conditions.type === index_1.NetworkType.CELLULAR) { maxDownloads = Math.min(maxDownloads, 1); // Very conservative for cellular } if (conditions.isMetered && this.config.meteredConnectionConservative) { maxDownloads = 1; // Force single download on metered connections } return Math.max(1, maxDownloads); // Ensure at least 1 download } /** * Update strategy configuration */ configure(newConfig) { this.config = { ...this.config, ...newConfig }; } /** * Async methods for advanced usage */ async getOptimalQualityAsync(conditions) { return NetworkEvaluator.getOptimalQuality(conditions); } async prioritizeBundlesAsync(bundles, conditions) { const optimalQuality = await this.getOptimalQualityAsync(conditions); return [...bundles].sort((a, b) => { const scoreA = BundleScorer.scoreBundle(a, optimalQuality); const scoreB = BundleScorer.scoreBundle(b, optimalQuality); return scoreB - scoreA; }); } async shouldDownloadAsync(bundle, conditions) { if (!conditions.isConnected) return false; if (bundle.isCritical) return true; if (conditions.isMetered && !this.config.enableMeteredDownloads) { return NetworkEvaluator.shouldDownloadOnMetered(bundle); } if (this.config.adaptToDevicePerformance) { const deviceMetrics = await DeviceDetector_1.DeviceDetector.getDeviceMetrics(); if (deviceMetrics.isLowEnd && bundle.size > this.config.lowEndDeviceSizeThreshold) { const avgPriority = bundle.assets.reduce((sum, a) => sum + a.priority, 0) / bundle.assets.length; return avgPriority <= index_1.DownloadPriority.MEDIUM; } } return true; } async getMaxConcurrentDownloadsAsync(conditions) { const deviceMetrics = await DeviceDetector_1.DeviceDetector.getDeviceMetrics(); let maxDownloads = this.config.maxConcurrentDownloads.medium; // Adjust based on device performance - more conservative for Indian market if (deviceMetrics.isLowEnd || deviceMetrics.totalMemory < 3 * 1024 * 1024 * 1024) { // <3GB maxDownloads = this.config.maxConcurrentDownloads.low; } else if (deviceMetrics.availableMemory > 6 * 1024 * 1024 * 1024) { // >6GB maxDownloads = this.config.maxConcurrentDownloads.high; } // Network condition adjustments - more conservative for Indian cellular if (conditions.type === index_1.NetworkType.CELLULAR) { maxDownloads = Math.min(maxDownloads, 1); // Very conservative for cellular } if (conditions.isMetered && this.config.meteredConnectionConservative) { maxDownloads = 1; // Force single download on metered connections } return Math.max(1, maxDownloads); // Ensure at least 1 download } } exports.NetworkAwareStrategy = NetworkAwareStrategy;