Skip to content

Commit

Permalink
Added FMTCTileProviderSettings.fallbackToAlternativeStore
Browse files Browse the repository at this point in the history
  • Loading branch information
JaffaKetchup committed Feb 25, 2024
1 parent f973da8 commit feaa712
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 25 deletions.
2 changes: 0 additions & 2 deletions lib/src/bulk_download/thread.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ Future<void> _singleDownloadThread(
obscuredQueryParams: input.obscuredQueryParams,
);

// TODO: Work across stores in the event of an error
final existingTile = await input.backend.readTile(
url: matcherUrl,
storeName: input.storeName,
Expand Down Expand Up @@ -136,7 +135,6 @@ Future<void> _singleDownloadThread(
}

// Write tile directly to database or place in buffer queue
//final tile = DbTile(url: matcherUrl, bytes: response.bodyBytes);
if (input.maxBufferLength == 0) {
await input.backend.htWriteTile(
storeName: input.storeName,
Expand Down
3 changes: 1 addition & 2 deletions lib/src/bulk_download/tile_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ enum TileEventResultCategory {
cached,

/// The associated tile may have been downloaded, but was not cached
/// intentionally
///
/// This may be because it:
/// - already existed & `skipExistingTiles` was `true`:
Expand All @@ -20,7 +19,7 @@ enum TileEventResultCategory {
skipped,

/// The associated tile was not successfully downloaded, potentially for a
/// variety of reasons.
/// variety of reasons
///
/// Category for [TileEventResult.negativeFetchResponse],
/// [TileEventResult.noConnectionDuringFetch], and
Expand Down
30 changes: 29 additions & 1 deletion lib/src/providers/image_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,26 @@ class FMTCImageProvider extends ImageProvider<FMTCImageProvider> {
return decode(await ImmutableBuffer.fromUint8List(bytes));
}

// TODO: Test
Future<Codec?> attemptFinishViaAltStore(String matcherUrl) async {
if (provider.settings.fallbackToAlternativeStore) {
final existingTileAltStore =
await FMTCBackendAccess.internal.readTile(url: matcherUrl);
if (existingTileAltStore == null) return null;
return finishSuccessfully(
bytes: existingTileAltStore.bytes,
cacheHit: false,
);
}
return null;
}

final networkUrl = provider.getTileUrl(coords, options);
final matcherUrl = obscureQueryParams(
url: networkUrl,
obscuredQueryParams: provider.settings.obscuredQueryParams,
);

// TODO: Work across stores in event of error
final existingTile = await FMTCBackendAccess.internal.readTile(
url: matcherUrl,
storeName: storeName,
Expand Down Expand Up @@ -119,6 +132,9 @@ class FMTCImageProvider extends ImageProvider<FMTCImageProvider> {
// before attempting a network call
if (provider.settings.behavior == CacheBehavior.cacheOnly &&
needsCreating) {
final codec = await attemptFinishViaAltStore(matcherUrl);
if (codec != null) return codec;

return finishWithError(
FMTCBrowsingError(
type: FMTCBrowsingErrorType.missingInCacheOnlyMode,
Expand All @@ -138,6 +154,10 @@ class FMTCImageProvider extends ImageProvider<FMTCImageProvider> {
if (!needsCreating) {
return finishSuccessfully(bytes: bytes!, cacheHit: false);
}

final codec = await attemptFinishViaAltStore(matcherUrl);
if (codec != null) return codec;

return finishWithError(
FMTCBrowsingError(
type: e is SocketException
Expand All @@ -156,6 +176,10 @@ class FMTCImageProvider extends ImageProvider<FMTCImageProvider> {
if (!needsCreating) {
return finishSuccessfully(bytes: bytes!, cacheHit: false);
}

final codec = await attemptFinishViaAltStore(matcherUrl);
if (codec != null) return codec;

return finishWithError(
FMTCBrowsingError(
type: FMTCBrowsingErrorType.negativeFetchResponse,
Expand Down Expand Up @@ -200,6 +224,10 @@ class FMTCImageProvider extends ImageProvider<FMTCImageProvider> {
if (!needsCreating) {
return finishSuccessfully(bytes: bytes!, cacheHit: false);
}

final codec = await attemptFinishViaAltStore(matcherUrl);
if (codec != null) return codec;

return finishWithError(
FMTCBrowsingError(
type: FMTCBrowsingErrorType.invalidImageData,
Expand Down
73 changes: 53 additions & 20 deletions lib/src/providers/tile_provider_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,48 +6,71 @@ part of flutter_map_tile_caching;
/// Callback type that takes an [FMTCBrowsingError] exception
typedef FMTCBrowsingErrorHandler = void Function(FMTCBrowsingError exception);

/// Behaviours dictating how and when browse caching should be carried out
/// Behaviours dictating how and when browse caching should occur
///
/// An online only behaviour is not available: use a default [TileProvider] to
/// achieve this.
enum CacheBehavior {
/// Only get tiles from the local cache
///
/// Throws [FMTCBrowsingErrorType.missingInCacheOnlyMode] if a tile is not
/// available.
/// Throws [FMTCBrowsingErrorType.missingInCacheOnlyMode] if a tile is
/// unavailable.
///
/// If [FMTCTileProviderSettings.fallbackToAlternativeStore] is enabled, cached
/// tiles may also be taken from other stores.
cacheOnly,

/// Get tiles from the local cache, only using the network to update the cached
/// tile if it has expired ([FMTCTileProviderSettings.cachedValidDuration] has
/// passed)
/// Retrieve tiles from the cache, only using the network to update the cached
/// tile if it has expired
///
/// Falls back to using cached tiles if the network is not available.
///
/// If [FMTCTileProviderSettings.fallbackToAlternativeStore] is enabled, and
/// the network is unavailable, cached tiles may also be taken from other
/// stores.
cacheFirst,

/// Get tiles from the network where possible, and update the cached tiles
///
/// Safely falls back to using cached tiles if the network is not available.
/// Falls back to using cached tiles if the network is unavailable.
///
/// If [FMTCTileProviderSettings.fallbackToAlternativeStore] is enabled, cached
/// tiles may also be taken from other stores.
onlineFirst,
}

/// Settings for an [FMTCTileProvider]
class FMTCTileProviderSettings {
/// Create new settings for an [FMTCTileProvider], and set the [instance]
/// Create new settings for an [FMTCTileProvider], and set the [instance] (if
/// [setInstance] is `true`, as default)
///
/// To access the existing settings, if any, get [instance].
factory FMTCTileProviderSettings({
CacheBehavior behavior = CacheBehavior.cacheFirst,
bool fallbackToAlternativeStore = true,
Duration cachedValidDuration = const Duration(days: 16),
int maxStoreLength = 0,
List<String> obscuredQueryParams = const [],
FMTCBrowsingErrorHandler? errorHandler,
}) =>
_instance = FMTCTileProviderSettings._(
behavior: behavior,
cachedValidDuration: cachedValidDuration,
maxStoreLength: maxStoreLength,
obscuredQueryParams: obscuredQueryParams.map((e) => RegExp('$e=[^&]*')),
errorHandler: errorHandler,
);
bool setInstance = true,
}) {
final settings = FMTCTileProviderSettings._(
behavior: behavior,
fallbackToAlternativeStore: fallbackToAlternativeStore,
cachedValidDuration: cachedValidDuration,
maxStoreLength: maxStoreLength,
obscuredQueryParams: obscuredQueryParams.map((e) => RegExp('$e=[^&]*')),
errorHandler: errorHandler,
);

if (setInstance) _instance = settings;
return settings;
}

FMTCTileProviderSettings._({
required this.behavior,
required this.cachedValidDuration,
required this.fallbackToAlternativeStore,
required this.maxStoreLength,
required this.obscuredQueryParams,
required this.errorHandler,
Expand All @@ -58,13 +81,23 @@ class FMTCTileProviderSettings {
static FMTCTileProviderSettings get instance => _instance;
static var _instance = FMTCTileProviderSettings();

/// The behavior method to get and cache a tile
/// The behaviour to use when retrieving and writing tiles when browsing
///
/// Defaults to [CacheBehavior.cacheFirst] - get tiles from the local cache,
/// going on the Internet to update the cached tile if it has expired
/// ([cachedValidDuration] has passed).
/// Defaults to [CacheBehavior.cacheFirst].
final CacheBehavior behavior;

/// Whether to retrieve a tile from another store if it exists, as a fallback,
/// instead of throwing an error
///
/// Does not add tiles taken from other stores to the specified store.
///
/// When tiles are retrieved from other stores, it is counted as a miss for the
/// specified store.
///
/// See details on [CacheBehavior] for information. Fallback to an alternative
/// store is always the last-resort option before throwing an error.
final bool fallbackToAlternativeStore;

/// The duration until a tile expires and needs to be fetched again when
/// browsing. Also called `validDuration`.
///
Expand Down

0 comments on commit feaa712

Please sign in to comment.