From 23f88b294e0dd5b08d857f5cfc707e38612b57b6 Mon Sep 17 00:00:00 2001 From: FTCHD <144691102+FTCHD@users.noreply.github.com> Date: Tue, 23 Sep 2025 21:00:18 +0200 Subject: [PATCH] check rclone running Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com> --- main.ts | 28 ++++++++++++++++++++++++++++ src-tauri/Cargo.lock | 34 ++++++++++++++++++++++++++++++++++ src-tauri/Cargo.toml | 1 + src-tauri/src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 1 deletion(-) diff --git a/main.ts b/main.ts index bb885dc..3bfa367 100644 --- a/main.ts +++ b/main.ts @@ -1,5 +1,6 @@ import * as Sentry from '@sentry/browser' import { getVersion as getUiVersion } from '@tauri-apps/api/app' +import { invoke } from '@tauri-apps/api/core' import { getCurrentWindow } from '@tauri-apps/api/window' import { ask, message } from '@tauri-apps/plugin-dialog' import { debug, error, info, trace, warn } from '@tauri-apps/plugin-log' @@ -115,6 +116,32 @@ async function validateInstance() { } } +async function checkAlreadyRunning() { + try { + const running = await invoke('is_rclone_running') + if (running) { + const confirmed = await ask( + 'Rclone is already running on this system.\n\nPlease stop it before launching Rclone UI.', + { + title: 'Rclone Already Running', + kind: 'info', + okLabel: 'Close Rclone', + cancelLabel: 'Exit UI', + } + ) + if (confirmed) { + const result = await invoke('stop_rclone_processes') + console.log('stop_rclone_processes', result) + await new Promise((resolve) => setTimeout(resolve, 1000)) + } else { + await exit(0) + } + } + } catch (err) { + console.error('Failed to check rclone process:', err) + } +} + async function startRclone() { console.log('[startRclone]') @@ -565,6 +592,7 @@ initTray() .then(() => waitForHydration()) .then(() => checkVersion()) .then(() => validateInstance()) + .then(() => checkAlreadyRunning()) .then(() => startRclone()) .then(() => onboardUser()) .then(() => startupMounts()) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 088b199..b6b9dc0 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -265,6 +265,7 @@ dependencies = [ "sentry", "serde", "serde_json", + "sysinfo", "tauri", "tauri-build", "tauri-plugin-autostart", @@ -3316,6 +3317,15 @@ dependencies = [ "zbus", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -3523,6 +3533,16 @@ dependencies = [ "objc2-core-foundation", ] +[[package]] +name = "objc2-io-kit" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71c1c64d6120e51cd86033f67176b1cb66780c2efe34dec55176f77befd93c0a" +dependencies = [ + "libc", + "objc2-core-foundation", +] + [[package]] name = "objc2-io-surface" version = "0.3.1" @@ -5616,6 +5636,20 @@ dependencies = [ "libc", ] +[[package]] +name = "sysinfo" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753" +dependencies = [ + "libc", + "memchr", + "ntapi", + "objc2-core-foundation", + "objc2-io-kit", + "windows", +] + [[package]] name = "system-configuration" version = "0.5.1" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 8767d4c..a69acd8 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -43,6 +43,7 @@ tauri-plugin-single-instance = "2.3.4" tauri-plugin-updater = "2.9.0" tauri-plugin-clipboard-manager = "2.3.0" reqwest = { version = "0.11", features = ["json"] } +sysinfo = "0.37" [target.'cfg(target_os = "macos")'.dependencies] cocoa = "0.26" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index d0c0864..75548d7 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -10,6 +10,7 @@ use machine_uid; use std::fs::{self, File}; use std::path::Path; use zip::ZipArchive; +use sysinfo::{System}; use tauri_plugin_sentry; use sentry; @@ -181,6 +182,46 @@ fn get_uid() -> String { return machine_uid::get().unwrap(); } +#[tauri::command] +fn is_rclone_running() -> bool { + + let system = System::new_all(); + for (_pid, process) in system.processes() { + let name = process.name(); + let lower = name.to_ascii_lowercase(); + if lower == "rclone" || lower == "rclone.exe" { + return true; + } + } + false +} + +#[tauri::command] +async fn stop_rclone_processes(timeout_ms: Option) -> Result { + let timeout = timeout_ms.unwrap_or(5000); + + let system = System::new_all(); + + // Collect PIDs first to avoid holding references across await points + let mut pids: Vec = Vec::new(); + for (pid, process) in system.processes() { + let name_lower = process.name().to_ascii_lowercase(); + if name_lower == "rclone" || name_lower == "rclone.exe" { + pids.push(pid.as_u32()); + } + } + + let mut stopped: u32 = 0; + for pid in pids { + match stop_pid(pid, Some(timeout)).await { + Ok(()) => stopped += 1, + Err(_e) => {} + } + } + + Ok(stopped) +} + #[tauri::command] async fn prompt_password(title: String, message: String) -> Result, String> { prompt_text(title, message, None, Some(true)).await @@ -582,7 +623,7 @@ pub fn run() { .plugin(tauri_plugin_log::Builder::new().build()) .plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![unzip_file, get_arch, get_uid, prompt_password, prompt_text, stop_pid, update_system_rclone, test_proxy_connection]) + .invoke_handler(tauri::generate_handler![unzip_file, get_arch, get_uid, is_rclone_running, stop_rclone_processes, prompt_password, prompt_text, stop_pid, update_system_rclone, test_proxy_connection]) .setup(|_app| Ok(())) // .setup(|app| { // if cfg!(debug_assertions) {