Electron side

This commit is contained in:
Manav Rathi 2024-05-15 13:08:21 +05:30
parent 96cd6b3759
commit 176431ba1f
No known key found for this signature in database
8 changed files with 70 additions and 60 deletions

View file

@ -17,7 +17,11 @@ import { existsSync } from "node:fs";
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import os from "node:os"; import os from "node:os";
import path from "node:path"; import path from "node:path";
import { attachFSWatchIPCHandlers, attachIPCHandlers } from "./main/ipc"; import {
attachFSWatchIPCHandlers,
attachIPCHandlers,
attachLogoutIPCHandler,
} from "./main/ipc";
import log, { initLogging } from "./main/log"; import log, { initLogging } from "./main/log";
import { createApplicationMenu, createTrayContextMenu } from "./main/menu"; import { createApplicationMenu, createTrayContextMenu } from "./main/menu";
import { setupAutoUpdater } from "./main/services/app-update"; import { setupAutoUpdater } from "./main/services/app-update";
@ -377,8 +381,12 @@ const main = () => {
void (async () => { void (async () => {
// Create window and prepare for the renderer. // Create window and prepare for the renderer.
mainWindow = createMainWindow(); mainWindow = createMainWindow();
// Setup IPC and streams.
const watcher = createWatcher(mainWindow);
attachIPCHandlers(); attachIPCHandlers();
attachFSWatchIPCHandlers(createWatcher(mainWindow)); attachFSWatchIPCHandlers(watcher);
attachLogoutIPCHandler(watcher);
registerStreamProtocol(); registerStreamProtocol();
// Configure the renderer's environment. // Configure the renderer's environment.

View file

@ -41,16 +41,13 @@ import {
fsWriteFile, fsWriteFile,
} from "./services/fs"; } from "./services/fs";
import { convertToJPEG, generateImageThumbnail } from "./services/image"; import { convertToJPEG, generateImageThumbnail } from "./services/image";
import { logout } from "./services/logout";
import { import {
clipImageEmbedding, clipImageEmbedding,
clipTextEmbeddingIfAvailable, clipTextEmbeddingIfAvailable,
} from "./services/ml-clip"; } from "./services/ml-clip";
import { detectFaces, faceEmbedding } from "./services/ml-face"; import { detectFaces, faceEmbedding } from "./services/ml-face";
import { import { encryptionKey, saveEncryptionKey } from "./services/store";
clearStores,
encryptionKey,
saveEncryptionKey,
} from "./services/store";
import { import {
clearPendingUploads, clearPendingUploads,
listZipItems, listZipItems,
@ -65,11 +62,9 @@ import {
watchFindFiles, watchFindFiles,
watchGet, watchGet,
watchRemove, watchRemove,
watchReset,
watchUpdateIgnoredFiles, watchUpdateIgnoredFiles,
watchUpdateSyncedFiles, watchUpdateSyncedFiles,
} from "./services/watch"; } from "./services/watch";
import { clearConvertToMP4Results } from "./stream";
/** /**
* Listen for IPC events sent/invoked by the renderer process, and route them to * Listen for IPC events sent/invoked by the renderer process, and route them to
@ -107,10 +102,6 @@ export const attachIPCHandlers = () => {
ipcMain.handle("selectDirectory", () => selectDirectory()); ipcMain.handle("selectDirectory", () => selectDirectory());
ipcMain.on("clearStores", () => clearStores());
ipcMain.on("clearConvertToMP4Results", () => clearConvertToMP4Results());
ipcMain.handle("saveEncryptionKey", (_, encryptionKey: string) => ipcMain.handle("saveEncryptionKey", (_, encryptionKey: string) =>
saveEncryptionKey(encryptionKey), saveEncryptionKey(encryptionKey),
); );
@ -265,6 +256,12 @@ export const attachFSWatchIPCHandlers = (watcher: FSWatcher) => {
ipcMain.handle("watchFindFiles", (_, folderPath: string) => ipcMain.handle("watchFindFiles", (_, folderPath: string) =>
watchFindFiles(folderPath), watchFindFiles(folderPath),
); );
};
ipcMain.handle("watchReset", () => watchReset(watcher));
/**
* Sibling of {@link attachIPCHandlers} specifically for use with the logout
* event with needs access to the {@link FSWatcher} instance.
*/
export const attachLogoutIPCHandler = (watcher: FSWatcher) => {
ipcMain.handle("logout", () => logout(watcher));
}; };

View file

@ -0,0 +1,30 @@
import type { FSWatcher } from "chokidar";
import log from "../log";
import { clearConvertToMP4Results } from "../stream";
import { clearStores } from "./store";
import { watchReset } from "./watch";
/**
* Perform the native side logout sequence.
*
* This function is guaranteed not to throw any errors.
*
* See: [Note: Do not throw during logout].
*/
export const logout = (watcher: FSWatcher) => {
try {
watchReset(watcher);
} catch (e) {
log.error("Ignoring error when resetting native folder watches", e);
}
try {
clearConvertToMP4Results();
} catch (e) {
log.error("Ignoring error when clearing convert-to-mp4 results", e);
}
try {
clearStores();
} catch (e) {
log.error("Ignoring error when clearing native stores", e);
}
}

View file

@ -151,6 +151,15 @@ export const watchFindFiles = async (dirPath: string) => {
return paths; return paths;
}; };
/**
* Stop watching all existing folder watches and remove any callbacks.
*
* This function is meant to be called when the user logs out. It stops
* all existing folder watches and forgets about any "on*" callback
* functions that have been registered.
*
* The persisted state itself gets cleared via {@link clearStores}.
*/
export const watchReset = (watcher: FSWatcher) => { export const watchReset = (watcher: FSWatcher) => {
watcher.unwatch(folderWatches().map((watch) => watch.folderPath)); watcher.unwatch(folderWatches().map((watch) => watch.folderPath));
}; };

View file

@ -63,10 +63,10 @@ const openLogDirectory = () => ipcRenderer.invoke("openLogDirectory");
const selectDirectory = () => ipcRenderer.invoke("selectDirectory"); const selectDirectory = () => ipcRenderer.invoke("selectDirectory");
const clearStores = () => ipcRenderer.send("clearStores"); const logout = () => {
watchRemoveListeners();
const clearConvertToMP4Results = () => ipcRenderer.send("logout");
ipcRenderer.send("clearConvertToMP4Results"); };
const encryptionKey = () => ipcRenderer.invoke("encryptionKey"); const encryptionKey = () => ipcRenderer.invoke("encryptionKey");
@ -212,11 +212,10 @@ const watchOnRemoveDir = (f: (path: string, watch: FolderWatch) => void) => {
const watchFindFiles = (folderPath: string) => const watchFindFiles = (folderPath: string) =>
ipcRenderer.invoke("watchFindFiles", folderPath); ipcRenderer.invoke("watchFindFiles", folderPath);
const watchReset = async () => { const watchRemoveListeners = () => {
ipcRenderer.removeAllListeners("watchAddFile"); ipcRenderer.removeAllListeners("watchAddFile");
ipcRenderer.removeAllListeners("watchRemoveFile"); ipcRenderer.removeAllListeners("watchRemoveFile");
ipcRenderer.removeAllListeners("watchRemoveDir"); ipcRenderer.removeAllListeners("watchRemoveDir");
await ipcRenderer.invoke("watchReset");
}; };
// - Upload // - Upload
@ -308,8 +307,7 @@ contextBridge.exposeInMainWorld("electron", {
openDirectory, openDirectory,
openLogDirectory, openLogDirectory,
selectDirectory, selectDirectory,
clearStores, logout,
clearConvertToMP4Results,
encryptionKey, encryptionKey,
saveEncryptionKey, saveEncryptionKey,
onMainWindowFocus, onMainWindowFocus,
@ -360,7 +358,6 @@ contextBridge.exposeInMainWorld("electron", {
onRemoveFile: watchOnRemoveFile, onRemoveFile: watchOnRemoveFile,
onRemoveDir: watchOnRemoveDir, onRemoveDir: watchOnRemoveDir,
findFiles: watchFindFiles, findFiles: watchFindFiles,
reset: watchReset,
}, },
// - Upload // - Upload

View file

@ -101,7 +101,7 @@ type AppContextType = {
setDialogBoxAttributesV2: SetDialogBoxAttributesV2; setDialogBoxAttributesV2: SetDialogBoxAttributesV2;
isCFProxyDisabled: boolean; isCFProxyDisabled: boolean;
setIsCFProxyDisabled: (disabled: boolean) => void; setIsCFProxyDisabled: (disabled: boolean) => void;
logout: () => Promise<void>; logout: () => void;
}; };
export const AppContext = createContext<AppContextType>(null); export const AppContext = createContext<AppContextType>(null);

View file

@ -15,19 +15,9 @@ export const photosLogout = async () => {
const electron = globalThis.electron; const electron = globalThis.electron;
if (electron) { if (electron) {
try { try {
await electron.watch.reset(); await electron?.logout();
} catch (e) { } catch (e) {
log.error("Ignoring error when resetting native folder watches", e); log.error("Ignoring error in native side logout sequence", e);
}
try {
await electron.clearConvertToMP4Results();
} catch (e) {
log.error("Ignoring error when clearing convert-to-mp4 results", e);
}
try {
await electron.clearStores();
} catch (e) {
log.error("Ignoring error when clearing native stores", e);
} }
} }
try { try {

View file

@ -64,19 +64,9 @@ export interface Electron {
selectDirectory: () => Promise<string | undefined>; selectDirectory: () => Promise<string | undefined>;
/** /**
* Clear any stored data. * Perform any logout related cleanup of native side state.
*
* This is a coarse single shot cleanup, meant for use in clearing any
* persisted Electron side state during logout.
*/ */
clearStores: () => Promise<void>; logout: () => Promise<void>;
/**
* Clear an state corresponding to in-flight convert-to-mp4 requests.
*
* This is meant for use during logout.
*/
clearConvertToMP4Results: () => Promise<void>;
/** /**
* Return the previously saved encryption key from persistent safe storage. * Return the previously saved encryption key from persistent safe storage.
@ -487,17 +477,6 @@ export interface Electron {
* The returned paths are guaranteed to use POSIX separators ('/'). * The returned paths are guaranteed to use POSIX separators ('/').
*/ */
findFiles: (folderPath: string) => Promise<string[]>; findFiles: (folderPath: string) => Promise<string[]>;
/**
* Stop watching all existing folder watches and remove any callbacks.
*
* This function is meant to be called when the user logs out. It stops
* all existing folder watches and forgets about any "on*" callback
* functions that have been registered.
*
* The persisted state itself gets cleared via {@link clearStores}.
*/
reset: () => Promise<void>;
}; };
// - Upload // - Upload