diff --git a/desktop/src/main/ipc.ts b/desktop/src/main/ipc.ts index a5de4514f9..3d4e15c992 100644 --- a/desktop/src/main/ipc.ts +++ b/desktop/src/main/ipc.ts @@ -55,6 +55,7 @@ import { } from "./services/upload"; import { addWatchMapping, + folderWatchesAndFilesTherein, getWatchMappings, removeWatchMapping, updateWatchMappingIgnoredFiles, @@ -238,6 +239,10 @@ export const attachFSWatchIPCHandlers = (watcher: FSWatcher) => { removeWatchMapping(watcher, folderPath), ); + ipcMain.handle("folderWatchesAndFilesTherein", () => + folderWatchesAndFilesTherein(watcher), + ); + ipcMain.handle("getWatchMappings", () => getWatchMappings()); ipcMain.handle( diff --git a/desktop/src/main/services/watch.ts b/desktop/src/main/services/watch.ts index 1d466d4156..125d65bf9a 100644 --- a/desktop/src/main/services/watch.ts +++ b/desktop/src/main/services/watch.ts @@ -1,7 +1,13 @@ import type { FSWatcher } from "chokidar"; import ElectronLog from "electron-log"; -import { FolderWatch, WatchStoreType } from "../../types/ipc"; +import { + FolderWatch, + WatchStoreType, + type ElectronFile, +} from "../../types/ipc"; +import { isFolder } from "../fs"; import { watchStore } from "../stores/watch.store"; +import { getDirFiles } from "./fs"; export const addWatchMapping = async ( watcher: FSWatcher, @@ -99,3 +105,26 @@ export function getWatchMappings() { function setWatchMappings(watchMappings: WatchStoreType["mappings"]) { watchStore.set("mappings", watchMappings); } + +export const folderWatchesAndFilesTherein = async ( + watcher: FSWatcher, +): Promise<[watch: FolderWatch, files: ElectronFile[]][]> => { + const mappings = await getWatchMappings(); + + const activeMappings = []; + for (const mapping of mappings) { + const mappingExists = await isFolder(mapping.folderPath); + if (!mappingExists) { + await removeWatchMapping(watcher, mapping.folderPath); + } else { + activeMappings.push(mapping); + } + } + + return Promise.all( + activeMappings.map(async (mapping) => [ + mapping, + await getDirFiles(mapping.folderPath), + ]), + ); +}; diff --git a/desktop/src/preload.ts b/desktop/src/preload.ts index 2749fa50d2..a3deb1fae0 100644 --- a/desktop/src/preload.ts +++ b/desktop/src/preload.ts @@ -220,6 +220,10 @@ const addWatchMapping = ( const removeWatchMapping = (folderPath: string): Promise => ipcRenderer.invoke("removeWatchMapping", folderPath); +const folderWatchesAndFilesTherein = (): Promise< + [watch: FolderWatch, files: ElectronFile[]][] +> => ipcRenderer.invoke("folderWatchesAndFilesTherein"); + const getWatchMappings = (): Promise => ipcRenderer.invoke("getWatchMappings"); @@ -343,6 +347,7 @@ contextBridge.exposeInMainWorld("electron", { showUploadZipDialog, // - Watch + folderWatchesAndFilesTherein, registerWatcherFunctions, addWatchMapping, removeWatchMapping, diff --git a/web/apps/photos/src/services/watch.ts b/web/apps/photos/src/services/watch.ts index 2d5ef02287..7eaf391a19 100644 --- a/web/apps/photos/src/services/watch.ts +++ b/web/apps/photos/src/services/watch.ts @@ -70,25 +70,20 @@ class WatchFolderService { async getAndSyncDiffOfFiles() { try { - let mappings = await this.getWatchMappings(); - - if (!mappings?.length) { + const watchesAndFiles = + await ensureElectron().folderWatchesAndFilesTherein(); + if (!watchesAndFiles) { return; } - mappings = await this.filterOutDeletedMappings(mappings); - this.eventQueue = []; - for (const mapping of mappings) { - const filesOnDisk: ElectronFile[] = - await ensureElectron().getDirFiles(mapping.folderPath); - - this.uploadDiffOfFiles(mapping, filesOnDisk); - this.trashDiffOfFiles(mapping, filesOnDisk); + for (const [mapping, files] of watchesAndFiles) { + this.uploadDiffOfFiles(mapping, files); + this.trashDiffOfFiles(mapping, files); } } catch (e) { - log.error("error while getting and syncing diff of files", e); + log.error("Ignoring error while syncing watched folders", e); } } @@ -144,23 +139,6 @@ class WatchFolderService { } } - private async filterOutDeletedMappings( - mappings: WatchMapping[], - ): Promise { - const notDeletedMappings = []; - for (const mapping of mappings) { - const mappingExists = await ensureElectron().isFolder( - mapping.folderPath, - ); - if (!mappingExists) { - ensureElectron().removeWatchMapping(mapping.folderPath); - } else { - notDeletedMappings.push(mapping); - } - } - return notDeletedMappings; - } - pushEvent(event: EventQueueItem) { this.eventQueue.push(event); this.debouncedRunNextEvent(); diff --git a/web/packages/next/types/ipc.ts b/web/packages/next/types/ipc.ts index 85986b6391..800befa7fb 100644 --- a/web/packages/next/types/ipc.ts +++ b/web/packages/next/types/ipc.ts @@ -284,6 +284,17 @@ export interface Electron { // - Watch + /** + * Get the latest state of the watched folders. + * + * We persist the folder watches that the user has setup. This function goes + * through that list, prunes any folders that don't exist on disk anymore, + * and for each, also returns a list of files that exist in that folder. + */ + folderWatchesAndFilesTherein: () => Promise< + [watch: FolderWatch, files: ElectronFile[]][] + >; + registerWatcherFunctions: ( addFile: (file: ElectronFile) => Promise, removeFile: (path: string) => Promise,