Remove one copy of duplication from IPC types

This commit is contained in:
Manav Rathi 2024-03-26 20:50:30 +05:30
parent b0ca3a1a9f
commit ac97d65c12
No known key found for this signature in database
25 changed files with 99 additions and 115 deletions

View file

@ -4,7 +4,7 @@ import {
getSavedFilePaths, getSavedFilePaths,
} from "../services/upload"; } from "../services/upload";
import { uploadStatusStore } from "../stores/upload.store"; 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 () => { export const getPendingUploads = async () => {
const filePaths = getSavedFilePaths(FILE_PATH_TYPE.FILES); const filePaths = getSavedFilePaths(FILE_PATH_TYPE.FILES);

View file

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

View file

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

View file

@ -4,6 +4,8 @@
* *
* This file is meant as a sibling to `preload.ts`, but this one runs in the * 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/`. * 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"; import type { FSWatcher } from "chokidar";
@ -44,7 +46,7 @@ import type {
FILE_PATH_TYPE, FILE_PATH_TYPE,
Model, Model,
WatchMapping, WatchMapping,
} from "../types"; } from "../types/ipc";
import { import {
selectDirectory, selectDirectory,
showUploadDirsDialog, showUploadDirsDialog,
@ -95,7 +97,7 @@ export const attachIPCHandlers = () => {
ipcMain.handle("openLogDirectory", (_) => openLogDirectory()); 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("logToDisk", (_, message) => logToDisk(message));
ipcMain.on("clear-electron-store", (_) => { ipcMain.on("clear-electron-store", (_) => {

View file

@ -24,43 +24,43 @@
* file. However, since this is just boilerplate code providing a bridge between * 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 * the main and renderer, we avoid introducing another moving part into the mix
* and just keep the entire preload setup in this single file. * 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 { contextBridge, ipcRenderer } from "electron/renderer";
import type { ElectronFile } from "./types";
// 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 // - General
/** Return the version of the desktop app. */
const appVersion = (): Promise<string> => ipcRenderer.invoke("appVersion"); 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> => const openDirectory = (dirPath: string): Promise<void> =>
ipcRenderer.invoke("openDirectory"); ipcRenderer.invoke("openDirectory");
/**
* Open the app's log directory in the system's folder viewer.
*
* @see {@link openDirectory}
*/
const openLogDirectory = (): Promise<void> => const openLogDirectory = (): Promise<void> =>
ipcRenderer.invoke("openLogDirectory"); ipcRenderer.invoke("openLogDirectory");
/**
* Log the given {@link message} to the on-disk log file maintained by the
* desktop app.
*/
const logToDisk = (message: string): void => const logToDisk = (message: string): void =>
ipcRenderer.send("logToDisk", message); ipcRenderer.send("logToDisk", message);
/**
* Return true if there is a file or directory at the given
* {@link path}.
*/
const fsExists = (path: string): Promise<boolean> => const fsExists = (path: string): Promise<boolean> =>
ipcRenderer.invoke("fsExists", path); ipcRenderer.invoke("fsExists", path);
@ -85,12 +85,6 @@ const getEncryptionKey = (): Promise<string> =>
// - App update // - App update
/* preload: duplicated */
interface AppUpdateInfo {
autoUpdatable: boolean;
version: string;
}
const registerUpdateEventListener = ( const registerUpdateEventListener = (
showUpdateDialog: (updateInfo: AppUpdateInfo) => void, showUpdateDialog: (updateInfo: AppUpdateInfo) => void,
) => { ) => {
@ -148,12 +142,6 @@ const runFFmpegCmd = (
// - ML // - ML
/* preload: duplicated Model */
enum Model {
GGML_CLIP = "ggml-clip",
ONNX_CLIP = "onnx-clip",
}
const computeImageEmbedding = ( const computeImageEmbedding = (
model: Model, model: Model,
imageData: Uint8Array, imageData: Uint8Array,
@ -218,22 +206,6 @@ const addWatchMapping = (
const removeWatchMapping = (folderPath: string): Promise<void> => const removeWatchMapping = (folderPath: string): Promise<void> =>
ipcRenderer.invoke("removeWatchMapping", folderPath); 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[]> => const getWatchMappings = (): Promise<WatchMapping[]> =>
ipcRenderer.invoke("getWatchMappings"); ipcRenderer.invoke("getWatchMappings");
@ -288,12 +260,6 @@ const getPendingUploads = (): Promise<{
type: string; type: string;
}> => ipcRenderer.invoke("getPendingUploads"); }> => ipcRenderer.invoke("getPendingUploads");
/* preload: duplicated FILE_PATH_TYPE */
enum FILE_PATH_TYPE {
FILES = "files",
ZIPS = "zips",
}
const setToUploadFiles = ( const setToUploadFiles = (
type: FILE_PATH_TYPE, type: FILE_PATH_TYPE,
filePaths: string[], filePaths: string[],
@ -327,7 +293,7 @@ const getDirFiles = (dirPath: string): Promise<ElectronFile[]> =>
// Algorithm to serialize objects passed between processes. // Algorithm to serialize objects passed between processes.
// https://www.electronjs.org/docs/latest/tutorial/ipc#object-serialization // 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 // 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 // Also, ArrayBuffer is "transferable", which means it is a zero-copy operation

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,8 @@
import StreamZip from "node-stream-zip"; import StreamZip from "node-stream-zip";
import path from "path"; import path from "path";
import { uploadStatusStore } from "../stores/upload.store"; 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"; import { getValidPaths, getZipFileStream } from "./fs";
export const getSavedFilePaths = (type: FILE_PATH_TYPE) => { export const getSavedFilePaths = (type: FILE_PATH_TYPE) => {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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 * Deprecated - Use File + webUtils.getPathForFile instead
* *
@ -20,18 +26,6 @@ export interface ElectronFile {
arrayBuffer: () => Promise<Uint8Array>; arrayBuffer: () => Promise<Uint8Array>;
} }
export interface UploadStoreType {
filePaths: string[];
zipPaths: string[];
collectionName: string;
}
export interface KeysStoreType {
AnonymizeUserID: {
id: string;
};
}
interface WatchMappingSyncedFile { interface WatchMappingSyncedFile {
path: string; path: string;
uploadedFileID: number; uploadedFileID: number;
@ -55,23 +49,6 @@ export enum FILE_PATH_TYPE {
ZIPS = "zips", 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 { export interface AppUpdateInfo {
autoUpdatable: boolean; autoUpdatable: boolean;
version: string; version: string;

36
desktop/src/types/main.ts Normal file
View file

@ -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;
}

View file

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

View file

@ -1,5 +1,10 @@
import { ElectronFile } from "@ente/shared/upload/types"; // Following are types shared with the Electron process. This list is manually
import { WatchMapping } from "@ente/shared/watchFolder/types"; // 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 { export interface AppUpdateInfo {
autoUpdatable: boolean; 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 * 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 * 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 * 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 * running as the renderer process in Electron. So something in the code path