Skip to content

Commit

Permalink
Merge branch 'offline'
Browse files Browse the repository at this point in the history
  • Loading branch information
claustres committed Nov 11, 2024
2 parents 6d46fff + 609ffef commit fcf30bd
Show file tree
Hide file tree
Showing 10 changed files with 596 additions and 338 deletions.
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"@kalisio/leaflet-pmtiles": "https://github.com/kalisio/leaflet-pmtiles",
"@kalisio/leaflet.donutcluster": "^1.1.0",
"@mapbox/geojsonhint": "^3.0.1",
"@mapbox/sphericalmercator": "^1.2.0",
"@pdfme/common": "^4.1.0",
"@pdfme/generator": "^4.1.0",
"@pdfme/schemas": "^4.1.0",
Expand All @@ -116,7 +117,8 @@
"@turf/distance": "^6.0.0",
"@turf/explode": "^6.2.0-alpha.2",
"@turf/flatten": "^6.0.0",
"@turf/helpers": "^6.0.0",
"@turf/helpers": "^7.0.0",
"@turf/intersect": "^7.0.0",
"@turf/invariant": "^6.0.0",
"@turf/kinks": "^6.0.0",
"@turf/length": "^6.0.0",
Expand Down Expand Up @@ -171,6 +173,7 @@
"leaflet.locatecontrol": "^0.69.0",
"leaflet.markercluster": "1.1.0",
"leaflet.vectorgrid": "^1.3.0",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
"loglevel": "^1.8.0",
"mapillary-js": "^4.0.0",
Expand All @@ -183,6 +186,7 @@
"path-browserify": "^1.0.1",
"pinch-zoom-element": "^1.1.1",
"pixi.js": "5.3.10",
"pmtiles": "^3.0.7",
"post-robot": "10.0.42",
"protomaps-leaflet": "^3.1.2",
"quasar": "^2.12.0",
Expand Down
File renamed without changes.
File renamed without changes.
60 changes: 60 additions & 0 deletions public/iframe/dependencies/turf.min.js

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions public/iframe/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">

<title>Kano IFrame integration</title>
<link rel="shortcut icon" type="image/x-icon" href="iframe/kano-icon-32x32.png">
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script>
<link rel="shortcut icon" type="image/x-icon" href="../icons/kano-icon-32x32.png">
<script src="./flightpath.js"></script>
<script src="./flightradar.js"></script>
<script src="./post-robot.min.js"></script>
<script src="./chroma.min.js"></script>
<script src='./dependencies/turf.min.js'></script>
<script src="./dependencies/post-robot.min.js"></script>
<script src="./dependencies/chroma.min.js"></script>
<script>
var layerIsShown = false
var component = 'map'
Expand Down
4 changes: 2 additions & 2 deletions quasar.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,8 @@ module.exports = configure(function (ctx) {
// https://v2.quasar.dev/quasar-cli-webpack/developing-pwa/configuring-pwa
pwa: {
workboxPluginMode: 'InjectManifest', // 'GenerateSW' or 'InjectManifest'
workboxOptions: { // only for
maximumFileSizeToCacheInBytes: 30 * 1024 * 1024
workboxOptions: { // Large file size allowed for eg not minimized vendor file in dev mode
maximumFileSizeToCacheInBytes: 50 * 1024 * 1024
},

// for the custom service worker ONLY (/src-pwa/custom-service-worker.[js|ts])
Expand Down
86 changes: 81 additions & 5 deletions src-pwa/custom-service-worker.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { precacheAndRoute } from 'workbox-precaching'
import { registerRoute } from 'workbox-routing'
import { NetworkFirst } from 'workbox-strategies'
import { NetworkFirst, CacheFirst } from 'workbox-strategies'
import { ExpirationPlugin } from 'workbox-expiration'
import logger from 'loglevel'
import { LocalForage } from '@kalisio/feathers-localforage'
// Ensure same underlying configuration as we are in another process and instance may differ
LocalForage.config({
name: 'offline_cache',
storeName: 'cache_entries'
})

let cachedUrls
let updatingCachedUrls = false
// Disable workbox logs
self.__WB_DISABLE_DEV_LOGS = true

Expand All @@ -12,11 +22,77 @@ self.addEventListener('message', event => {
}
})

// As route function cannot be async and localforage is, we have to retrieve
// the cached layer list on a reccurent basis to be able to respond synchronously
setInterval(async () => {
// Avoid reentrance in any case
if (updatingCachedUrls) return
updatingCachedUrls = true
cachedUrls = new Map()
await LocalForage.iterate((value, key) => {
cachedUrls.set(key, value)
})
updatingCachedUrls = false
}, 1000)

// Caching for offline mode
// Preload and cache all resources defined in the manifest
precacheAndRoute(self.__WB_MANIFEST)
// Register the `NetworkFirst` caching strategy for all HTTP requests

async function cacheKeyWillBeUsed({ request, mode }) {
const url = new URL(request.url)
url.searchParams.delete('jwt')
const key = url.href
// Need to add range request in key as it is ignored by cache otherwise
if (request.headers && request.headers.Range) {
const range = request.headers.Range.replace('bytes=', '').split('-')
key += `/${range[0]}/${range[1]}`
}
return key
}

async function fetchDidFail({ error, request }) {
logger.debug(`[Kano] Fetching ${request.url} from layers cache failed`)
}

// Register the `CacheFirst` caching strategy for offline data
// targetting layers data
registerRoute(
({url, request}) => {
let key = new URL(url.href)
key.searchParams.delete('jwt')
key = key.href
if (request.headers && request.headers.Range) {
const range = request.headers.Range.replace('bytes=', '').split('-')
key += `/${range[0]}/${range[1]}`
}
const isCached = cachedUrls && cachedUrls.has(key)
if (isCached) {
logger.debug(`[Kano] Return response for ${url.href} from layers cache`)
}
return isCached
},
new CacheFirst({
cacheName: 'layers',
plugins : [{ cacheKeyWillBeUsed, fetchDidFail }]
})
)
// Register the `NetworkFirst` caching strategy for all others HTTP requests
registerRoute(
({url}) => url.href.startsWith('http'),
new NetworkFirst()
)
({url}) => {
return url.href.startsWith('http')
},
new NetworkFirst({
cacheName: 'app',
plugins: [
new ExpirationPlugin({
// Keep at most N entries.
maxEntries: 1000000,
// Don't keep any entries for more than N days.
maxAgeSeconds: 30 * (24 * 60 * 60),
// Automatically cleanup if quota is exceeded.
purgeOnQuotaError: true
})
]
})
)
8 changes: 6 additions & 2 deletions src/boot/kdk.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ export default async ({ app, router }) => {
})
// Event bus dispatch
postRobot.on('event', async (event) => {
// Does not make any sense in disconnected mode
if (api.isDisconnected) return
const result = await serviceOperation({
operation: 'create',
service: 'events',
Expand All @@ -139,8 +141,10 @@ export default async ({ app, router }) => {
})
})
// Listen to websocket events
Events.on('disconnected', () => utils.sendEmbedEvent('kano-disconnected'))
Events.on('reconnected', () => utils.sendEmbedEvent('kano-reconnected'))
Events.on('navigator-disconnected', () => utils.sendEmbedEvent('kano-disconnected'))
Events.on('navigator-reconnected', () => utils.sendEmbedEvent('kano-reconnected'))
Events.on('websocket-disconnected', () => utils.sendEmbedEvent('kano-disconnected'))
Events.on('websocket-reconnected', () => utils.sendEmbedEvent('kano-reconnected'))

await utils.sendEmbedEvent('api-ready')

Expand Down
5 changes: 4 additions & 1 deletion src/services/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import logger from 'loglevel'
import kdkCore from '@kalisio/kdk/core.client'
import kdkMap from '@kalisio/kdk/map.client.map'
import kdkMap, { utils as kMapUtils } from '@kalisio/kdk/map.client.map'

export default async function () {
const api = this
Expand All @@ -9,12 +9,15 @@ export default async function () {
try {
await api.configure(kdkCore)
await api.configure(kdkMap)

// TODO we use createService because of the custom methods
// https://github.com/kalisio/kdk/issues/781
api.createService('events', { methods: ['create'], events: ['event'] })
// Restore previous settings if any
const settingsService = api.getService('settings')
if (settingsService) settingsService.restoreSettings()
// Create required services for offline mode
kMapUtils.createOfflineServices()
} catch (error) {
logger.error(error.message)
}
Expand Down
Loading

0 comments on commit fcf30bd

Please sign in to comment.