diff --git a/src-tauri/src/browser_runner.rs b/src-tauri/src/browser_runner.rs index 2d56e5f..2f05c36 100644 --- a/src-tauri/src/browser_runner.rs +++ b/src-tauri/src/browser_runner.rs @@ -38,6 +38,20 @@ impl BrowserRunner { &BROWSER_RUNNER } + // Start periodic cleanup of dead proxies + #[allow(dead_code)] + pub fn start_proxy_cleanup_task(&self, app_handle: tauri::AppHandle) { + tokio::spawn(async move { + let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(30)); + loop { + interval.tick().await; + if let Err(e) = PROXY_MANAGER.cleanup_dead_proxies(app_handle.clone()).await { + println!("Warning: Failed to cleanup dead proxies: {e}"); + } + } + }); + } + // Helper function to check if a process matches TOR/Mullvad browser fn is_tor_or_mullvad_browser( &self, @@ -242,6 +256,13 @@ impl BrowserRunner { updated_profile.process_id = Some(process_id); updated_profile.last_launch = Some(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs()); + // Update the proxy manager with the correct PID + if let Err(e) = PROXY_MANAGER.update_proxy_pid(0, process_id) { + println!("Warning: Failed to update proxy PID mapping: {e}"); + } else { + println!("Updated proxy PID mapping from temp (0) to actual PID: {process_id}"); + } + // Save the updated profile self.save_process_info(&updated_profile)?; println!( diff --git a/src-tauri/src/camoufox.rs b/src-tauri/src/camoufox.rs index 129fa82..294226c 100644 --- a/src-tauri/src/camoufox.rs +++ b/src-tauri/src/camoufox.rs @@ -226,6 +226,11 @@ impl CamoufoxNodecarLauncher { // Always add the generated custom config args.extend(["--custom-config".to_string(), custom_config]); + // Add proxy if provided + if let Some(proxy) = &config.proxy { + args.extend(["--proxy".to_string(), proxy.clone()]); + } + // Add headless flag for tests if std::env::var("CAMOUFOX_HEADLESS").is_ok() { args.push("--headless".to_string()); diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index eb13c6c..93dc28c 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -386,6 +386,33 @@ pub fn run() { } }); + // Start proxy cleanup task for dead browser processes + let app_handle_proxy_cleanup = app.handle().clone(); + tauri::async_runtime::spawn(async move { + let mut interval = tokio::time::interval(tokio::time::Duration::from_secs(30)); + + loop { + interval.tick().await; + + match crate::proxy_manager::PROXY_MANAGER + .cleanup_dead_proxies(app_handle_proxy_cleanup.clone()) + .await + { + Ok(dead_pids) => { + if !dead_pids.is_empty() { + println!( + "Cleaned up proxies for {} dead browser processes", + dead_pids.len() + ); + } + } + Err(e) => { + eprintln!("Error during proxy cleanup: {e}"); + } + } + } + }); + // Warm up nodecar binary in the background tauri::async_runtime::spawn(async move { println!("Starting nodecar warm-up..."); diff --git a/src-tauri/src/profile/manager.rs b/src-tauri/src/profile/manager.rs index 8d10901..5811607 100644 --- a/src-tauri/src/profile/manager.rs +++ b/src-tauri/src/profile/manager.rs @@ -805,22 +805,25 @@ impl ProfileManager { // Check if there's a running Camoufox instance for this profile match launcher.find_camoufox_by_profile(&profile_path_str).await { Ok(Some(camoufox_process)) => { - // Found a running instance, update profile with process info - let mut updated_profile = profile.clone(); - updated_profile.process_id = camoufox_process.processId; - if let Err(e) = self.save_profile(&updated_profile) { - println!("Warning: Failed to update Camoufox profile with process info: {e}"); - } + // Found a running instance, update profile with process info if changed + let process_id_changed = profile.process_id != camoufox_process.processId; + if process_id_changed { + let mut updated_profile = profile.clone(); + updated_profile.process_id = camoufox_process.processId; + if let Err(e) = self.save_profile(&updated_profile) { + println!("Warning: Failed to update Camoufox profile with process info: {e}"); + } - // Emit profile update event to frontend - if let Err(e) = app_handle.emit("profile-updated", &updated_profile) { - println!("Warning: Failed to emit profile update event: {e}"); - } + // Emit profile update event to frontend + if let Err(e) = app_handle.emit("profile-updated", &updated_profile) { + println!("Warning: Failed to emit profile update event: {e}"); + } - println!( - "Camoufox profile '{}' is running with PID: {:?}", - profile.name, camoufox_process.processId - ); + println!( + "Camoufox process has started for profile '{}' with PID: {:?}", + profile.name, camoufox_process.processId + ); + } Ok(true) } Ok(None) => { @@ -836,8 +839,12 @@ impl ProfileManager { if let Err(e) = app_handle.emit("profile-updated", &updated_profile) { println!("Warning: Failed to emit profile update event: {e}"); } + + println!( + "Camoufox process has stopped for profile '{}'", + profile.name + ); } - println!("Camoufox profile '{}' is not running", profile.name); Ok(false) } Err(e) => { diff --git a/src-tauri/src/proxy_manager.rs b/src-tauri/src/proxy_manager.rs index 6224fb7..0a281e0 100644 --- a/src-tauri/src/proxy_manager.rs +++ b/src-tauri/src/proxy_manager.rs @@ -438,6 +438,42 @@ impl ProxyManager { Err(format!("No proxy found for PID {old_pid}")) } } + + // Check if a process is still running + fn is_process_running(&self, pid: u32) -> bool { + use sysinfo::{Pid, System}; + let system = System::new_all(); + system.process(Pid::from(pid as usize)).is_some() + } + + // Clean up proxies for dead browser processes + pub async fn cleanup_dead_proxies( + &self, + app_handle: tauri::AppHandle, + ) -> Result, String> { + let dead_pids = { + let proxies = self.active_proxies.lock().unwrap(); + proxies + .keys() + .filter(|&&pid| pid != 0 && !self.is_process_running(pid)) // Skip temporary PID 0 + .copied() + .collect::>() + }; + + for dead_pid in &dead_pids { + println!("Cleaning up proxy for dead browser process PID: {dead_pid}"); + let _ = self.stop_proxy(app_handle.clone(), *dead_pid).await; + } + + Ok(dead_pids) + } + + // Get all active proxy PIDs for monitoring + #[allow(dead_code)] + pub fn get_active_proxy_pids(&self) -> Vec { + let proxies = self.active_proxies.lock().unwrap(); + proxies.keys().copied().collect() + } } // Create a singleton instance of the proxy manager