Files
TREK/client/src/native/tileCache.ts
T

74 lines
2.9 KiB
TypeScript

import { hasNativeFeature } from './capabilities';
import { GL_MAPS_THROUGH_APP_SCHEMES } from './glSchemes';
import { isNativeApp, isNativeIos } from './platform';
/**
* The iOS app's own tile store (TrekTileSchemeHandler.swift), reached through
* the trek-tile:// scheme.
*
* WKWebView runs no service worker for a self-hosted server, so on iOS nothing
* kept the map tiles a user had looked at. Binaries that report the tileCache
* feature serve every trek-tile:// request from a store on disk, filled as the
* tiles are viewed and kept for at most 30 days (Mapbox's limit for a device
* cache, applied to every provider alike), and from the network otherwise. The
* URL keeps its host and path, only the scheme changes, so the handler knows
* where the tile really lives.
*
* Nothing is prefetched through here: Mapbox forbids bulk downloads, and the
* OpenFreeMap region a trip stores goes through Cache Storage (offlineTiles.ts).
*/
const TILE_CACHE_SCHEME = 'trek-tile';
/**
* Whether the app keeps the Mapbox map's resources itself, so a Mapbox map works
* offline where it was viewed. On Android the app's WebView client takes those
* requests as they are (tiles/TrekTileStore.kt), so only iOS rewrites URLs.
*/
export function tileCacheActive(): boolean {
return isNativeApp() && hasNativeFeature('tileCache');
}
/** Whether a GL map keeps what it showed in the store (see glSchemes.ts for why not, for now). */
export function glTileStoreActive(): boolean {
return GL_MAPS_THROUGH_APP_SCHEMES && tileSchemeActive();
}
/** Whether URLs go through the trek-tile:// scheme: the iOS store only. */
function tileSchemeActive(): boolean {
return isNativeIos() && hasNativeFeature('tileCache');
}
/** https://host/path?query -> trek-tile://host/path?query. Anything else stays. */
export function toTileCacheUrl(url: string): string {
return url.startsWith('https://') ? `${TILE_CACHE_SCHEME}://${url.slice('https://'.length)}` : url;
}
/** A raster tile template for Leaflet, through the store where the app has one. */
export function nativeRasterTemplate(template: string): string {
return tileSchemeActive() ? toTileCacheUrl(template) : template;
}
const MAPBOX_HOST = /^https:\/\/(?:api\.mapbox\.com|[a-z0-9-]+\.tiles\.mapbox\.com)\//i;
/** What a map draws; telemetry and anything else keeps going straight out. */
const CACHED_RESOURCES = new Set([
'Style',
'Source',
'Tile',
'Glyphs',
'SpriteImage',
'SpriteJSON',
'Image',
'Iconset',
'Model',
]);
/**
* Mapbox GL's transformRequest for the iOS app: the map's own resources from
* Mapbox's servers go through the store, events and sessions never do.
*/
export function mapboxTileCacheRequest(url: string, resourceType?: string): { url: string } {
if (!glTileStoreActive() || !MAPBOX_HOST.test(url)) return { url };
if (resourceType && !CACHED_RESOURCES.has(resourceType)) return { url };
return { url: toTileCacheUrl(url) };
}