From 2ee05c4fe27e98d95cf45cc9302aa68988eb75c6 Mon Sep 17 00:00:00 2001 From: FTCHD Date: Sun, 2 Feb 2025 11:33:41 +0200 Subject: [PATCH] consolidate mount/unmount --- lib/menu.ts | 41 ++++++++++++++++++++++++++------------ lib/rclone/api.ts | 48 +++++++++++++++++++++++++++++++++++++++++++++ lib/rclone/mount.ts | 4 ++-- src/pages/Mount.tsx | 45 ++++++++++++++++++++++++++++++------------ 4 files changed, 111 insertions(+), 27 deletions(-) diff --git a/lib/menu.ts b/lib/menu.ts index 492d2ff..9a05004 100644 --- a/lib/menu.ts +++ b/lib/menu.ts @@ -1,15 +1,15 @@ import { Menu, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-apps/api/menu' import { getCurrentWindow } from '@tauri-apps/api/window' import { ask, message, open } from '@tauri-apps/plugin-dialog' -import { exists, remove } from '@tauri-apps/plugin-fs' +import { exists, mkdir, remove } from '@tauri-apps/plugin-fs' import { isPermissionGranted, requestPermission } from '@tauri-apps/plugin-notification' import { sendNotification } from '@tauri-apps/plugin-notification' import { openPath } from '@tauri-apps/plugin-opener' import { platform } from '@tauri-apps/plugin-os' import { exit } from '@tauri-apps/plugin-process' import { isDirectoryEmpty } from './fs' -import { deleteRemote, mountRemote } from './rclone/api' -import { dialogGetMountPlugin, needsMountPlugin, unmountRemote } from './rclone/mount' +import { deleteRemote, mountRemote, unmountRemote } from './rclone/api' +import { dialogGetMountPlugin, needsMountPlugin } from './rclone/mount' import { usePersistedStore, useStore } from './store' import { getLoadingTray, getMainTray, rebuildTrayMenu } from './tray' import { lockWindows, openFullWindow, openTrayWindow, openWindow, unlockWindows } from './window' @@ -54,7 +54,7 @@ export async function buildMenu() { console.error(`No mount point found for remote ${remote}`) return } - await unmountRemote(mountPoint) + await unmountRemote({ mountPoint }) delete storeState.mountedRemotes[remote] await rebuildTrayMenu() await message(`Successfully unmounted ${remote} from ${mountPoint}`, { @@ -63,6 +63,7 @@ export async function buildMenu() { } catch (err) { console.error('Unmount operation failed:', err) await message(`Failed to unmount ${remote}: ${err}`, { + kind: 'error', title: 'Unmount Error', }) } @@ -134,10 +135,18 @@ export async function buildMenu() { console.log('selectedPath', selectedPath) - const directoryExists = await exists(selectedPath) + let directoryExists: boolean | undefined + + try { + directoryExists = await exists(selectedPath) + } catch (err) { + console.error('Error checking if directory exists:', err) + } + console.log('directoryExists', directoryExists) const isPlatformWindows = platform() === 'windows' - if (directoryExists || isPlatformWindows) { + + if (directoryExists) { const isEmpty = await isDirectoryEmpty(selectedPath) if (!isEmpty) { // await resetMainWindow() @@ -156,12 +165,20 @@ export async function buildMenu() { if (isPlatformWindows) { await remove(selectedPath) } - } else { - await message('The selected directory does not exist.', { - title: 'Mount Error', - kind: 'error', - }) - return + } else if (!isPlatformWindows) { + try { + await mkdir(selectedPath) + } catch (error) { + console.error('Error creating directory:', error) + await message( + 'Failed to create mount directory. Try creating it manually first.', + { + title: 'Mount Error', + kind: 'error', + } + ) + return + } } // Mount the remote diff --git a/lib/rclone/api.ts b/lib/rclone/api.ts index 0418253..8ac3529 100644 --- a/lib/rclone/api.ts +++ b/lib/rclone/api.ts @@ -8,6 +8,7 @@ const SUPPORRTED_BACKENDS = ['sftp', 's3', 'b2', 'drive'] function getAuthHeader() { return + // biome-ignore lint/correctness/noUnreachable: if (platform() === 'macos') { return } @@ -319,6 +320,53 @@ export async function mountRemote({ return } +export async function unmountRemote({ + mountPoint, +}: { + mountPoint: string +}) { + const options = new URLSearchParams() + options.set('mountPoint', mountPoint) + + const r = await fetch(`http://localhost:5572/mount/unmount?${options.toString()}`, { + method: 'POST', + headers: getAuthHeader(), + }) + .then((res) => res.json()) + .catch((e) => { + console.log('error', e) + throw e + }) + + // console.log('unmountRemote', JSON.stringify(r, null, 2)) + + if ('error' in r) { + throw new Error(r.error) + } + + return +} + +export async function unmountAllRemotes() { + const r = await fetch('http://localhost:5572/mount/unmountall', { + method: 'POST', + headers: getAuthHeader(), + }) + .then((res) => res.json()) + .catch((e) => { + console.log('error', e) + throw e + }) + + console.log('unmountAllRemotes', r) + + if ('error' in r) { + throw new Error(r.error) + } + + return +} + export async function startCopy({ source, dest, diff --git a/lib/rclone/mount.ts b/lib/rclone/mount.ts index 591389d..d30cd60 100644 --- a/lib/rclone/mount.ts +++ b/lib/rclone/mount.ts @@ -74,7 +74,7 @@ export async function dialogGetMountPlugin() { } } -export async function unmountRemote(mountPoint: string, force = false) { +export async function unmount(mountPoint: string, force = false) { const command = Command.create('umount', [force ? '-f' : '', mountPoint]) const output = await command.execute() @@ -91,7 +91,7 @@ export async function unmountRemote(mountPoint: string, force = false) { cancelLabel: 'Cancel', }) if (answer) { - return await unmountRemote(mountPoint, true) + return await unmount(mountPoint, true) } throw new Error(output.stderr) } diff --git a/src/pages/Mount.tsx b/src/pages/Mount.tsx index fbeb803..660eacf 100644 --- a/src/pages/Mount.tsx +++ b/src/pages/Mount.tsx @@ -1,7 +1,7 @@ import { Accordion, AccordionItem, Avatar, Button } from '@nextui-org/react' import { getCurrentWindow } from '@tauri-apps/api/window' import { message } from '@tauri-apps/plugin-dialog' -import { exists, remove } from '@tauri-apps/plugin-fs' +import { exists, mkdir, remove } from '@tauri-apps/plugin-fs' import { revealItemInDir } from '@tauri-apps/plugin-opener' import { platform } from '@tauri-apps/plugin-os' import { @@ -94,6 +94,8 @@ export default function Mount() { }, [mountOptionsJson, vfsOptionsJson]) const handleStartMount = useCallback(async () => { + if (!dest || !source) return + setIsLoading(true) try { @@ -111,11 +113,19 @@ export default function Mount() { _mountOptions.VolumeName = source!.split('/').pop()! } - const directoryExists = await exists(dest!) + let directoryExists: boolean | undefined + + try { + directoryExists = await exists(dest) + } catch (err) { + console.error('Error checking if directory exists:', err) + } + console.log('directoryExists', directoryExists) const isPlatformWindows = platform() === 'windows' - if (directoryExists || isPlatformWindows) { - const isEmpty = await isDirectoryEmpty(dest!) + + if (directoryExists) { + const isEmpty = await isDirectoryEmpty(dest) if (!isEmpty) { // await resetMainWindow() @@ -128,18 +138,27 @@ export default function Mount() { } if (isPlatformWindows) { - await remove(dest!) + await remove(dest) + } + } else if (!isPlatformWindows) { + try { + await mkdir(dest) + } catch (error) { + console.error('Error creating directory:', error) + await message( + 'Failed to create mount directory. Try creating it manually first.', + { + title: 'Mount Error', + kind: 'error', + } + ) + return } - } else { - await message('The selected directory does not exist.', { - title: 'Mount Error', - kind: 'error', - }) - return } + await mountRemote({ - remotePath: source!, - mountPoint: dest!, + remotePath: source, + mountPoint: dest, mountOptions: _mountOptions, vfsOptions, })