UNPKG

@applicaster/quick-brick-core

Version:

Core package for Applicaster's Quick Brick App

146 lines (111 loc) 3.78 kB
import * as R from "ramda"; import { isTV } from "@applicaster/zapp-react-native-utils/reactUtils"; import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage"; import { deleteFolders, getNativeRootPath, } from "@applicaster/zapp-react-native-bridge/OfflineAssets"; import { log_verbose } from "./logger"; type LayoutCacheStorageData = { id: string; files: FilesList }; type AssetCacheDataStorageData = { [key in string]: LayoutCacheStorageData; }; const CACHE_DATA_KEY = "APP_ASSETS_CACHE_DATA_KEY"; const CACHE_NAMESPACE = "offline_mode"; const ASSET_FOLDERS = ["rivers", "plugins", "cellStyles"]; const getAssetsProps = (assets) => { return assets.map((asset) => { return { file: asset.file, url: asset.url, }; }); }; const diff = (arr1, arr2) => { return arr1.filter((a1) => !arr2.some((a2) => a1.url === a2.url)); }; export class CacheManager { private static _instance: CacheManager; public static get instance() { if (!CacheManager._instance) { CacheManager._instance = new CacheManager(); } return CacheManager._instance; } private _layoutId: string; private _files: { file: string; url: string }[]; async getFilesToCache( layoutId: string, assetFiles: FilesList ): Promise<{ removedFiles: FilesList; newFiles: FilesList; unchangedFiles: FilesList; }> { if (isTV()) return { removedFiles: [], newFiles: [], unchangedFiles: [] }; await this.getCacheData(layoutId); if (layoutId !== this._layoutId) { log_verbose("getFilesToCache: caching new layout id", { previousLayout: this._layoutId, requestedLayout: layoutId, numberOfAssets: assetFiles?.length, }); return { removedFiles: this._files || [], newFiles: assetFiles, unchangedFiles: [], }; } const start = performance.now(); const files = getAssetsProps(assetFiles); const removedFiles = diff(this._files, files); const newFiles = diff(files, this._files); const unchangedFiles = diff(diff(files, removedFiles), newFiles); const time = performance.now() - start; log_verbose( `getFilesToCache: getting cache diff for current layout, took ${time} ms`, { layoutId, removedFiles, newFiles, } ); return { removedFiles, newFiles, unchangedFiles }; } async clearCache(removedFiles: FilesList) { const folders = removedFiles.map((fileObj) => fileObj.file); if (folders && folders?.length > 0) { log_verbose("getFilesToCache: clearing asset cache folders", { folders }); await deleteFolders(folders); return; } log_verbose("getFilesToCache: no assets to remove from cache"); } async saveCacheData(layoutId: string, assetFiles: FilesList) { const files = getAssetsProps(assetFiles); log_verbose("getFilesToCache: saving cache data", { layoutId, files }); await localStorage.setItem( CACHE_DATA_KEY, { [layoutId]: { id: layoutId, files }, }, CACHE_NAMESPACE ); } async getCacheData(layoutId: string) { const cacheData: Maybe<AssetCacheDataStorageData> = await localStorage.getItem(CACHE_DATA_KEY, CACHE_NAMESPACE); const layoutCacheData: Maybe<LayoutCacheStorageData> = cacheData?.[layoutId] || {}; this._layoutId = layoutCacheData?.id || null; this._files = layoutCacheData?.files || null; } async deleteAllFiles() { const nativeFolder = await getNativeRootPath(); const assetfolders = R.compose(R.map(R.concat(`${nativeFolder}/`)))( ASSET_FOLDERS ); await localStorage.removeItem(CACHE_DATA_KEY, CACHE_NAMESPACE); return deleteFolders(assetfolders); } }