getCached method

Future<CachedText> getCached(
  1. Uri uri, {
  2. required File? cache,
  3. required String decode(
    1. Uint8List bytes
    ),
  4. bool refresh = false,
  5. int? maxBytes,
  6. CancelToken? cancel,
})

The text at uri, kept in cache (with its ETag beside it) so an unchanged file costs one small request and the last copy still reads offline. refresh asks again even when the copy would do. decode turns the bytes into text, and may throw an Exception to refuse them; the cached copy is then used, as when offline.

The text may be maxBytes long (defaultMaxTextBytes when null); cancel stops the request (a cancelled one never falls back on the cached copy).

Throws what get or decode throws when there is no cached copy to fall back on.

Implementation

Future<CachedText> getCached(
  Uri uri, {
  required File? cache,
  required String Function(Uint8List bytes) decode,
  bool refresh = false,
  int? maxBytes,
  CancelToken? cancel,
}) async {
  final cached = cache == null ? null : _readCache(cache);
  final etag = refresh ? null : cached?.etag;
  final FetchResponse response;
  try {
    response = await get(
      uri,
      headers: {'If-None-Match': ?etag},
      maxBytes: maxBytes ?? defaultMaxTextBytes,
      cancel: cancel,
    );
  } on Object catch (e) {
    if (e is! FetchException && e is! IOException && e is! TimeoutException) {
      rethrow;
    }
    if (cached != null) {
      return CachedText(cached.text, offline: true, error: e);
    }
    rethrow;
  }
  if (response.status == HttpStatus.notModified && cached != null) {
    return CachedText(cached.text);
  }
  final String text;
  try {
    text = decode(response.body);
  } on Exception catch (e) {
    // A captive portal's page, or a half-published catalog: the last good
    // copy is better than nothing.
    if (cached != null) {
      return CachedText(cached.text, offline: true, error: e);
    }
    rethrow;
  }
  if (cache != null) _writeCache(cache, text, response.etag);
  return CachedText(text);
}