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

Heading towards a wrap.
This commit is contained in:
Manav Rathi 2024-05-01 19:08:41 +05:30 committed by GitHub
commit eb64cd8367
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 73 additions and 37 deletions

View file

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

View file

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

View file

@ -37,26 +37,18 @@ export const registerStreamProtocol = () => {
protocol.handle("stream", async (request: Request) => {
const url = request.url;
// 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) {
case "read":
return handleRead(path);
return handleRead(ensure(searchParams.get("path")));
case "read-zip":
return handleReadZip(path, hashPath);
return handleReadZip(
ensure(searchParams.get("zipPath")),
ensure(searchParams.get("entryName")),
);
case "write":
return handleWrite(path, request);
return handleWrite(ensure(searchParams.get("path")), request);
default:
return new Response("", { status: 404 });
}

View file

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

View file

@ -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;
grid-template-columns: ${({ columns, shrinkRatio, groups }) =>
getTemplateColumns(columns, shrinkRatio, groups)};
grid-template-columns: ${(props) => props.gridTemplateColumns};
grid-column-gap: ${GAP_BTW_TILES}px;
width: 100%;
color: #fff;
@ -235,9 +234,11 @@ const PhotoListRow = React.memo(
return (
<ListItem style={style}>
<ListContainer
columns={columns}
shrinkRatio={shrinkRatio}
groups={timeStampList[index].groups}
gridTemplateColumns={getTemplateColumns(
columns,
shrinkRatio,
timeStampList[index].groups,
)}
>
{renderListItem(timeStampList[index], isScrolling)}
</ListContainer>

View file

@ -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};
max-width: 484px;
margin: auto;

View file

@ -39,11 +39,12 @@ export const readStream = async (
): Promise<{ response: Response; size: number; lastModifiedMs: number }> => {
let url: URL;
if (typeof pathOrZipItem == "string") {
url = new URL(`stream://read${pathOrZipItem}`);
const params = new URLSearchParams({ path: pathOrZipItem });
url = new URL(`stream://read?${params.toString()}`);
} else {
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" });
@ -89,6 +90,9 @@ export const writeStream = async (
path: string,
stream: ReadableStream,
) => {
const params = new URLSearchParams({ path });
const url = new URL(`stream://write?${params.toString()}`);
// TODO(MR): This doesn't currently work.
//
// 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",
body: await new Response(stream).blob(),
});

View file

@ -40,10 +40,18 @@ export const logoutUser = async () => {
} catch (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 {
eventBus.emit(Events.LOGOUT);

View file

@ -462,6 +462,17 @@ export interface Electron {
* The returned paths are guaranteed to use POSIX separators ('/').
*/
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

View file

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