import * as plugins from './plugins.js'; import * as interfaces from '../dist_ts_interfaces/index.js'; import { ServiceWorker } from './classes.serviceworker.js'; import { logger } from './logging.js'; import { CacheManager } from './classes.cachemanager.js'; export class UpdateManager { public lastUpdateCheck: number = 0; public lastVersionInfo: interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo['response']; public serviceworkerRef: ServiceWorker; constructor(serviceWorkerRefArg: ServiceWorker) { this.serviceworkerRef = serviceWorkerRefArg; } /** * checks wether an update is needed */ public async checkUpdate(cacheManager: CacheManager): Promise { const lswVersionInfoKey = 'versionInfo'; if (!this.lastVersionInfo && !(await this.serviceworkerRef.store.check(lswVersionInfoKey))) { this.lastVersionInfo = { appHash: '', appSemVer: 'v0.0.0', }; } else if ( !this.lastVersionInfo && (await this.serviceworkerRef.store.check(lswVersionInfoKey)) ) { this.lastVersionInfo = await this.serviceworkerRef.store.get(lswVersionInfoKey); } const now = Date.now(); const millisSinceLastCheck = now - this.lastUpdateCheck; if (millisSinceLastCheck < 100000) { // TODO account for being offline return false; } logger.log('info', 'checking for update of the app by comparing app hashes...'); this.lastUpdateCheck = now; const currentVersionInfo = await this.getVersionInfoFromServer(); logger.log('info', `old versionInfo: ${JSON.stringify(this.lastVersionInfo)}`); logger.log('info', `current versionInfo: ${JSON.stringify(currentVersionInfo)}`); const needsUpdate = this.lastVersionInfo.appHash !== currentVersionInfo.appHash ? true : false; if (needsUpdate) { logger.log('info', 'Caches need to be updated'); logger.log('info', 'starting a debounced update task'); this.performAsyncUpdateDebouncedTask.trigger(); this.lastVersionInfo = currentVersionInfo; await this.serviceworkerRef.store.set(lswVersionInfoKey, this.lastVersionInfo); } else { logger.log('ok', 'caches are still valid, performing revalidation in a bit...'); this.performAsyncCacheRevalidationDebouncedTask.trigger(); } } /** * gets the apphash from the server */ public async getVersionInfoFromServer() { const getAppHashRequest = new plugins.typedrequest.TypedRequest< interfaces.serviceworker.IRequest_Serviceworker_Backend_VersionInfo >('/sw-typedrequest', 'serviceworker_versionInfo'); const result = await getAppHashRequest.fire({}); return result; } // tasks /** * this task is executed once we know that there is a new version available */ public performAsyncUpdateDebouncedTask = new plugins.taskbuffer.TaskDebounced({ name: 'performAsyncUpdate', taskFunction: async () => { logger.log('info', 'trying to update PWA with serviceworker'); await this.serviceworkerRef.cacheManager.cleanCaches('a new app version has been communicated by the server.'); // lets notify all current clients about the update await this.serviceworkerRef.leleServiceWorkerBackend.triggerReloadAll(); }, debounceTimeInMillis: 2000, }); public performAsyncCacheRevalidationDebouncedTask = new plugins.taskbuffer.TaskDebounced({ name: 'performAsyncCacheRevalidation', taskFunction: async () => { await this.serviceworkerRef.cacheManager.revalidateCache(); }, debounceTimeInMillis: 6000 }); }