Procházet zdrojové kódy

Remove one copy of duplication from IPC types

Manav Rathi před 1 rokem
rodič
revize
ac97d65c12

+ 1 - 1
desktop/src/api/upload.ts

@@ -4,7 +4,7 @@ import {
     getSavedFilePaths,
 } from "../services/upload";
 import { uploadStatusStore } from "../stores/upload.store";
-import { ElectronFile, FILE_PATH_TYPE } from "../types";
+import { ElectronFile, FILE_PATH_TYPE } from "../types/ipc";
 
 export const getPendingUploads = async () => {
     const filePaths = getSavedFilePaths(FILE_PATH_TYPE.FILES);

+ 3 - 2
desktop/src/main.ts

@@ -100,8 +100,9 @@ const increaseDiskCache = () => {
 
 /**
  * Older versions of our app used to maintain a cache dir using the main
- * process. This has been deprecated in favor of using a normal web cache (See:
- * [Note: Increased disk cache for the desktop app]).
+ * process. This has been deprecated in favor of using a normal web cache.
+ *
+ * See [Note: Increased disk cache for the desktop app]
  *
  * Delete the old cache dir if it exists. This code was added March 2024, and
  * can be removed after some time once most people have upgraded to newer

+ 1 - 1
desktop/src/main/dialogs.ts

@@ -2,7 +2,7 @@ import { dialog } from "electron/main";
 import path from "node:path";
 import { getDirFilePaths, getElectronFile } from "../services/fs";
 import { getElectronFilesFromGoogleZip } from "../services/upload";
-import type { ElectronFile } from "../types";
+import type { ElectronFile } from "../types/ipc";
 
 export const selectDirectory = async () => {
     const result = await dialog.showOpenDialog({

+ 4 - 2
desktop/src/main/ipc.ts

@@ -4,6 +4,8 @@
  *
  * This file is meant as a sibling to `preload.ts`, but this one runs in the
  * context of the main process, and can import other files from `src/`.
+ *
+ * See [Note: types.ts <-> preload.ts <-> ipc.ts]
  */
 
 import type { FSWatcher } from "chokidar";
@@ -44,7 +46,7 @@ import type {
     FILE_PATH_TYPE,
     Model,
     WatchMapping,
-} from "../types";
+} from "../types/ipc";
 import {
     selectDirectory,
     showUploadDirsDialog,
@@ -95,7 +97,7 @@ export const attachIPCHandlers = () => {
 
     ipcMain.handle("openLogDirectory", (_) => openLogDirectory());
 
-    // See: [Note: Catching exception during .send/.on]
+    // See [Note: Catching exception during .send/.on]
     ipcMain.on("logToDisk", (_, message) => logToDisk(message));
 
     ipcMain.on("clear-electron-store", (_) => {

+ 22 - 56
desktop/src/preload.ts

@@ -24,43 +24,43 @@
  * file. However, since this is just boilerplate code providing a bridge between
  * the main and renderer, we avoid introducing another moving part into the mix
  * and just keep the entire preload setup in this single file.
+ *
+ * [Note: types.ts <-> preload.ts <-> ipc.ts]
+ *
+ * The following three files are boilerplatish linkage of the same functions,
+ * and when changing one of them, remember to see if the other two also need
+ * changing:
+ *
+ * -    [renderer]  web/packages/shared/electron/types.ts     contains docs
+ * -    [preload]   desktop/src/preload.ts                          ↕︎
+ * -    [main]      desktop/src/main/ipc.ts                   contains impl
  */
 
-import { contextBridge, ipcRenderer } from "electron";
-import type { ElectronFile } from "./types";
+import { contextBridge, ipcRenderer } from "electron/renderer";
+
+// While we can't import other code, we can import types since they're just
+// needed when compiling and will not be needed / looked around for at runtime.
+import type {
+    AppUpdateInfo,
+    ElectronFile,
+    FILE_PATH_TYPE,
+    Model,
+    WatchMapping,
+} from "./types/ipc";
 
 // - General
 
-/** Return the version of the desktop app. */
 const appVersion = (): Promise<string> => ipcRenderer.invoke("appVersion");
 
-/**
- * Open the given {@link dirPath} in the system's folder viewer.
- *
- * For example, on macOS this'll open {@link dirPath} in Finder.
- */
 const openDirectory = (dirPath: string): Promise<void> =>
     ipcRenderer.invoke("openDirectory");
 
-/**
- * Open the app's log directory in the system's folder viewer.
- *
- * @see {@link openDirectory}
- */
 const openLogDirectory = (): Promise<void> =>
     ipcRenderer.invoke("openLogDirectory");
 
-/**
- * Log the given {@link message} to the on-disk log file maintained by the
- * desktop app.
- */
 const logToDisk = (message: string): void =>
     ipcRenderer.send("logToDisk", message);
 
-/**
- * Return true if there is a file or directory at the given
- * {@link path}.
- */
 const fsExists = (path: string): Promise<boolean> =>
     ipcRenderer.invoke("fsExists", path);
 
@@ -85,12 +85,6 @@ const getEncryptionKey = (): Promise<string> =>
 
 // - App update
 
-/* preload: duplicated */
-interface AppUpdateInfo {
-    autoUpdatable: boolean;
-    version: string;
-}
-
 const registerUpdateEventListener = (
     showUpdateDialog: (updateInfo: AppUpdateInfo) => void,
 ) => {
@@ -148,12 +142,6 @@ const runFFmpegCmd = (
 
 // - ML
 
-/* preload: duplicated Model */
-enum Model {
-    GGML_CLIP = "ggml-clip",
-    ONNX_CLIP = "onnx-clip",
-}
-
 const computeImageEmbedding = (
     model: Model,
     imageData: Uint8Array,
@@ -218,22 +206,6 @@ const addWatchMapping = (
 const removeWatchMapping = (folderPath: string): Promise<void> =>
     ipcRenderer.invoke("removeWatchMapping", folderPath);
 
-/* preload: duplicated WatchMappingSyncedFile */
-interface WatchMappingSyncedFile {
-    path: string;
-    uploadedFileID: number;
-    collectionID: number;
-}
-
-/* preload: duplicated WatchMapping */
-interface WatchMapping {
-    rootFolderName: string;
-    uploadStrategy: number;
-    folderPath: string;
-    syncedFiles: WatchMappingSyncedFile[];
-    ignoredFiles: string[];
-}
-
 const getWatchMappings = (): Promise<WatchMapping[]> =>
     ipcRenderer.invoke("getWatchMappings");
 
@@ -288,12 +260,6 @@ const getPendingUploads = (): Promise<{
     type: string;
 }> => ipcRenderer.invoke("getPendingUploads");
 
-/* preload: duplicated FILE_PATH_TYPE */
-enum FILE_PATH_TYPE {
-    FILES = "files",
-    ZIPS = "zips",
-}
-
 const setToUploadFiles = (
     type: FILE_PATH_TYPE,
     filePaths: string[],
@@ -327,7 +293,7 @@ const getDirFiles = (dirPath: string): Promise<ElectronFile[]> =>
 // Algorithm to serialize objects passed between processes.
 // https://www.electronjs.org/docs/latest/tutorial/ipc#object-serialization
 //
-// In particular, both ArrayBuffer is eligible for structured cloning.
+// In particular, ArrayBuffer is eligible for structured cloning.
 // https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
 //
 // Also, ArrayBuffer is "transferable", which means it is a zero-copy operation

+ 1 - 1
desktop/src/services/appUpdater.ts

@@ -4,7 +4,7 @@ import { default as ElectronLog, default as log } from "electron-log";
 import { autoUpdater } from "electron-updater";
 import { setIsAppQuitting, setIsUpdateAvailable } from "../main";
 import { logErrorSentry } from "../main/log";
-import { AppUpdateInfo } from "../types";
+import { AppUpdateInfo } from "../types/ipc";
 import {
     clearMuteUpdateNotificationVersion,
     clearSkipAppVersion,

+ 1 - 1
desktop/src/services/autoLauncher.ts

@@ -1,4 +1,4 @@
-import { AutoLauncherClient } from "../types/autoLauncher";
+import { AutoLauncherClient } from "../types/main";
 import { isPlatform } from "../utils/common/platform";
 import linuxAndWinAutoLauncher from "./autoLauncherClients/linuxAndWinAutoLauncher";
 import macAutoLauncher from "./autoLauncherClients/macAutoLauncher";

+ 1 - 1
desktop/src/services/autoLauncherClients/linuxAndWinAutoLauncher.ts

@@ -1,6 +1,6 @@
 import AutoLaunch from "auto-launch";
 import { app } from "electron";
-import { AutoLauncherClient } from "../../types/autoLauncher";
+import { AutoLauncherClient } from "../../types/main";
 
 const LAUNCHED_AS_HIDDEN_FLAG = "hidden";
 

+ 1 - 1
desktop/src/services/autoLauncherClients/macAutoLauncher.ts

@@ -1,5 +1,5 @@
 import { app } from "electron";
-import { AutoLauncherClient } from "../../types/autoLauncher";
+import { AutoLauncherClient } from "../../types/main";
 
 class MacAutoLauncher implements AutoLauncherClient {
     async isEnabled() {

+ 1 - 1
desktop/src/services/clipService.ts

@@ -8,7 +8,7 @@ import { CustomErrors } from "../constants/errors";
 import { writeStream } from "../main/fs";
 import { isDev } from "../main/general";
 import { logErrorSentry } from "../main/log";
-import { Model } from "../types";
+import { Model } from "../types/ipc";
 import Tokenizer from "../utils/clip-bpe-ts/mod";
 import { getPlatform } from "../utils/common/platform";
 import { generateTempFilePath } from "../utils/temp";

+ 1 - 1
desktop/src/services/ffmpeg.ts

@@ -6,7 +6,7 @@ import util from "util";
 import { CustomErrors } from "../constants/errors";
 import { writeStream } from "../main/fs";
 import { logError, logErrorSentry } from "../main/log";
-import { ElectronFile } from "../types";
+import { ElectronFile } from "../types/ipc";
 import { generateTempFilePath, getTempDirPath } from "../utils/temp";
 
 const shellescape = require("any-shell-escape");

+ 1 - 1
desktop/src/services/fs.ts

@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
 import fs from "node:fs/promises";
 import path from "node:path";
 import { logError } from "../main/log";
-import { ElectronFile } from "../types";
+import { ElectronFile } from "../types/ipc";
 
 const FILE_STREAM_CHUNK_SIZE: number = 4 * 1024 * 1024;
 

+ 1 - 1
desktop/src/services/imageProcessor.ts

@@ -8,7 +8,7 @@ import { CustomErrors } from "../constants/errors";
 import { writeStream } from "../main/fs";
 import { isDev } from "../main/general";
 import { logError, logErrorSentry } from "../main/log";
-import { ElectronFile } from "../types";
+import { ElectronFile } from "../types/ipc";
 import { isPlatform } from "../utils/common/platform";
 import { generateTempFilePath } from "../utils/temp";
 import { deleteTempFile } from "./ffmpeg";

+ 2 - 1
desktop/src/services/upload.ts

@@ -1,7 +1,8 @@
 import StreamZip from "node-stream-zip";
 import path from "path";
 import { uploadStatusStore } from "../stores/upload.store";
-import { ElectronFile, FILE_PATH_KEYS, FILE_PATH_TYPE } from "../types";
+import { ElectronFile, FILE_PATH_TYPE } from "../types/ipc";
+import { FILE_PATH_KEYS } from "../types/main";
 import { getValidPaths, getZipFileStream } from "./fs";
 
 export const getSavedFilePaths = (type: FILE_PATH_TYPE) => {

+ 1 - 1
desktop/src/services/watch.ts

@@ -1,7 +1,7 @@
 import type { FSWatcher } from "chokidar";
 import ElectronLog from "electron-log";
 import { watchStore } from "../stores/watch.store";
-import { WatchMapping, WatchStoreType } from "../types";
+import { WatchMapping, WatchStoreType } from "../types/ipc";
 import { isMappingPresent } from "../utils/watch";
 
 export const addWatchMapping = async (

+ 1 - 1
desktop/src/stores/keys.store.ts

@@ -1,5 +1,5 @@
 import Store, { Schema } from "electron-store";
-import { KeysStoreType } from "../types";
+import type { KeysStoreType } from "../types/main";
 
 const keysStoreSchema: Schema<KeysStoreType> = {
     AnonymizeUserID: {

+ 1 - 1
desktop/src/stores/safeStorage.store.ts

@@ -1,5 +1,5 @@
 import Store, { Schema } from "electron-store";
-import { SafeStorageStoreType } from "../types";
+import type { SafeStorageStoreType } from "../types/main";
 
 const safeStorageSchema: Schema<SafeStorageStoreType> = {
     encryptionKey: {

+ 1 - 1
desktop/src/stores/upload.store.ts

@@ -1,5 +1,5 @@
 import Store, { Schema } from "electron-store";
-import { UploadStoreType } from "../types";
+import type { UploadStoreType } from "../types/main";
 
 const uploadStoreSchema: Schema<UploadStoreType> = {
     filePaths: {

+ 1 - 1
desktop/src/stores/userPreferences.store.ts

@@ -1,5 +1,5 @@
 import Store, { Schema } from "electron-store";
-import { UserPreferencesType } from "../types";
+import type { UserPreferencesType } from "../types/main";
 
 const userPreferencesSchema: Schema<UserPreferencesType> = {
     hideDockIcon: {

+ 1 - 1
desktop/src/stores/watch.store.ts

@@ -1,5 +1,5 @@
 import Store, { Schema } from "electron-store";
-import { WatchStoreType } from "../types";
+import { WatchStoreType } from "../types/ipc";
 
 const watchStoreSchema: Schema<WatchStoreType> = {
     mappings: {

+ 0 - 5
desktop/src/types/autoLauncher.ts

@@ -1,5 +0,0 @@
-export interface AutoLauncherClient {
-    isEnabled: () => Promise<boolean>;
-    toggleAutoLaunch: () => Promise<void>;
-    wasAutoLaunched: () => Promise<boolean>;
-}

+ 6 - 29
desktop/src/types/index.ts → desktop/src/types/ipc.ts

@@ -1,3 +1,9 @@
+/**
+ * @file types that are shared across the IPC boundary with the renderer process
+ *
+ * This file is manually kept in sync with the renderer code.
+ * See [Note: types.ts <-> preload.ts <-> ipc.ts]
+ */
 /**
  * Deprecated - Use File + webUtils.getPathForFile instead
  *
@@ -20,18 +26,6 @@ export interface ElectronFile {
     arrayBuffer: () => Promise<Uint8Array>;
 }
 
-export interface UploadStoreType {
-    filePaths: string[];
-    zipPaths: string[];
-    collectionName: string;
-}
-
-export interface KeysStoreType {
-    AnonymizeUserID: {
-        id: string;
-    };
-}
-
 interface WatchMappingSyncedFile {
     path: string;
     uploadedFileID: number;
@@ -55,23 +49,6 @@ export enum FILE_PATH_TYPE {
     ZIPS = "zips",
 }
 
-export const FILE_PATH_KEYS: {
-    [k in FILE_PATH_TYPE]: keyof UploadStoreType;
-} = {
-    [FILE_PATH_TYPE.ZIPS]: "zipPaths",
-    [FILE_PATH_TYPE.FILES]: "filePaths",
-};
-
-export interface SafeStorageStoreType {
-    encryptionKey: string;
-}
-
-export interface UserPreferencesType {
-    hideDockIcon: boolean;
-    skipAppVersion: string;
-    muteUpdateNotificationVersion: string;
-}
-
 export interface AppUpdateInfo {
     autoUpdatable: boolean;
     version: string;

+ 36 - 0
desktop/src/types/main.ts

@@ -0,0 +1,36 @@
+import { FILE_PATH_TYPE } from "./ipc";
+
+export interface AutoLauncherClient {
+    isEnabled: () => Promise<boolean>;
+    toggleAutoLaunch: () => Promise<void>;
+    wasAutoLaunched: () => Promise<boolean>;
+}
+
+export interface UploadStoreType {
+    filePaths: string[];
+    zipPaths: string[];
+    collectionName: string;
+}
+
+export interface KeysStoreType {
+    AnonymizeUserID: {
+        id: string;
+    };
+}
+
+export const FILE_PATH_KEYS: {
+    [k in FILE_PATH_TYPE]: keyof UploadStoreType;
+} = {
+    [FILE_PATH_TYPE.ZIPS]: "zipPaths",
+    [FILE_PATH_TYPE.FILES]: "filePaths",
+};
+
+export interface SafeStorageStoreType {
+    encryptionKey: string;
+}
+
+export interface UserPreferencesType {
+    hideDockIcon: boolean;
+    skipAppVersion: string;
+    muteUpdateNotificationVersion: string;
+}

+ 1 - 1
desktop/src/utils/watch.ts

@@ -1,4 +1,4 @@
-import { WatchMapping } from "../types";
+import { WatchMapping } from "../types/ipc";
 
 export function isMappingPresent(
     watchMappings: WatchMapping[],

+ 9 - 3
web/packages/shared/electron/types.ts

@@ -1,5 +1,10 @@
-import { ElectronFile } from "@ente/shared/upload/types";
-import { WatchMapping } from "@ente/shared/watchFolder/types";
+// Following are types shared with the Electron process. This list is manually
+// kept in sync with `desktop/src/types/ipc.ts`.
+//
+// See [Note: types.ts <-> preload.ts <-> ipc.ts]
+
+import type { ElectronFile } from "@ente/shared/upload/types";
+import type { WatchMapping } from "@ente/shared/watchFolder/types";
 
 export interface AppUpdateInfo {
     autoUpdatable: boolean;
@@ -26,7 +31,8 @@ export enum PICKED_UPLOAD_TYPE {
  * Extra APIs provided by the Node.js layer when our code is running in Electron
  *
  * This list is manually kept in sync with `desktop/src/preload.ts`. In case of
- * a mismatch, the types may lie.
+ * a mismatch, the types may lie. See also: [Note: types.ts <-> preload.ts <->
+ * ipc.ts]
  *
  * These extra objects and functions will only be available when our code is
  * running as the renderer process in Electron. So something in the code path