From 007e4126305e9b9a57496d99d5b42da53983f2d0 Mon Sep 17 00:00:00 2001 From: myl7 Date: Sun, 2 Jan 2022 11:54:31 +0800 Subject: [PATCH 1/3] handle errors when traversing --- components/MultiFileDownloader.tsx | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/components/MultiFileDownloader.tsx b/components/MultiFileDownloader.tsx index 1eb0bef..0fd1bd6 100644 --- a/components/MultiFileDownloader.tsx +++ b/components/MultiFileDownloader.tsx @@ -178,7 +178,18 @@ export async function* traverseFolder(path: string): AsyncGenerator< const itemLists = await Promise.all( folderPaths.map(fp => (async fp => { - const data = await fetcher(`/api?path=${fp}`, hashedToken ?? undefined) + let data: any + try { + data = await fetcher(`/api?path=${fp}`, hashedToken ?? undefined) + } catch (error: any) { + // Skip errors caused by the client + if (Math.floor(error.response.status / 100) === 4) { + return null + } else { + throw error + } + } + if (data && data.folder) { return data.folder.value.map((c: any) => { const p = `${fp === '/' ? '' : fp}/${encodeURIComponent(c.name)}` @@ -191,7 +202,7 @@ export async function* traverseFolder(path: string): AsyncGenerator< ) ) - const items = itemLists.flat() as { path: string; meta: any; isFolder: boolean }[] + const items = itemLists.filter(Boolean).flat() as { path: string; meta: any; isFolder: boolean }[] yield* items folderPaths = items.filter(i => i.isFolder).map(i => i.path) } From 9bde9bdab01b9bd6241e103812b3b0f1a9122759 Mon Sep 17 00:00:00 2001 From: myl7 Date: Mon, 24 Jan 2022 22:00:08 +0800 Subject: [PATCH 2/3] report handleable error in downloading --- components/FileListing.tsx | 6 +++++- components/MultiFileDownloader.tsx | 22 ++++++++++++++++------ 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/components/FileListing.tsx b/components/FileListing.tsx index 8043f76..a947055 100644 --- a/components/FileListing.tsx +++ b/components/FileListing.tsx @@ -297,7 +297,11 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { // Folder recursive download const handleFolderDownload = (path: string, id: string, name?: string) => () => { const files = (async function* () { - for await (const { meta: c, path: p, isFolder } of traverseFolder(path)) { + for await (const { meta: c, path: p, isFolder, error } of traverseFolder(path)) { + if (error) { + toast.error(`Failed to download folder ${p}: ${error[0]} ${error[1]} Skipped it to continue.`) + continue + } yield { name: c?.name, url: c ? c['@microsoft.graph.downloadUrl'] : undefined, diff --git a/components/MultiFileDownloader.tsx b/components/MultiFileDownloader.tsx index 0fd1bd6..e08a96b 100644 --- a/components/MultiFileDownloader.tsx +++ b/components/MultiFileDownloader.tsx @@ -161,12 +161,14 @@ export async function downloadTreelikeMultipleFiles({ * @param path Folder to be traversed * @returns Array of items representing folders and files of traversed folder in BFS order and excluding root folder. * Due to BFS, folder items are ALWAYS in front of its children items. + * Error key in the item will contain the error when there is a handleable error. */ export async function* traverseFolder(path: string): AsyncGenerator< { path: string meta: any isFolder: boolean + error?: [number, string] }, void, undefined @@ -182,9 +184,14 @@ export async function* traverseFolder(path: string): AsyncGenerator< try { data = await fetcher(`/api?path=${fp}`, hashedToken ?? undefined) } catch (error: any) { - // Skip errors caused by the client - if (Math.floor(error.response.status / 100) === 4) { - return null + console.log(error) + // 4xx errors are identified as handleable errors + if (Math.floor(error.status / 100) === 4) { + return { + path: fp, + isFolder: true, + error: [error.status as number, error.message.error as string] + } } else { throw error } @@ -202,8 +209,11 @@ export async function* traverseFolder(path: string): AsyncGenerator< ) ) - const items = itemLists.filter(Boolean).flat() as { path: string; meta: any; isFolder: boolean }[] - yield* items - folderPaths = items.filter(i => i.isFolder).map(i => i.path) + const items = itemLists.flat() as { path: string; meta: any; isFolder: boolean; error?: [number, string] }[] + yield * items + folderPaths = items + .filter(({ error }) => !error) + .filter(i => i.isFolder) + .map(i => i.path) } } From 6df1447d33244d58a86749288e051b3fbedaa6f9 Mon Sep 17 00:00:00 2001 From: myl7 Date: Mon, 24 Jan 2022 23:16:10 +0800 Subject: [PATCH 3/3] update error inner structure --- components/FileListing.tsx | 2 +- components/MultiFileDownloader.tsx | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/components/FileListing.tsx b/components/FileListing.tsx index a947055..f49c6b5 100644 --- a/components/FileListing.tsx +++ b/components/FileListing.tsx @@ -299,7 +299,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => { const files = (async function* () { for await (const { meta: c, path: p, isFolder, error } of traverseFolder(path)) { if (error) { - toast.error(`Failed to download folder ${p}: ${error[0]} ${error[1]} Skipped it to continue.`) + toast.error(`Failed to download folder ${p}: ${error.status} ${error.message} Skipped it to continue.`) continue } yield { diff --git a/components/MultiFileDownloader.tsx b/components/MultiFileDownloader.tsx index e08a96b..b4f5b60 100644 --- a/components/MultiFileDownloader.tsx +++ b/components/MultiFileDownloader.tsx @@ -168,7 +168,7 @@ export async function* traverseFolder(path: string): AsyncGenerator< path: string meta: any isFolder: boolean - error?: [number, string] + error?: { status: number; message: string } }, void, undefined @@ -184,13 +184,12 @@ export async function* traverseFolder(path: string): AsyncGenerator< try { data = await fetcher(`/api?path=${fp}`, hashedToken ?? undefined) } catch (error: any) { - console.log(error) // 4xx errors are identified as handleable errors if (Math.floor(error.status / 100) === 4) { return { path: fp, isFolder: true, - error: [error.status as number, error.message.error as string] + error: { status: error.status, message: error.message.error }, } } else { throw error @@ -209,7 +208,12 @@ export async function* traverseFolder(path: string): AsyncGenerator< ) ) - const items = itemLists.flat() as { path: string; meta: any; isFolder: boolean; error?: [number, string] }[] + const items = itemLists.flat() as { + path: string + meta: any + isFolder: boolean + error?: { status: number; message: string } + }[] yield * items folderPaths = items .filter(({ error }) => !error)