diff --git a/fission/src/mirabuf/MirabufLoader.ts b/fission/src/mirabuf/MirabufLoader.ts index 00c0068733..1355d9e38c 100644 --- a/fission/src/mirabuf/MirabufLoader.ts +++ b/fission/src/mirabuf/MirabufLoader.ts @@ -21,7 +21,7 @@ export interface MirabufRemoteInfo { src: string } -type MiraCache = { [id: string]: MirabufCacheInfo } +type MapCache = { [id: MirabufCacheID]: MirabufCacheInfo } const robotsDirName = "Robots" const fieldsDirName = "Fields" @@ -29,6 +29,33 @@ const root = await navigator.storage.getDirectory() const robotFolderHandle = await root.getDirectoryHandle(robotsDirName, { create: true }) const fieldFolderHandle = await root.getDirectoryHandle(fieldsDirName, { create: true }) +export const backUpRobots: Map = new Map() +export const backUpFields: Map = new Map() + +const canOPFS = await (async () => { + try { + if (robotFolderHandle.name == robotsDirName) { + robotFolderHandle.entries + robotFolderHandle.keys + + const fileHandle = await robotFolderHandle.getFileHandle("0", { create: true }) + const writable = await fileHandle.createWritable() + await writable.close() + await fileHandle.getFile() + + robotFolderHandle.removeEntry(fileHandle.name) + + return true + } else { + console.log(`No access to OPFS`) + return false + } + } catch (e) { + console.log(`No access to OPFS`) + return false + } +})() + export function UnzipMira(buff: Uint8Array): Uint8Array { // Check if file is gzipped via magic gzip numbers 31 139 if (buff[0] == 31 && buff[1] == 139) { @@ -42,11 +69,11 @@ class MirabufCachingService { /** * Get the map of mirabuf keys and paired MirabufCacheInfo from local storage * - * @param {MiraType} miraType Type of Mirabuf Assembly. + * @param {MiraType} miraType Type of Mirabuf Assembly * - * @returns {MiraCache} Map of cached keys and paired MirabufCacheInfo + * @returns {MapCache} Map of cached keys and paired MirabufCacheInfo */ - public static GetCacheMap(miraType: MiraType): MiraCache { + public static GetCacheMap(miraType: MiraType): MapCache { if ( (window.localStorage.getItem(MIRABUF_LOCALSTORAGE_GENERATION_KEY) ?? "") == MIRABUF_LOCALSTORAGE_GENERATION ) { @@ -159,18 +186,18 @@ class MirabufCachingService { thumbnailStorageID?: string ): Promise { try { - const map: MiraCache = this.GetCacheMap(miraType) + const map: MapCache = this.GetCacheMap(miraType) const id = map[key].id const _name = map[key].name const _thumbnailStorageID = map[key].thumbnailStorageID - const hi: MirabufCacheInfo = { + const info: MirabufCacheInfo = { id: id, cacheKey: key, miraType: miraType, name: name ?? _name, thumbnailStorageID: thumbnailStorageID ?? _thumbnailStorageID, } - map[key] = hi + map[key] = info window.localStorage.setItem(miraType == MiraType.ROBOT ? robotsDirName : fieldsDirName, JSON.stringify(map)) return true } catch (e) { @@ -213,16 +240,21 @@ class MirabufCachingService { */ public static async Get(id: MirabufCacheID, miraType: MiraType): Promise { try { - const fileHandle = await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle( - id, - { - create: false, - } - ) - - // Get assembly from file - if (fileHandle) { - const buff = await fileHandle.getFile().then(x => x.arrayBuffer()) + // Get buffer from hashMap. If not in hashMap, check OPFS. Otherwise, buff is undefined + const cache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + const buff = + cache.get(id) ?? + (await (async () => { + const fileHandle = canOPFS + ? await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle(id, { + create: false, + }) + : undefined + return fileHandle ? await fileHandle.getFile().then(x => x.arrayBuffer()) : undefined + })()) + + // If we have buffer, get assembly + if (buff) { const assembly = this.AssemblyFromBuffer(buff) World.AnalyticsSystem?.Event("Cache Get", { key: id, @@ -232,11 +264,10 @@ class MirabufCachingService { }) return assembly } else { - console.error(`Failed to get file handle for ID: ${id}`) - return undefined + console.error(`Failed to find arrayBuffer for id: ${id}`) } } catch (e) { - console.error(`Failed to find file from OPFS\n${e}`) + console.error(`Failed to find file\n${e}`) return undefined } } @@ -261,8 +292,15 @@ class MirabufCachingService { ) } - const dir = miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle - await dir.removeEntry(id) + if (canOPFS) { + const dir = miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle + await dir.removeEntry(id) + } + + const backUpCache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + if (backUpCache) { + backUpCache.delete(id) + } World.AnalyticsSystem?.Event("Cache Remove", { key: key, @@ -289,6 +327,9 @@ class MirabufCachingService { window.localStorage.removeItem(robotsDirName) window.localStorage.removeItem(fieldsDirName) + + backUpRobots.clear() + backUpFields.clear() } // Optional name for when assembly is being decoded anyway like in CacheAndGetLocal() @@ -298,7 +339,6 @@ class MirabufCachingService { miraType?: MiraType, name?: string ): Promise { - // Store in OPFS const backupID = Date.now().toString() try { if (!miraType) { @@ -306,16 +346,8 @@ class MirabufCachingService { miraType = this.AssemblyFromBuffer(miraBuff).dynamic ? MiraType.ROBOT : MiraType.FIELD } - const fileHandle = await (miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle).getFileHandle( - backupID, - { create: true } - ) - const writable = await fileHandle.createWritable() - await writable.write(miraBuff) - await writable.close() - // Local cache map - const map: MiraCache = this.GetCacheMap(miraType) + const map: MapCache = this.GetCacheMap(miraType) const info: MirabufCacheInfo = { id: backupID, cacheKey: key, @@ -331,6 +363,22 @@ class MirabufCachingService { type: miraType == MiraType.ROBOT ? "robot" : "field", fileSize: miraBuff.byteLength, }) + + // Store buffer + if (canOPFS) { + // Store in OPFS + const fileHandle = await ( + miraType == MiraType.ROBOT ? robotFolderHandle : fieldFolderHandle + ).getFileHandle(backupID, { create: true }) + const writable = await fileHandle.createWritable() + await writable.write(miraBuff) + await writable.close() + } + + // Store in hash + const cache = miraType == MiraType.ROBOT ? backUpRobots : backUpFields + cache.set(backupID, miraBuff) + return info } catch (e) { console.error("Failed to cache mira " + e) @@ -353,7 +401,7 @@ class MirabufCachingService { export enum MiraType { ROBOT = 1, - FIELD = 2, + FIELD, } export default MirabufCachingService diff --git a/fission/src/mirabuf/MirabufParser.ts b/fission/src/mirabuf/MirabufParser.ts index dd7df1e7cf..7dab72156b 100644 --- a/fission/src/mirabuf/MirabufParser.ts +++ b/fission/src/mirabuf/MirabufParser.ts @@ -240,7 +240,6 @@ class MirabufParser { console.log("Failed to get part definitions") return } - console.log(partDefinitions) } private NewRigidNode(suffix?: string): RigidNode { diff --git a/fission/src/ui/panels/DebugPanel.tsx b/fission/src/ui/panels/DebugPanel.tsx index 3daebda498..e94cdedd03 100644 --- a/fission/src/ui/panels/DebugPanel.tsx +++ b/fission/src/ui/panels/DebugPanel.tsx @@ -6,7 +6,11 @@ import WPILibBrain from "@/systems/simulation/wpilib_brain/WPILibBrain" import { MainHUD_AddToast } from "../components/MainHUD" import { ToastType } from "../ToastContext" import { Random } from "@/util/Random" -import MirabufCachingService, { MiraType } from "@/mirabuf/MirabufLoader" +import MirabufCachingService, { + backUpFields as hashedMiraFields, + backUpRobots as hashedMiraRobots, + MiraType, +} from "@/mirabuf/MirabufLoader" import { Box, styled } from "@mui/material" import { usePanelControlContext } from "../PanelContext" import APS from "@/aps/APS" @@ -113,6 +117,8 @@ const DebugPanel: React.FC = ({ panelId }) => { onClick={() => { console.log(MirabufCachingService.GetCacheMap(MiraType.ROBOT)) console.log(MirabufCachingService.GetCacheMap(MiraType.FIELD)) + console.log(hashedMiraRobots) + console.log(hashedMiraFields) }} />