From 620d174e9bbe24f12fc2ebe07bb454b537721d41 Mon Sep 17 00:00:00 2001 From: static Date: Fri, 17 Jan 2025 13:02:21 +0900 Subject: [PATCH] =?UTF-8?q?=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8?= =?UTF-8?q?=EA=B0=80=20=EC=8B=9C=EC=9E=91=EB=90=A0=20=EB=95=8C=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=EB=90=9C=20=ED=8C=8C=EC=9D=BC=EC=9D=B4=EB=82=98=20?= =?UTF-8?q?=EB=94=94=EB=A0=89=ED=84=B0=EB=A6=AC=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EB=A5=BC=20IndexedDB=EC=97=90=EC=84=9C=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks.client.ts | 4 +++- src/lib/indexedDB/filesystem.ts | 34 +++++++++++++++++++++++++++++++++ src/lib/modules/filesystem.ts | 20 ++++++++++++++++--- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/hooks.client.ts b/src/hooks.client.ts index d947c8e..ec6f620 100644 --- a/src/hooks.client.ts +++ b/src/hooks.client.ts @@ -1,5 +1,5 @@ import type { ClientInit } from "@sveltejs/kit"; -import { getClientKey, getMasterKeys, getHmacSecrets } from "$lib/indexedDB"; +import { cleanupDanglingInfos, getClientKey, getMasterKeys, getHmacSecrets } from "$lib/indexedDB"; import { prepareFileCache } from "$lib/modules/file"; import { prepareOpfs } from "$lib/modules/opfs"; import { clientKeyStore, masterKeyStore, hmacSecretStore } from "$lib/stores"; @@ -38,4 +38,6 @@ export const init: ClientInit = async () => { prepareHmacSecretStore(), prepareOpfs(), ]); + + cleanupDanglingInfos(); // Intended }; diff --git a/src/lib/indexedDB/filesystem.ts b/src/lib/indexedDB/filesystem.ts index a6567ff..5c9fc4d 100644 --- a/src/lib/indexedDB/filesystem.ts +++ b/src/lib/indexedDB/filesystem.ts @@ -39,6 +39,10 @@ export const storeDirectoryInfo = async (directoryInfo: DirectoryInfo) => { await filesystem.directory.put(directoryInfo); }; +export const deleteDirectoryInfo = async (id: number) => { + await filesystem.directory.delete(id); +}; + export const getFileInfos = async (parentId: DirectoryId) => { return await filesystem.file.where({ parentId }).toArray(); }; @@ -50,3 +54,33 @@ export const getFileInfo = async (id: number) => { export const storeFileInfo = async (fileInfo: FileInfo) => { await filesystem.file.put(fileInfo); }; + +export const deleteFileInfo = async (id: number) => { + await filesystem.file.delete(id); +}; + +export const cleanupDanglingInfos = async () => { + const validDirectoryIds: number[] = []; + const validFileIds: number[] = []; + const queue: DirectoryId[] = ["root"]; + + while (true) { + const directoryId = queue.shift(); + if (!directoryId) break; + + const [subDirectories, files] = await Promise.all([ + filesystem.directory.where({ parentId: directoryId }).toArray(), + filesystem.file.where({ parentId: directoryId }).toArray(), + ]); + subDirectories.forEach(({ id }) => { + validDirectoryIds.push(id); + queue.push(id); + }); + files.forEach(({ id }) => validFileIds.push(id)); + } + + await Promise.all([ + filesystem.directory.where("id").noneOf(validDirectoryIds).delete(), + filesystem.file.where("id").noneOf(validFileIds).delete(), + ]); +}; diff --git a/src/lib/modules/filesystem.ts b/src/lib/modules/filesystem.ts index e1c929e..7313cb5 100644 --- a/src/lib/modules/filesystem.ts +++ b/src/lib/modules/filesystem.ts @@ -4,9 +4,11 @@ import { getDirectoryInfos as getDirectoryInfosFromIndexedDB, getDirectoryInfo as getDirectoryInfoFromIndexedDB, storeDirectoryInfo, + deleteDirectoryInfo, getFileInfos as getFileInfosFromIndexedDB, getFileInfo as getFileInfoFromIndexedDB, storeFileInfo, + deleteFileInfo, type DirectoryId, } from "$lib/indexedDB"; import { unwrapDataKey, decryptString } from "$lib/modules/crypto"; @@ -72,7 +74,13 @@ const fetchDirectoryInfoFromServer = async ( masterKey: CryptoKey, ) => { const res = await callGetApi(`/api/directory/${id}`); - if (!res.ok) throw new Error("Failed to fetch directory information"); // TODO: Handle 404 + if (res.status === 404) { + info.set(null); + await deleteDirectoryInfo(id as number); + } else if (!res.ok) { + throw new Error("Failed to fetch directory information"); + } + const { metadata, subDirectories: subDirectoryIds, @@ -138,10 +146,16 @@ const fetchFileInfoFromServer = async ( masterKey: CryptoKey, ) => { const res = await callGetApi(`/api/file/${id}`); - if (!res.ok) throw new Error("Failed to fetch file information"); // TODO: Handle 404 - const metadata: FileInfoResponse = await res.json(); + if (res.status === 404) { + info.set(null); + await deleteFileInfo(id); + } else if (!res.ok) { + throw new Error("Failed to fetch file information"); + } + const metadata: FileInfoResponse = await res.json(); const { dataKey } = await unwrapDataKey(metadata.dek, masterKey); + const name = await decryptString(metadata.name, metadata.nameIv, dataKey); const createdAt = metadata.createdAt && metadata.createdAtIv