Forráskód Böngészése

[desktop] More IPC enhancements and fixes (#1577)

Heading towards a wrap.
Manav Rathi 1 éve
szülő
commit
eb64cd8367

+ 3 - 0
desktop/src/main/ipc.ts

@@ -64,6 +64,7 @@ import {
     watchFindFiles,
     watchFindFiles,
     watchGet,
     watchGet,
     watchRemove,
     watchRemove,
+    watchReset,
     watchUpdateIgnoredFiles,
     watchUpdateIgnoredFiles,
     watchUpdateSyncedFiles,
     watchUpdateSyncedFiles,
 } from "./services/watch";
 } from "./services/watch";
@@ -263,4 +264,6 @@ export const attachFSWatchIPCHandlers = (watcher: FSWatcher) => {
     ipcMain.handle("watchFindFiles", (_, folderPath: string) =>
     ipcMain.handle("watchFindFiles", (_, folderPath: string) =>
         watchFindFiles(folderPath),
         watchFindFiles(folderPath),
     );
     );
+
+    ipcMain.handle("watchReset", () => watchReset(watcher));
 };
 };

+ 4 - 0
desktop/src/main/services/watch.ts

@@ -150,3 +150,7 @@ export const watchFindFiles = async (dirPath: string) => {
     }
     }
     return paths;
     return paths;
 };
 };
+
+export const watchReset = (watcher: FSWatcher) => {
+    watcher.unwatch(folderWatches().map((watch) => watch.folderPath));
+};

+ 8 - 16
desktop/src/main/stream.ts

@@ -37,26 +37,18 @@ export const registerStreamProtocol = () => {
     protocol.handle("stream", async (request: Request) => {
     protocol.handle("stream", async (request: Request) => {
         const url = request.url;
         const url = request.url;
         // The request URL contains the command to run as the host, and the
         // The request URL contains the command to run as the host, and the
-        // pathname of the file as the path. An additional path can be specified
-        // as the URL hash.
-        //
-        // For example,
-        //
-        //     stream://write/path/to/file#/path/to/another/file
-        //              host[pathname----] [pathname-2---------]
-        //
-        const { host, pathname, hash } = new URL(url);
-        // Convert e.g. "%20" to spaces.
-        const path = decodeURIComponent(pathname);
-        // `hash` begins with a "#", slice that off.
-        const hashPath = decodeURIComponent(hash.slice(1));
+        // pathname of the file(s) as the search params.
+        const { host, searchParams } = new URL(url);
         switch (host) {
         switch (host) {
             case "read":
             case "read":
-                return handleRead(path);
+                return handleRead(ensure(searchParams.get("path")));
             case "read-zip":
             case "read-zip":
-                return handleReadZip(path, hashPath);
+                return handleReadZip(
+                    ensure(searchParams.get("zipPath")),
+                    ensure(searchParams.get("entryName")),
+                );
             case "write":
             case "write":
-                return handleWrite(path, request);
+                return handleWrite(ensure(searchParams.get("path")), request);
             default:
             default:
                 return new Response("", { status: 404 });
                 return new Response("", { status: 404 });
         }
         }

+ 10 - 2
desktop/src/preload.ts

@@ -208,6 +208,13 @@ 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 () => {
+    ipcRenderer.removeAllListeners("watchAddFile");
+    ipcRenderer.removeAllListeners("watchRemoveFile");
+    ipcRenderer.removeAllListeners("watchRemoveDir");
+    await ipcRenderer.invoke("watchReset");
+};
+
 // - Upload
 // - Upload
 
 
 const pathForFile = (file: File) => webUtils.getPathForFile(file);
 const pathForFile = (file: File) => webUtils.getPathForFile(file);
@@ -323,12 +330,13 @@ contextBridge.exposeInMainWorld("electron", {
         get: watchGet,
         get: watchGet,
         add: watchAdd,
         add: watchAdd,
         remove: watchRemove,
         remove: watchRemove,
+        updateSyncedFiles: watchUpdateSyncedFiles,
+        updateIgnoredFiles: watchUpdateIgnoredFiles,
         onAddFile: watchOnAddFile,
         onAddFile: watchOnAddFile,
         onRemoveFile: watchOnRemoveFile,
         onRemoveFile: watchOnRemoveFile,
         onRemoveDir: watchOnRemoveDir,
         onRemoveDir: watchOnRemoveDir,
         findFiles: watchFindFiles,
         findFiles: watchFindFiles,
-        updateSyncedFiles: watchUpdateSyncedFiles,
-        updateIgnoredFiles: watchUpdateIgnoredFiles,
+        reset: watchReset,
     },
     },
 
 
     // - Upload
     // - Upload

+ 10 - 9
web/apps/photos/src/components/PhotoList/index.tsx

@@ -111,14 +111,13 @@ function getShrinkRatio(width: number, columns: number) {
     );
     );
 }
 }
 
 
-const ListContainer = styled(Box)<{
-    columns: number;
-    shrinkRatio: number;
-    groups?: number[];
+const ListContainer = styled(Box, {
+    shouldForwardProp: (propName) => propName != "gridTemplateColumns",
+})<{
+    gridTemplateColumns: string;
 }>`
 }>`
     display: grid;
     display: grid;
-    grid-template-columns: ${({ columns, shrinkRatio, groups }) =>
-        getTemplateColumns(columns, shrinkRatio, groups)};
+    grid-template-columns: ${(props) => props.gridTemplateColumns};
     grid-column-gap: ${GAP_BTW_TILES}px;
     grid-column-gap: ${GAP_BTW_TILES}px;
     width: 100%;
     width: 100%;
     color: #fff;
     color: #fff;
@@ -235,9 +234,11 @@ const PhotoListRow = React.memo(
         return (
         return (
             <ListItem style={style}>
             <ListItem style={style}>
                 <ListContainer
                 <ListContainer
-                    columns={columns}
-                    shrinkRatio={shrinkRatio}
-                    groups={timeStampList[index].groups}
+                    gridTemplateColumns={getTemplateColumns(
+                        columns,
+                        shrinkRatio,
+                        timeStampList[index].groups,
+                    )}
                 >
                 >
                     {renderListItem(timeStampList[index], isScrolling)}
                     {renderListItem(timeStampList[index], isScrolling)}
                 </ListContainer>
                 </ListContainer>

+ 3 - 1
web/apps/photos/src/components/Search/SearchBar/styledComponents.tsx

@@ -23,7 +23,9 @@ export const SearchMobileBox = styled(FluidContainer)`
     }
     }
 `;
 `;
 
 
-export const SearchInputWrapper = styled(CenteredFlex)<{ isOpen: boolean }>`
+export const SearchInputWrapper = styled(CenteredFlex, {
+    shouldForwardProp: (propName) => propName != "isOpen",
+})<{ isOpen: boolean }>`
     background: ${({ theme }) => theme.colors.background.base};
     background: ${({ theme }) => theme.colors.background.base};
     max-width: 484px;
     max-width: 484px;
     margin: auto;
     margin: auto;

+ 8 - 4
web/apps/photos/src/utils/native-stream.ts

@@ -39,11 +39,12 @@ export const readStream = async (
 ): Promise<{ response: Response; size: number; lastModifiedMs: number }> => {
 ): Promise<{ response: Response; size: number; lastModifiedMs: number }> => {
     let url: URL;
     let url: URL;
     if (typeof pathOrZipItem == "string") {
     if (typeof pathOrZipItem == "string") {
-        url = new URL(`stream://read${pathOrZipItem}`);
+        const params = new URLSearchParams({ path: pathOrZipItem });
+        url = new URL(`stream://read?${params.toString()}`);
     } else {
     } else {
         const [zipPath, entryName] = pathOrZipItem;
         const [zipPath, entryName] = pathOrZipItem;
-        url = new URL(`stream://read-zip${zipPath}`);
-        url.hash = entryName;
+        const params = new URLSearchParams({ zipPath, entryName });
+        url = new URL(`stream://read-zip?${params.toString()}`);
     }
     }
 
 
     const req = new Request(url, { method: "GET" });
     const req = new Request(url, { method: "GET" });
@@ -89,6 +90,9 @@ export const writeStream = async (
     path: string,
     path: string,
     stream: ReadableStream,
     stream: ReadableStream,
 ) => {
 ) => {
+    const params = new URLSearchParams({ path });
+    const url = new URL(`stream://write?${params.toString()}`);
+
     // TODO(MR): This doesn't currently work.
     // TODO(MR): This doesn't currently work.
     //
     //
     // Not sure what I'm doing wrong here; I've opened an issue upstream
     // Not sure what I'm doing wrong here; I've opened an issue upstream
@@ -119,7 +123,7 @@ export const writeStream = async (
     });
     });
     */
     */
 
 
-    const req = new Request(`stream://write${path}`, {
+    const req = new Request(url, {
         method: "POST",
         method: "POST",
         body: await new Response(stream).blob(),
         body: await new Response(stream).blob(),
     });
     });

+ 12 - 4
web/packages/accounts/services/user.ts

@@ -40,10 +40,18 @@ export const logoutUser = async () => {
     } catch (e) {
     } catch (e) {
         log.error("Ignoring error when clearing files", e);
         log.error("Ignoring error when clearing files", e);
     }
     }
-    try {
-        globalThis.electron?.clearStores();
-    } catch (e) {
-        log.error("Ignoring error when clearing electron stores", e);
+    const electron = globalThis.electron;
+    if (electron) {
+        try {
+            await electron.watch.reset();
+        } catch (e) {
+            log.error("Ignoring error when resetting native folder watches", e);
+        }
+        try {
+            await electron.clearStores();
+        } catch (e) {
+            log.error("Ignoring error when clearing native stores", e);
+        }
     }
     }
     try {
     try {
         eventBus.emit(Events.LOGOUT);
         eventBus.emit(Events.LOGOUT);

+ 11 - 0
web/packages/next/types/ipc.ts

@@ -462,6 +462,17 @@ 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

+ 4 - 1
web/packages/shared/components/Navbar/base.tsx

@@ -1,6 +1,9 @@
 import { styled } from "@mui/material";
 import { styled } from "@mui/material";
 import { FlexWrapper } from "../../components/Container";
 import { FlexWrapper } from "../../components/Container";
-const NavbarBase = styled(FlexWrapper)<{ isMobile: boolean }>`
+
+const NavbarBase = styled(FlexWrapper, {
+    shouldForwardProp: (propName) => propName != "isMobile",
+})<{ isMobile: boolean }>`
     min-height: 64px;
     min-height: 64px;
     position: sticky;
     position: sticky;
     top: 0;
     top: 0;