@applicaster/quick-brick-core
Version:
Core package for Applicaster's Quick Brick App
146 lines (111 loc) • 3.78 kB
text/typescript
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);
}
}