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