aero_cache 1.0.0 copy "aero_cache: ^1.0.0" to clipboard
aero_cache: ^1.0.0 copied to clipboard

A high-performance HTTP caching library for Dart/Flutter with zstd compression, ETag/Last-Modified revalidation, and full Cache-Control directive support.

AeroCache ☁️ #

CI pub package style: very good analysis

A high-performance HTTP caching library for Dart/Flutter with zstd compression, ETag/Last-Modified revalidation, and full Cache-Control directive support.

Features #

  • High Performance: Efficient caching with zstd compression for optimal storage
  • ETag Support: Automatic cache revalidation using ETag headers
  • Last-Modified Support: Fallback cache validation using Last-Modified headers
  • Vary Header Support: Intelligent cache key generation based on Vary header specifications
  • Cache Control Directives: Support for no-cache, no-store, must-revalidate, max-age, max-stale, min-fresh, only-if-cached, stale-while-revalidate, and stale-if-error
  • Background Revalidation: Stale-while-revalidate support for serving stale content while updating cache
  • Error Resilience: Stale-if-error support for serving cached content during network failures
  • Progress Tracking: Real-time download progress callbacks
  • Automatic Cleanup: Built-in expired cache cleanup
  • Flexible Configuration: Customizable cache directory and compression settings
  • Exception Handling: Comprehensive error handling with custom exceptions

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  aero_cache: ^0.0.1

Then run:

flutter pub get

Usage #

Basic Usage #

import 'package:aero_cache/aero_cache.dart';

void main() async {
  // Create AeroCache instance
  final cache = AeroCache();
  
  // Initialize the cache
  await cache.initialize();
  
  // Get data (downloads if not cached or stale)
  final data = await cache.get('https://example.com/image.jpg');
  
  // Use the data
  print('Downloaded ${data.length} bytes');
  
  // Clean up
  cache.dispose();
}

Advanced Usage #

import 'package:aero_cache/aero_cache.dart';

void main() async {
  // Create AeroCache with custom configuration
  final cache = AeroCache(
    disableCompression: false,  // Enable zstd compression
    compressionLevel: 6,        // Custom compression level (1-22)
    cacheDirPath: '/custom/cache/path',  // Custom cache directory
    defaultCacheDuration: const Duration(hours: 24),  // Custom cache duration
  );
  
  await cache.initialize();
  
  // Get data with progress tracking
  final data = await cache.get(
    'https://example.com/large-file.zip',
    onProgress: (received, total) {
      final progress = (received / total * 100).toStringAsFixed(1);
      print('Download progress: $progress%');
    },
  );
  
  // Get metadata information
  final metaInfo = await cache.metaInfo('https://example.com/large-file.zip');
  if (metaInfo != null) {
    print('ETag: ${metaInfo.etag}');
    print('Last Modified: ${metaInfo.lastModified}');
    print('Is Stale: ${metaInfo.isStale}');
    print('Expires At: ${metaInfo.expiresAt}');
    print('Content Type: ${metaInfo.contentType}');
  }
  
  // Clear expired cache
  await cache.clearExpiredCache();
  
  // Clear all cache
  await cache.clearAllCache();
  
  cache.dispose();
}

Vary Header Handling #

import 'package:aero_cache/aero_cache.dart';

void main() async {
  final cache = AeroCache();
  await cache.initialize();
  
  // First request with English accept-language
  final data1 = await cache.get(
    'https://api.example.com/content',
    headers: {
      'Accept-Language': 'en-US',
      'User-Agent': 'MyApp/1.0',
      'Accept-Encoding': 'gzip',
    },
  );
  
  // Second request with different accept-language
  // This will create a separate cache entry if the server's response
  // includes "Vary: Accept-Language"
  final data2 = await cache.get(
    'https://api.example.com/content',
    headers: {
      'Accept-Language': 'ja-JP',
      'User-Agent': 'MyApp/1.0',
      'Accept-Encoding': 'gzip',
    },
  );
  
  cache.dispose();
}

Cache Control Directives #

import 'package:aero_cache/aero_cache.dart';

void main() async {
  final cache = AeroCache();
  await cache.initialize();
  
  // Force bypass cache and download fresh data
  final freshData = await cache.get(
    'https://api.example.com/data',
    noCache: true,
  );
  
  // Only use cached data, fail if not available
  try {
    final cachedData = await cache.get(
      'https://api.example.com/data',
      onlyIfCached: true,
    );
  } catch (e) {
    print('No cached data available');
  }
  
  // Accept stale data up to 3600 seconds old
  final staleData = await cache.get(
    'https://api.example.com/data',
    maxStale: 3600,
  );
  
  // Require data to be fresh for at least 300 seconds
  final freshRequiredData = await cache.get(
    'https://api.example.com/data',
    minFresh: 300,
  );
  
  // Download without caching (no-store equivalent)
  final temporaryData = await cache.get(
    'https://api.example.com/data',
    noStore: true,
  );
  
  cache.dispose();
}

Flutter Integration #

import 'package:flutter/material.dart';
import 'package:aero_cache/aero_cache.dart';

class ImageWidget extends StatefulWidget {
  final String imageUrl;
  
  const ImageWidget({Key? key, required this.imageUrl}) : super(key: key);
  
  @override
  _ImageWidgetState createState() => _ImageWidgetState();
}

class _ImageWidgetState extends State<ImageWidget> {
  final AeroCache _cache = AeroCache();
  Uint8List? _imageData;
  bool _isLoading = true;
  double _progress = 0.0;
  
  @override
  void initState() {
    super.initState();
    _loadImage();
  }
  
  Future<void> _loadImage() async {
    try {
      await _cache.initialize();
      final data = await _cache.get(
        widget.imageUrl,
        onProgress: (received, total) {
          setState(() {
            _progress = received / total;
          });
        },
      );
      setState(() {
        _imageData = data;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
      });
      // Handle error
    }
  }
  
  @override
  Widget build(BuildContext context) {
    if (_isLoading) {
      return Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          const CircularProgressIndicator(),
          const SizedBox(height: 8),
          Text('${(_progress * 100).toInt()}%'),
        ],
      );
    }
    
    if (_imageData != null) {
      return Image.memory(_imageData!);
    }
    
    return const Icon(Icons.error);
  }
  
  @override
  void dispose() {
    _cache.dispose();
    super.dispose();
  }
}

API Reference #

AeroCache #

Constructor

AeroCache({
  HttpClient? httpClient,
  bool disableCompression = false,
  int compressionLevel = 3,
  Duration defaultCacheDuration = const Duration(days: 5),
  String? cacheDirPath,
})
  • httpClient: Optional custom HTTP client
  • disableCompression: Disable zstd compression (default: false)
  • compressionLevel: Zstd compression level 1-22 (default: 3)
  • defaultCacheDuration: Default cache duration (default: 5 days)
  • cacheDirPath: Custom cache directory path

Methods

  • Future<void> initialize(): Initialize the cache manager
  • Future<Uint8List> get(String url, {ProgressCallback? onProgress, bool noCache, int? maxAge, int? maxStale, int? minFresh, bool onlyIfCached, bool noStore, Map<String, String>? headers}): Get data from cache or download with advanced cache control
  • Future<void> clearAllCache(): Clear all cached data
  • Future<void> clearExpiredCache(): Clear expired cache entries
  • Future<MetaInfo?> metaInfo(String url): Get metadata for a URL
  • void dispose(): Dispose of resources

MetaInfo #

Contains metadata information about cached entries:

  • String? etag: ETag header value
  • String? lastModified: Last-Modified header value
  • String? contentType: Content-Type header value
  • DateTime createdAt: Cache creation time
  • DateTime expiresAt: Cache expiration time
  • int contentLength: Content length in bytes
  • bool isStale: Whether the cache entry is stale
  • bool requiresRevalidation: Whether cache requires revalidation
  • bool mustRevalidate: Whether cache must be revalidated
  • Duration? staleWhileRevalidate: Stale-while-revalidate duration
  • Duration? staleIfError: Stale-if-error duration
  • List<String>? varyHeaders: Vary header specifications

Exceptions #

  • AeroCacheException: Base exception class for cache-related errors

Performance #

AeroCache uses zstd compression by default, which provides:

  • Fast compression/decompression speeds
  • Excellent compression ratios
  • Low memory usage

Benchmarks show significant storage savings compared to uncompressed caching, especially for text-based content like JSON and HTML.

Vary Header Support #

AeroCache intelligently handles the Vary header to ensure correct cache behavior when responses depend on request headers. When a server includes a Vary header in its response, AeroCache automatically:

  • Parses the Vary header to identify which request headers affect the response
  • Incorporates relevant request header values into the cache key calculation
  • Ensures cache hits only occur when the specified request headers match exactly
  • Supports common headers like Accept-Encoding, User-Agent, Accept-Language, etc.

This ensures that cached responses are served only when appropriate, preventing issues like serving compressed content to clients that don't support compression.

Contributing #

We welcome contributions to AeroCache! Please follow the GitHub Flow process:

How to Contribute #

  1. Fork the repository on GitHub
  2. Create a feature branch from main:
    git checkout -b feature/your-feature-name
    
  3. Make your changes and add tests if applicable
  4. Ensure all tests pass:
    flutter test
    
  5. Follow the code style using very_good_analysis:
    dart analyze
    
  6. Commit your changes with a clear message:
    git commit -m "Add: your feature description"
    
  7. Push to your fork:
    git push origin feature/your-feature-name
    
  8. Create a Pull Request on GitHub with:
    • Clear description of changes
    • Reference any related issues
    • Screenshots if applicable

Development Setup #

  1. Clone the repository:

    git clone https://github.com/your-username/aero_cache.git
    cd aero_cache
    
  2. Install dependencies:

    flutter pub get
    
  3. Run tests:

    flutter test
    
  4. Run the example:

    cd example
    flutter run
    

Code Style #

  • Follow the official Dart style guide
  • Use very_good_analysis linting rules
  • Write comprehensive tests for new features
  • Add documentation for public APIs

Reporting Issues #

When reporting issues, please include:

  • Flutter/Dart version
  • Operating system
  • Steps to reproduce
  • Expected vs actual behavior
  • Code samples if applicable

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog #

See CHANGELOG.md for version history and changes.

Support #

For questions and support:

  • Check the example directory for usage examples
  • Open an issue on GitHub for bugs or feature requests
  • Review the API documentation
0
likes
0
points
16
downloads

Publisher

verified publishernikaera.com

Weekly Downloads

A high-performance HTTP caching library for Dart/Flutter with zstd compression, ETag/Last-Modified revalidation, and full Cache-Control directive support.

Repository (GitHub)
View/report issues

Topics

#lint

Documentation

Documentation

License

unknown (license)

Dependencies

crypto, flutter, path_provider, zstandard

More

Packages that depend on aero_cache