getOrCacheAndRegisterWithProgress method

Stream<int> getOrCacheAndRegisterWithProgress({
  1. required String cacheKey,
  2. required Future<Uint8List> loader(
    1. void onProgress(
      1. double
      )
    ),
  3. required String targetPath,
})

Universal caching wrapper with progress tracking (stream version)

Checks cache first (if enabled), loads if needed, caches (if enabled), creates blob URL, registers in file system. Yields progress as int percentage (0-100).

cacheKey - Key for Cache API storage loader - Async function that loads data and reports progress via callback targetPath - Path to register in WebFileSystemService

Returns: Stream of progress percentages (0-100)

Implementation

Stream<int> getOrCacheAndRegisterWithProgress({
  required String cacheKey,
  required Future<Uint8List> Function(void Function(double) onProgress) loader,
  required String targetPath,
}) async* {
  try {
    // 1. Check cache first (only if caching enabled)
    if (enableCache) {
      final cachedBlobUrl = await getCachedBlobUrl(cacheKey);
      if (cachedBlobUrl != null) {
        debugPrint('[WebCacheService] ✅ Found in cache: $cacheKey');
        _fileSystem.registerUrl(targetPath, cachedBlobUrl);
        yield 100; // Instant completion
        return;
      }
    }

    // 2. Load data with progress tracking
    debugPrint('[WebCacheService] 📥 Loading: $cacheKey (cache: ${enableCache ? "enabled" : "disabled"})');

    final controller = StreamController<int>();
    Uint8List? loadedData;

    // Start loading in background with progress callback
    loader((progress) {
      final percent = (progress * 100).clamp(0, 99).toInt();
      if (!controller.isClosed) {
        controller.add(percent);
      }
    }).then((data) {
      loadedData = data;
      if (!controller.isClosed) {
        controller.close();
      }
    }).catchError((error) {
      if (!controller.isClosed) {
        controller.addError(error);
        controller.close();
      }
    });

    // Yield progress updates
    await for (final progress in controller.stream) {
      yield progress;
    }

    if (loadedData == null) {
      throw Exception('Failed to load data for: $cacheKey');
    }

    // 3. Cache the data (only if caching enabled)
    if (enableCache) {
      await cacheModel(cacheKey, loadedData!);

      // 4. Create blob URL from cache
      final blobUrl = await getCachedBlobUrl(cacheKey);
      if (blobUrl == null) {
        throw Exception('Failed to create blob URL for: $cacheKey');
      }

      // 5. Register in file system
      _fileSystem.registerUrl(targetPath, blobUrl);

      debugPrint('[WebCacheService] ✅ Cached and registered: $cacheKey');
    } else {
      // Create temporary blob URL without caching
      final blobUrl = _cacheInterop.createBlobUrl(loadedData!);
      _fileSystem.registerUrl(targetPath, blobUrl);

      debugPrint('[WebCacheService] ✅ Registered (no cache): $cacheKey');
    }

    yield 100; // Final completion
  } catch (e) {
    debugPrint('[WebCacheService] ❌ getOrCacheAndRegisterWithProgress failed: $e');
    rethrow;
  }
}