diff --git a/desktop/src/api/upload.ts b/desktop/src/api/upload.ts index f80c25977..24d0283ff 100644 --- a/desktop/src/api/upload.ts +++ b/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); diff --git a/desktop/src/main.ts b/desktop/src/main.ts index 3c56a5df5..f5bbce835 100644 --- a/desktop/src/main.ts +++ b/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 diff --git a/desktop/src/main/dialogs.ts b/desktop/src/main/dialogs.ts index 80813a78f..5f18878b5 100644 --- a/desktop/src/main/dialogs.ts +++ b/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({ diff --git a/desktop/src/main/ipc.ts b/desktop/src/main/ipc.ts index 66eca4ff8..beac3b721 100644 --- a/desktop/src/main/ipc.ts +++ b/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", (_) => { diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts index 415c9141c..4b171e28e 100644 --- a/desktop/src/preload.ts +++ b/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 => 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 => ipcRenderer.invoke("openDirectory"); -/** - * Open the app's log directory in the system's folder viewer. - * - * @see {@link openDirectory} - */ const openLogDirectory = (): Promise => 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 => ipcRenderer.invoke("fsExists", path); @@ -85,12 +85,6 @@ const getEncryptionKey = (): Promise => // - 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 => 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 => 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 => // 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 diff --git a/desktop/src/services/appUpdater.ts b/desktop/src/services/appUpdater.ts index ce31618b0..98db606a4 100644 --- a/desktop/src/services/appUpdater.ts +++ b/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, diff --git a/desktop/src/services/autoLauncher.ts b/desktop/src/services/autoLauncher.ts index 5cac556a9..bc1270ac9 100644 --- a/desktop/src/services/autoLauncher.ts +++ b/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"; diff --git a/desktop/src/services/autoLauncherClients/linuxAndWinAutoLauncher.ts b/desktop/src/services/autoLauncherClients/linuxAndWinAutoLauncher.ts index 132f8d1f5..761b58a06 100644 --- a/desktop/src/services/autoLauncherClients/linuxAndWinAutoLauncher.ts +++ b/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"; diff --git a/desktop/src/services/autoLauncherClients/macAutoLauncher.ts b/desktop/src/services/autoLauncherClients/macAutoLauncher.ts index fcdc7bd81..d4fc343b0 100644 --- a/desktop/src/services/autoLauncherClients/macAutoLauncher.ts +++ b/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() { diff --git a/desktop/src/services/clipService.ts b/desktop/src/services/clipService.ts index 7874d5620..049b706b6 100644 --- a/desktop/src/services/clipService.ts +++ b/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"; diff --git a/desktop/src/services/ffmpeg.ts b/desktop/src/services/ffmpeg.ts index b04c84c79..b6ac4dbda 100644 --- a/desktop/src/services/ffmpeg.ts +++ b/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"); diff --git a/desktop/src/services/fs.ts b/desktop/src/services/fs.ts index 3b9a63802..d36317720 100644 --- a/desktop/src/services/fs.ts +++ b/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; diff --git a/desktop/src/services/imageProcessor.ts b/desktop/src/services/imageProcessor.ts index 1abc78451..ffb86edea 100644 --- a/desktop/src/services/imageProcessor.ts +++ b/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"; diff --git a/desktop/src/services/upload.ts b/desktop/src/services/upload.ts index 38a628c25..2fc56fef5 100644 --- a/desktop/src/services/upload.ts +++ b/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) => { diff --git a/desktop/src/services/watch.ts b/desktop/src/services/watch.ts index ab29dbc5c..3505be744 100644 --- a/desktop/src/services/watch.ts +++ b/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 ( diff --git a/desktop/src/stores/keys.store.ts b/desktop/src/stores/keys.store.ts index 943bdb1ca..d112f045a 100644 --- a/desktop/src/stores/keys.store.ts +++ b/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 = { AnonymizeUserID: { diff --git a/desktop/src/stores/safeStorage.store.ts b/desktop/src/stores/safeStorage.store.ts index 7822e32e3..809c9623f 100644 --- a/desktop/src/stores/safeStorage.store.ts +++ b/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 = { encryptionKey: { diff --git a/desktop/src/stores/upload.store.ts b/desktop/src/stores/upload.store.ts index b918fd283..5ede1fb99 100644 --- a/desktop/src/stores/upload.store.ts +++ b/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 = { filePaths: { diff --git a/desktop/src/stores/userPreferences.store.ts b/desktop/src/stores/userPreferences.store.ts index 7e17182ad..9545b1261 100644 --- a/desktop/src/stores/userPreferences.store.ts +++ b/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 = { hideDockIcon: { diff --git a/desktop/src/stores/watch.store.ts b/desktop/src/stores/watch.store.ts index 6489ba3e8..cbc71dde7 100644 --- a/desktop/src/stores/watch.store.ts +++ b/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 = { mappings: { diff --git a/desktop/src/types/autoLauncher.ts b/desktop/src/types/autoLauncher.ts deleted file mode 100644 index 9f82d2014..000000000 --- a/desktop/src/types/autoLauncher.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface AutoLauncherClient { - isEnabled: () => Promise; - toggleAutoLaunch: () => Promise; - wasAutoLaunched: () => Promise; -} diff --git a/desktop/src/types/index.ts b/desktop/src/types/ipc.ts similarity index 69% rename from desktop/src/types/index.ts rename to desktop/src/types/ipc.ts index 9473ee6dd..93586f29a 100644 --- a/desktop/src/types/index.ts +++ b/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; } -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; diff --git a/desktop/src/types/main.ts b/desktop/src/types/main.ts new file mode 100644 index 000000000..98d04ec6e --- /dev/null +++ b/desktop/src/types/main.ts @@ -0,0 +1,36 @@ +import { FILE_PATH_TYPE } from "./ipc"; + +export interface AutoLauncherClient { + isEnabled: () => Promise; + toggleAutoLaunch: () => Promise; + wasAutoLaunched: () => Promise; +} + +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; +} diff --git a/desktop/src/utils/watch.ts b/desktop/src/utils/watch.ts index d8575ebd7..b5bf13029 100644 --- a/desktop/src/utils/watch.ts +++ b/desktop/src/utils/watch.ts @@ -1,4 +1,4 @@ -import { WatchMapping } from "../types"; +import { WatchMapping } from "../types/ipc"; export function isMappingPresent( watchMappings: WatchMapping[], diff --git a/web/packages/shared/electron/types.ts b/web/packages/shared/electron/types.ts index 7a62cc9a1..821a6072a 100644 --- a/web/packages/shared/electron/types.ts +++ b/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