getCached method
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 — it may take its time (fetching what the
text names, say) — 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 FutureOr<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 = await 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);
}