浏览代码

Checkpoint

Manav Rathi 1 年之前
父节点
当前提交
a286b11adb
共有 2 个文件被更改,包括 70 次插入60 次删除
  1. 58 54
      web/apps/photos/src/services/upload/uploadService.ts
  2. 12 6
      web/apps/photos/src/utils/native-stream.ts

+ 58 - 54
web/apps/photos/src/services/upload/uploadService.ts

@@ -54,12 +54,9 @@ import {
     getNonEmptyMagicMetadataProps,
     updateMagicMetadata,
 } from "utils/magicMetadata";
+import { readStream } from "utils/native-stream";
 import { findMatchingExistingFiles } from "utils/upload";
-import {
-    getElectronFileStream,
-    getFileStream,
-    getUint8ArrayView,
-} from "../readerService";
+import { getFileStream, getUint8ArrayView } from "../readerService";
 import { getFileType } from "../typeDetectionService";
 import {
     MAX_FILE_NAME_LENGTH_GOOGLE_EXPORT,
@@ -431,62 +428,69 @@ const readFileOrPath = async (
 ): Promise<FileInMemory> => {
     log.info(`Reading file ${fopLabel(fileOrPath)} `);
 
-    // If it's a file, read-in its data. We need to do it once anyway for
-    // generating the thumbnail.
-    const dataOrPath =
-        fileOrPath instanceof File
-            ? new Uint8Array(await fileOrPath.arrayBuffer())
-            : fileOrPath;
-
-    let thumbnail: Uint8Array;
-
-    const electron = globalThis.electron;
-    if (electron) {
-        if  !moduleState.isNativeImageThumbnailCreationNotAvailable;
-        try {
-            return await generateImageThumbnailNative(electron, fileOrPath);
-        } catch (e) {
-            if (e.message == CustomErrorMessage.NotAvailable) {
-                moduleState.isNativeThumbnailCreationNotAvailable = true;
-            } else {
-                log.error("Native thumbnail creation failed", e);
-            }
-        }
-    }
-
-    let filedata: Uint8Array | DataStream;
-    if (!(rawFile instanceof File)) {
-        if (rawFile.size > MULTIPART_PART_SIZE) {
-            filedata = await getElectronFileStream(
-                rawFile,
-                FILE_READER_CHUNK_SIZE,
-            );
+    let dataOrStream: Uint8Array | DataStream;
+    if (fileOrPath instanceof File) {
+        const file = fileOrPath;
+        if (file.size > MULTIPART_PART_SIZE) {
+            dataOrStream = getFileStream(file, FILE_READER_CHUNK_SIZE);
         } else {
-            filedata = await getUint8ArrayView(rawFile);
+            dataOrStream = new Uint8Array(await file.arrayBuffer());
         }
-    } else if (rawFile.size > MULTIPART_PART_SIZE) {
-        filedata = getFileStream(rawFile, FILE_READER_CHUNK_SIZE);
     } else {
-        filedata = await getUint8ArrayView(rawFile);
+        const path = fileOrPath;
+        const { stream, size } = await readStream(path);
+        if (size > MULTIPART_PART_SIZE) {
+            const chunkCount = Math.ceil(size / FILE_READER_CHUNK_SIZE);
+            dataOrStream = { stream, chunkCount };
+        } else {
+            dataOrStream = new Uint8Array(
+                await new Response(stream).arrayBuffer(),
+            );
+        }
     }
 
-    try {
-        const thumbnail =
-            fileTypeInfo.fileType === FILE_TYPE.IMAGE
-                ? await generateImageThumbnailUsingCanvas(blob, fileTypeInfo)
-                : await generateVideoThumbnail(blob);
+    let filedata: Uint8Array | DataStream;
 
-        if (thumbnail.length == 0) throw new Error("Empty thumbnail");
-        return { thumbnail, hasStaticThumbnail: false };
-    } catch (e) {
-        log.error(`Failed to generate ${fileTypeInfo.exactType} thumbnail`, e);
-        return { thumbnail: fallbackThumbnail(), hasStaticThumbnail: true };
-    }
+    // If it's a file, read-in its data. We need to do it once anyway for
+    // generating the thumbnail.
+    const dataOrPath =
+        fileOrPath instanceof File
+            ? new Uint8Array(await fileOrPath.arrayBuffer())
+            : fileOrPath;
 
-    if (filedata instanceof Uint8Array) {
-    } else {
-        filedata.stream;
-    }
+    // let thumbnail: Uint8Array;
+
+    // const electron = globalThis.electron;
+    // if (electron) {
+    //     if  !moduleState.isNativeImageThumbnailCreationNotAvailable;
+    //     try {
+    //         return await generateImageThumbnailNative(electron, fileOrPath);
+    //     } catch (e) {
+    //         if (e.message == CustomErrorMessage.NotAvailable) {
+    //             moduleState.isNativeThumbnailCreationNotAvailable = true;
+    //         } else {
+    //             log.error("Native thumbnail creation failed", e);
+    //         }
+    //     }
+    // }
+
+    // try {
+    //     const thumbnail =
+    //         fileTypeInfo.fileType === FILE_TYPE.IMAGE
+    //             ? await generateImageThumbnailUsingCanvas(blob, fileTypeInfo)
+    //             : await generateVideoThumbnail(blob);
+
+    //     if (thumbnail.length == 0) throw new Error("Empty thumbnail");
+    //     return { thumbnail, hasStaticThumbnail: false };
+    // } catch (e) {
+    //     log.error(`Failed to generate ${fileTypeInfo.exactType} thumbnail`, e);
+    //     return { thumbnail: fallbackThumbnail(), hasStaticThumbnail: true };
+    // }
+
+    // if (filedata instanceof Uint8Array) {
+    // } else {
+    //     filedata.stream;
+    // }
 
     log.info(`read file data successfully ${getFileNameSize(rawFile)} `);
 

+ 12 - 6
web/apps/photos/src/utils/native-stream.ts

@@ -14,13 +14,13 @@
  * @param path The path on the file on the user's local filesystem whose
  * contents we want to stream.
  *
- * @return A standard web {@link Response} object that contains the contents of
- * the file. In particular, `response.body` will be a {@link ReadableStream}
- * that can be used to read the files contents in a streaming, chunked, manner.
- * Also, the response is guaranteed to have a "Content-Length" header indicating
+ * @return A (ReadableStream, size) tuple. The {@link ReadableStream} can be
+ * used to read the files contents in a streaming manner. The size value is the
  * the size of the file that we'll be reading from disk.
  */
-export const readStream = async (path: string) => {
+export const readStream = async (
+    path: string,
+): Promise<{ stream: ReadableStream; size: number }> => {
     const req = new Request(`stream://read${path}`, {
         method: "GET",
     });
@@ -31,7 +31,13 @@ export const readStream = async (path: string) => {
             `Failed to read stream from ${path}: HTTP ${res.status}`,
         );
 
-    return res;
+    const size = +res.headers["Content-Length"];
+    if (isNaN(size))
+        throw new Error(
+            `Got a numeric Content-Length when reading a stream. The response was ${res}`,
+        );
+
+    return { stream: res.body, size };
 };
 
 /**