瀏覽代碼

Wrap the assertion

Manav Rathi 1 年之前
父節點
當前提交
4aa3d68e36

+ 2 - 2
web/apps/photos/src/components/Directory/index.tsx

@@ -1,4 +1,4 @@
-import ElectronAPIs from "@/next/electron";
+import { ensureElectron } from "@/next/electron";
 import log from "@/next/log";
 import LinkButton from "@ente/shared/components/LinkButton";
 import { Tooltip } from "@mui/material";
@@ -19,7 +19,7 @@ const DirectoryPathContainer = styled(LinkButton)(
 export const DirectoryPath = ({ width, path }) => {
     const handleClick = async () => {
         try {
-            await ElectronAPIs.openDirectory(path);
+            await ensureElectron().openDirectory(path);
         } catch (e) {
             log.error("openDirectory failed", e);
         }

+ 7 - 4
web/apps/photos/src/services/clipService.ts

@@ -1,4 +1,4 @@
-import ElectronAPIs from "@/next/electron";
+import { ensureElectron } from "@/next/electron";
 import log from "@/next/log";
 import ComlinkCryptoWorker from "@ente/shared/crypto";
 import { CustomError } from "@ente/shared/error";
@@ -157,7 +157,7 @@ class ClipServiceImpl {
         model: Model = Model.ONNX_CLIP,
     ): Promise<Float32Array> => {
         try {
-            return ElectronAPIs.computeTextEmbedding(model, text);
+            return ensureElectron().computeTextEmbedding(model, text);
         } catch (e) {
             if (e?.message?.includes(CustomError.UNSUPPORTED_PLATFORM)) {
                 this.unsupportedPlatform = true;
@@ -304,7 +304,10 @@ class ClipServiceImpl {
         const file = await localFile
             .arrayBuffer()
             .then((buffer) => new Uint8Array(buffer));
-        const embedding = await ElectronAPIs.computeImageEmbedding(model, file);
+        const embedding = await ensureElectron().computeImageEmbedding(
+            model,
+            file,
+        );
         return embedding;
     };
 
@@ -344,7 +347,7 @@ class ClipServiceImpl {
         file: EnteFile,
     ) => {
         const thumb = await downloadManager.getThumbnail(file);
-        const embedding = await ElectronAPIs.computeImageEmbedding(
+        const embedding = await ensureElectron().computeImageEmbedding(
             model,
             thumb,
         );

+ 28 - 36
web/apps/photos/src/services/export/index.ts

@@ -57,7 +57,6 @@ import downloadManager from "../download";
 import { getAllLocalFiles } from "../fileService";
 import { decodeLivePhoto } from "../livePhotoService";
 import { migrateExport } from "./migration";
-import type { Electron } from "@/next/types/ipc";
 
 const EXPORT_RECORD_FILE_NAME = "export_status.json";
 
@@ -71,15 +70,6 @@ export const NULL_EXPORT_RECORD: ExportRecord = {
     collectionExportNames: {},
 };
 
-const electron = (): Electron => {
-    const et = globalThis.electron;
-    if (!et)
-        throw new Error(
-            "Attempting to use ExportService in an unsupported non-electron context",
-        );
-    return et;
-};
-
 class ExportService {
     private exportSettings: ExportSettings;
     private exportInProgress: RequestCanceller = null;
@@ -166,12 +156,12 @@ class ExportService {
 
     async changeExportDirectory() {
         try {
-            const newRootDir = await electron().selectDirectory();
+            const newRootDir = await ensureElectron().selectDirectory();
             if (!newRootDir) {
                 throw Error(CustomError.SELECT_FOLDER_ABORTED);
             }
             const newExportDir = `${newRootDir}/${ENTE_EXPORT_DIRECTORY}`;
-            await electron().checkExistsAndCreateDir(newExportDir);
+            await ensureElectron().checkExistsAndCreateDir(newExportDir);
             return newExportDir;
         } catch (e) {
             if (e.message !== CustomError.SELECT_FOLDER_ABORTED) {
@@ -521,7 +511,7 @@ class ExportService {
                         newCollectionExportName,
                     );
                     try {
-                        await electron().rename(
+                        await ensureElectron().rename(
                             oldCollectionExportPath,
                             newCollectionExportPath,
                         );
@@ -606,11 +596,13 @@ class ExportService {
                     );
                     try {
                         // delete the collection metadata folder
-                        await electron().deleteFolder(
+                        await ensureElectron().deleteFolder(
                             getMetadataFolderExportPath(collectionExportPath),
                         );
                         // delete the collection folder
-                        await electron().deleteFolder(collectionExportPath);
+                        await ensureElectron().deleteFolder(
+                            collectionExportPath,
+                        );
                     } catch (e) {
                         await this.addCollectionExportedRecord(
                             exportFolder,
@@ -693,10 +685,10 @@ class ExportService {
                         exportDir,
                         collectionExportName,
                     );
-                    await electron().checkExistsAndCreateDir(
+                    await ensureElectron().checkExistsAndCreateDir(
                         collectionExportPath,
                     );
-                    await electron().checkExistsAndCreateDir(
+                    await ensureElectron().checkExistsAndCreateDir(
                         getMetadataFolderExportPath(collectionExportPath),
                     );
                     await this.downloadAndSave(
@@ -776,7 +768,7 @@ class ExportService {
                                 `moving image file ${imageExportPath} to trash folder`,
                             );
                             if (await this.exists(imageExportPath)) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     imageExportPath,
                                     await getTrashedFileExportPath(
                                         exportDir,
@@ -791,7 +783,7 @@ class ExportService {
                             if (
                                 await this.exists(imageMetadataFileExportPath)
                             ) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     imageMetadataFileExportPath,
                                     await getTrashedFileExportPath(
                                         exportDir,
@@ -808,7 +800,7 @@ class ExportService {
                                 `moving video file ${videoExportPath} to trash folder`,
                             );
                             if (await this.exists(videoExportPath)) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     videoExportPath,
                                     await getTrashedFileExportPath(
                                         exportDir,
@@ -821,7 +813,7 @@ class ExportService {
                             if (
                                 await this.exists(videoMetadataFileExportPath)
                             ) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     videoMetadataFileExportPath,
                                     await getTrashedFileExportPath(
                                         exportDir,
@@ -843,7 +835,7 @@ class ExportService {
                                 `moving file ${fileExportPath} to ${trashedFilePath} trash folder`,
                             );
                             if (await this.exists(fileExportPath)) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     fileExportPath,
                                     trashedFilePath,
                                 );
@@ -851,7 +843,7 @@ class ExportService {
                             const metadataFileExportPath =
                                 getMetadataFileExportPath(fileExportPath);
                             if (await this.exists(metadataFileExportPath)) {
-                                await electron().moveFile(
+                                await ensureElectron().moveFile(
                                     metadataFileExportPath,
                                     await getTrashedFileExportPath(
                                         exportDir,
@@ -990,7 +982,7 @@ class ExportService {
         try {
             const exportRecord = await this.getExportRecord(folder);
             const newRecord: ExportRecord = { ...exportRecord, ...newData };
-            await electron().saveFileToDisk(
+            await ensureElectron().saveFileToDisk(
                 `${folder}/${EXPORT_RECORD_FILE_NAME}`,
                 JSON.stringify(newRecord, null, 2),
             );
@@ -1012,7 +1004,7 @@ class ExportService {
                 return this.createEmptyExportRecord(exportRecordJSONPath);
             }
             const recordFile =
-                await electron().readTextFile(exportRecordJSONPath);
+                await ensureElectron().readTextFile(exportRecordJSONPath);
             try {
                 return JSON.parse(recordFile);
             } catch (e) {
@@ -1048,8 +1040,8 @@ class ExportService {
             exportFolder,
             collectionExportName,
         );
-        await electron().checkExistsAndCreateDir(collectionExportPath);
-        await electron().checkExistsAndCreateDir(
+        await ensureElectron().checkExistsAndCreateDir(collectionExportPath);
+        await ensureElectron().checkExistsAndCreateDir(
             getMetadataFolderExportPath(collectionExportPath),
         );
 
@@ -1096,7 +1088,7 @@ class ExportService {
                         fileExportName,
                         file,
                     );
-                    await electron().saveStreamToDisk(
+                    await ensureElectron().saveStreamToDisk(
                         getFileExportPath(collectionExportPath, fileExportName),
                         updatedFileStream,
                     );
@@ -1144,7 +1136,7 @@ class ExportService {
                 imageExportName,
                 file,
             );
-            await electron().saveStreamToDisk(
+            await ensureElectron().saveStreamToDisk(
                 getFileExportPath(collectionExportPath, imageExportName),
                 imageStream,
             );
@@ -1156,12 +1148,12 @@ class ExportService {
                 file,
             );
             try {
-                await electron().saveStreamToDisk(
+                await ensureElectron().saveStreamToDisk(
                     getFileExportPath(collectionExportPath, videoExportName),
                     videoStream,
                 );
             } catch (e) {
-                await electron().deleteFile(
+                await ensureElectron().deleteFile(
                     getFileExportPath(collectionExportPath, imageExportName),
                 );
                 throw e;
@@ -1177,7 +1169,7 @@ class ExportService {
         fileExportName: string,
         file: EnteFile,
     ) {
-        await electron().saveFileToDisk(
+        await ensureElectron().saveFileToDisk(
             getFileMetadataExportPath(collectionExportPath, fileExportName),
             getGoogleLikeMetadataFile(fileExportName, file),
         );
@@ -1188,15 +1180,15 @@ class ExportService {
     };
 
     exists = (path: string) => {
-        return electron().fs.exists(path);
+        return ensureElectron().fs.exists(path);
     };
 
     rename = (oldPath: string, newPath: string) => {
-        return electron().rename(oldPath, newPath);
+        return ensureElectron().rename(oldPath, newPath);
     };
 
     checkExistsAndCreateDir = (path: string) => {
-        return electron().checkExistsAndCreateDir(path);
+        return ensureElectron().checkExistsAndCreateDir(path);
     };
 
     exportFolderExists = async (exportFolder: string) => {
@@ -1218,7 +1210,7 @@ class ExportService {
 
     private createEmptyExportRecord = async (exportRecordJSONPath: string) => {
         const exportRecord: ExportRecord = NULL_EXPORT_RECORD;
-        await electron().saveFileToDisk(
+        await ensureElectron().saveFileToDisk(
             exportRecordJSONPath,
             JSON.stringify(exportRecord, null, 2),
         );

+ 11 - 16
web/apps/photos/src/services/importService.ts

@@ -1,5 +1,5 @@
+import { ensureElectron } from "@/next/electron";
 import log from "@/next/log";
-import type { Electron } from "@/next/types/ipc";
 import { PICKED_UPLOAD_TYPE } from "constants/upload";
 import { Collection } from "types/collection";
 import { ElectronFile, FileWithCollection } from "types/upload";
@@ -10,20 +10,11 @@ interface PendingUploads {
     type: PICKED_UPLOAD_TYPE;
 }
 
-const electron = (): Electron => {
-    const et = globalThis.electron;
-    if (!et)
-        throw new Error(
-            "Attempting to use ExportService in an unsupported non-electron context",
-        );
-    return et;
-};
-
 class ImportService {
     async getPendingUploads(): Promise<PendingUploads> {
         try {
             const pendingUploads =
-                (await electron().getPendingUploads()) as PendingUploads;
+                (await ensureElectron().getPendingUploads()) as PendingUploads;
             return pendingUploads;
         } catch (e) {
             if (e?.message?.includes("ENOENT: no such file or directory")) {
@@ -49,7 +40,7 @@ class ImportService {
         if (collections.length === 1) {
             collectionName = collections[0].name;
         }
-        await electron().setToUploadCollection(collectionName);
+        await ensureElectron().setToUploadCollection(collectionName);
     }
 
     async updatePendingUploads(files: FileWithCollection[]) {
@@ -66,13 +57,17 @@ class ImportService {
                 filePaths.push((fileWithCollection.file as ElectronFile).path);
             }
         }
-        await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, filePaths);
+        await ensureElectron().setToUploadFiles(
+            PICKED_UPLOAD_TYPE.FILES,
+            filePaths,
+        );
     }
 
     async cancelRemainingUploads() {
-        await electron().setToUploadCollection(null);
-        await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.ZIPS, []);
-        await electron().setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, []);
+        const electron = ensureElectron();
+        await electron.setToUploadCollection(null);
+        await electron.setToUploadFiles(PICKED_UPLOAD_TYPE.ZIPS, []);
+        await electron.setToUploadFiles(PICKED_UPLOAD_TYPE.FILES, []);
     }
 }
 

+ 2 - 2
web/apps/photos/src/services/upload/thumbnailService.ts

@@ -1,4 +1,4 @@
-import ElectronAPIs from "@/next/electron";
+import { ensureElectron } from "@/next/electron";
 import { convertBytesToHumanReadable, getFileNameSize } from "@/next/file";
 import log from "@/next/log";
 import { CustomError } from "@ente/shared/error";
@@ -98,7 +98,7 @@ const generateImageThumbnailInElectron = async (
 ): Promise<Uint8Array> => {
     try {
         const startTime = Date.now();
-        const thumb = await ElectronAPIs.generateImageThumbnail(
+        const thumb = await ensureElectron().generateImageThumbnail(
             inputFile,
             maxDimension,
             maxSize,

+ 15 - 22
web/apps/photos/src/services/watchFolder/watchFolderService.ts

@@ -1,5 +1,5 @@
+import { ensureElectron } from "@/next/electron";
 import log from "@/next/log";
-import type { Electron } from "@/next/types/ipc";
 import { UPLOAD_RESULT, UPLOAD_STRATEGY } from "constants/upload";
 import debounce from "debounce";
 import uploadManager from "services/upload/uploadManager";
@@ -22,15 +22,6 @@ import {
     diskFolderRemovedCallback,
 } from "./watchFolderEventHandlers";
 
-const electron = (): Electron => {
-    const et = globalThis.electron;
-    if (!et)
-        throw new Error(
-            "Attempting to use ExportService in an unsupported non-electron context",
-        );
-    return et;
-};
-
 class watchFolderService {
     private eventQueue: EventQueueItem[] = [];
     private currentEvent: EventQueueItem;
@@ -92,7 +83,7 @@ class watchFolderService {
 
             for (const mapping of mappings) {
                 const filesOnDisk: ElectronFile[] =
-                    await electron().getDirFiles(mapping.folderPath);
+                    await ensureElectron().getDirFiles(mapping.folderPath);
 
                 this.uploadDiffOfFiles(mapping, filesOnDisk);
                 this.trashDiffOfFiles(mapping, filesOnDisk);
@@ -159,9 +150,11 @@ class watchFolderService {
     ): Promise<WatchMapping[]> {
         const notDeletedMappings = [];
         for (const mapping of mappings) {
-            const mappingExists = await electron().isFolder(mapping.folderPath);
+            const mappingExists = await ensureElectron().isFolder(
+                mapping.folderPath,
+            );
             if (!mappingExists) {
-                electron().removeWatchMapping(mapping.folderPath);
+                ensureElectron().removeWatchMapping(mapping.folderPath);
             } else {
                 notDeletedMappings.push(mapping);
             }
@@ -179,7 +172,7 @@ class watchFolderService {
     }
 
     private setupWatcherFunctions() {
-        electron().registerWatcherFunctions(
+        ensureElectron().registerWatcherFunctions(
             diskFileAddedCallback,
             diskFileRemovedCallback,
             diskFolderRemovedCallback,
@@ -192,7 +185,7 @@ class watchFolderService {
         uploadStrategy: UPLOAD_STRATEGY,
     ) {
         try {
-            await electron().addWatchMapping(
+            await ensureElectron().addWatchMapping(
                 rootFolderName,
                 folderPath,
                 uploadStrategy,
@@ -205,7 +198,7 @@ class watchFolderService {
 
     async removeWatchMapping(folderPath: string) {
         try {
-            await electron().removeWatchMapping(folderPath);
+            await ensureElectron().removeWatchMapping(folderPath);
         } catch (e) {
             log.error("error while removing watch mapping", e);
         }
@@ -213,7 +206,7 @@ class watchFolderService {
 
     async getWatchMappings(): Promise<WatchMapping[]> {
         try {
-            return (await electron().getWatchMappings()) ?? [];
+            return (await ensureElectron().getWatchMappings()) ?? [];
         } catch (e) {
             log.error("error while getting watch mappings", e);
             return [];
@@ -385,7 +378,7 @@ class watchFolderService {
                     ...this.currentlySyncedMapping.syncedFiles,
                     ...syncedFiles,
                 ];
-                await electron().updateWatchMappingSyncedFiles(
+                await ensureElectron().updateWatchMappingSyncedFiles(
                     this.currentlySyncedMapping.folderPath,
                     this.currentlySyncedMapping.syncedFiles,
                 );
@@ -395,7 +388,7 @@ class watchFolderService {
                     ...this.currentlySyncedMapping.ignoredFiles,
                     ...ignoredFiles,
                 ];
-                await electron().updateWatchMappingIgnoredFiles(
+                await ensureElectron().updateWatchMappingIgnoredFiles(
                     this.currentlySyncedMapping.folderPath,
                     this.currentlySyncedMapping.ignoredFiles,
                 );
@@ -510,7 +503,7 @@ class watchFolderService {
                 this.currentlySyncedMapping.syncedFiles.filter(
                     (file) => !filePathsToRemove.has(file.path),
                 );
-            await electron().updateWatchMappingSyncedFiles(
+            await ensureElectron().updateWatchMappingSyncedFiles(
                 this.currentlySyncedMapping.folderPath,
                 this.currentlySyncedMapping.syncedFiles,
             );
@@ -602,7 +595,7 @@ class watchFolderService {
 
     async selectFolder(): Promise<string> {
         try {
-            const folderPath = await electron().selectDirectory();
+            const folderPath = await ensureElectron().selectDirectory();
             return folderPath;
         } catch (e) {
             log.error("error while selecting folder", e);
@@ -630,7 +623,7 @@ class watchFolderService {
 
     async isFolder(folderPath: string) {
         try {
-            const isFolder = await electron().isFolder(folderPath);
+            const isFolder = await ensureElectron().isFolder(folderPath);
             return isFolder;
         } catch (e) {
             log.error("error while checking if folder exists", e);

+ 3 - 4
web/apps/photos/src/utils/collection/index.ts

@@ -1,4 +1,3 @@
-import ElectronAPIs from "@/next/electron";
 import log from "@/next/log";
 import { CustomError } from "@ente/shared/error";
 import { getAlbumsURL } from "@ente/shared/network/api";
@@ -17,7 +16,6 @@ import {
     SYSTEM_COLLECTION_TYPES,
 } from "constants/collection";
 import { t } from "i18next";
-import isElectron from "is-electron";
 import {
     addToCollection,
     createAlbum,
@@ -152,8 +150,9 @@ export async function downloadCollectionFiles(
         return;
     }
     let downloadDirPath: string;
-    if (isElectron()) {
-        const selectedDir = await ElectronAPIs.selectDirectory();
+    const electron = globalThis.electron;
+    if (electron) {
+        const selectedDir = await electron.selectDirectory();
         if (!selectedDir) {
             return;
         }

+ 24 - 0
web/packages/next/electron.ts

@@ -20,3 +20,27 @@ const ElectronAPIs = (globalThis as unknown as any)[
 // export const globalElectron = globalThis.electron;
 
 export default ElectronAPIs;
+
+/**
+ * A wrapper over a non-null assertion of `globalThis.electron`.
+ *
+ * This is useful where we have previously verified that the code path in which
+ * we're running only executes when we're in electron (usually by directly
+ * checking that `globalThis.electron` is defined somewhere up the chain).
+ *
+ * Generally, this should not be required - the check and the use should be
+ * colocated, or the unwrapped non-null value saved somewhere. But sometimes
+ * doing so requires code refactoring, so as an escape hatch we provide this
+ * convenience function.
+ *
+ * It will throw if `globalThis.electron` is undefined.
+ *
+ * @see `global-electron.d.ts`.
+ */
+export const ensureElectron = (): Electron => {
+    const et = globalThis.electron;
+    if (et) return et;
+    throw new Error(
+        "Attempting to assert globalThis.electron in a non-electron context",
+    );
+};

+ 2 - 2
web/packages/next/worker/comlink-worker.ts

@@ -1,4 +1,4 @@
-import ElectronAPIs from "@/next/electron";
+import { ensureElectron } from "@/next/electron";
 import log, { logToDisk } from "@/next/log";
 import { expose, wrap, type Remote } from "comlink";
 
@@ -45,7 +45,7 @@ export class ComlinkWorker<T extends new () => InstanceType<T>> {
 const workerBridge = {
     logToDisk,
     convertToJPEG: (inputFileData: Uint8Array, filename: string) =>
-        ElectronAPIs.convertToJPEG(inputFileData, filename),
+        ensureElectron().convertToJPEG(inputFileData, filename),
 };
 
 export type WorkerBridge = typeof workerBridge;