From da7f7912742044124562e0cd074737046cb91ae9 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Fri, 1 Aug 2025 00:58:15 +0400 Subject: [PATCH] refactor: nodecar cleanup --- .vscode/settings.json | 1 + nodecar/src/camoufox-launcher.ts | 19 ++++------- nodecar/src/camoufox-storage.ts | 20 +---------- nodecar/src/camoufox-worker.ts | 26 +++++--------- nodecar/src/index.ts | 7 ++-- src-tauri/src/browser_runner.rs | 10 +++--- src-tauri/src/browser_version_service.rs | 4 +-- src-tauri/src/camoufox.rs | 43 ++++++++++++------------ src-tauri/src/profile/manager.rs | 4 +-- src/types.ts | 3 +- 10 files changed, 52 insertions(+), 85 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a871306..d0d239e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,6 +33,7 @@ "devedition", "doctest", "doesn", + "domcontentloaded", "donutbrowser", "dpkg", "dtolnay", diff --git a/nodecar/src/camoufox-launcher.ts b/nodecar/src/camoufox-launcher.ts index c01ebf6..8aea5cc 100644 --- a/nodecar/src/camoufox-launcher.ts +++ b/nodecar/src/camoufox-launcher.ts @@ -87,14 +87,13 @@ export async function startCamoufoxProcess( if (line.trim()) { try { const parsed = JSON.parse(line.trim()); - if (parsed.success && parsed.id === id && parsed.port) { + if (parsed.success && parsed.id === id && parsed.processId) { if (!resolved) { resolved = true; clearTimeout(timeout); - // Update config with server details - config.port = parsed.port; - config.wsEndpoint = parsed.wsEndpoint; + config.processId = parsed.processId; saveCamoufoxConfig(config); + // Unref immediately after success to detach properly child.unref(); resolve(config); @@ -177,25 +176,21 @@ export async function stopCamoufoxProcess(id: string): Promise { } try { - // Try to find and kill the worker process using multiple methods - const { spawn } = await import("node:child_process"); - - // Method 1: Kill by process pattern const killByPattern = spawn("pkill", ["-f", `camoufox-worker.*${id}`], { stdio: "ignore", }); - // Method 2: If we have a port (which is actually the process PID), kill by PID - if (config.port) { + // Method 2: If we have a process ID, kill by PID + if (config.processId) { try { - process.kill(config.port, "SIGTERM"); + process.kill(config.processId, "SIGTERM"); // Give it a moment to terminate gracefully await new Promise((resolve) => setTimeout(resolve, 2000)); // Force kill if still running try { - process.kill(config.port, "SIGKILL"); + process.kill(config.processId, "SIGKILL"); } catch { // Process already terminated } diff --git a/nodecar/src/camoufox-storage.ts b/nodecar/src/camoufox-storage.ts index e1204ac..34aaf21 100644 --- a/nodecar/src/camoufox-storage.ts +++ b/nodecar/src/camoufox-storage.ts @@ -8,8 +8,7 @@ export interface CamoufoxConfig { options: LaunchOptions; profilePath?: string; url?: string; - port?: number; - wsEndpoint?: string; + processId?: number; } const STORAGE_DIR = path.join(tmp.tmpdir, "donutbrowser", "camoufox"); @@ -126,23 +125,6 @@ export function updateCamoufoxConfig(config: CamoufoxConfig): boolean { } } -/** - * Check if a Camoufox server is running - * @param port The port to check - * @returns True if running, false otherwise - */ -export async function isServerRunning(port: number): Promise { - try { - const response = await fetch(`http://localhost:${port}/json/version`, { - method: "GET", - signal: AbortSignal.timeout(1000), - }); - return response.ok; - } catch { - return false; - } -} - /** * Generate a unique ID for a Camoufox instance * @returns A unique ID string diff --git a/nodecar/src/camoufox-worker.ts b/nodecar/src/camoufox-worker.ts index 256e218..c662824 100644 --- a/nodecar/src/camoufox-worker.ts +++ b/nodecar/src/camoufox-worker.ts @@ -27,16 +27,14 @@ export async function runCamoufoxWorker(id: string): Promise { JSON.stringify({ success: true, id: id, - port: processId, - wsEndpoint: `ws://localhost:0/camoufox-${id}`, + processId, profilePath: config.profilePath, message: "Camoufox worker started successfully", }), ); // Update config with process details - config.port = processId; - config.wsEndpoint = `ws://localhost:0/camoufox-${id}`; + config.processId = processId; saveCamoufoxConfig(config); // Handle process termination gracefully @@ -60,11 +58,16 @@ export async function runCamoufoxWorker(id: string): Promise { camoufoxOptions.user_data_dir = config.profilePath; } - // Theming + // Remove custom properties before passing to Camoufox camoufoxOptions.disableTheming = true; camoufoxOptions.showcursor = false; - // Default to headless for tests + // Set Firefox preferences for theming + if (!camoufoxOptions.firefox_user_prefs) { + camoufoxOptions.firefox_user_prefs = {}; + } + + // Default to non-headless for visibility if (camoufoxOptions.headless === undefined) { camoufoxOptions.headless = false; } @@ -72,17 +75,6 @@ export async function runCamoufoxWorker(id: string): Promise { const browser = await Camoufox(camoufoxOptions); const context = await browser.newContext(); - // Update config with actual browser details - let wsEndpoint: string | undefined; - try { - const browserWithWs = browser as any; - wsEndpoint = - browserWithWs.wsEndpoint?.() || `ws://localhost:0/camoufox-${id}`; - } catch { - wsEndpoint = `ws://localhost:0/camoufox-${id}`; - } - - config.wsEndpoint = wsEndpoint; saveCamoufoxConfig(config); // Handle URL opening if provided diff --git a/nodecar/src/index.ts b/nodecar/src/index.ts index 4e682bd..dbd4d48 100644 --- a/nodecar/src/index.ts +++ b/nodecar/src/index.ts @@ -396,9 +396,9 @@ program } } - // Theming + // Theming and cursor - these are custom properties for camoufox-js if (options.disableTheming) camoufoxOptions.disableTheming = true; - if (options.noShowcursor) camoufoxOptions.showcursor = false; + if (options.showcursor === false) camoufoxOptions.showcursor = false; // Use the launcher to start Camoufox properly const config = await startCamoufoxProcess( @@ -413,8 +413,7 @@ program console.log( JSON.stringify({ id: config.id, - port: config.port, - wsEndpoint: config.wsEndpoint, + processId: config.processId, profilePath: config.profilePath, url: config.url, }), diff --git a/src-tauri/src/browser_runner.rs b/src-tauri/src/browser_runner.rs index 17e8f56..b64eae2 100644 --- a/src-tauri/src/browser_runner.rs +++ b/src-tauri/src/browser_runner.rs @@ -239,8 +239,8 @@ impl BrowserRunner { format!("Failed to launch camoufox via nodecar: {e}").into() })?; - // For server-based Camoufox, we use the port as a unique identifier (which is actually the PID) - let process_id = camoufox_result.port.unwrap_or(0); + // For server-based Camoufox, we use the process_id + let process_id = camoufox_result.processId.unwrap_or(0); println!("Camoufox launched successfully with PID: {process_id}"); // Update profile with the process info from camoufox result @@ -808,7 +808,7 @@ impl BrowserRunner { Ok(Some(camoufox_process)) => { println!( "Found Camoufox process: {} (PID: {:?})", - camoufox_process.id, camoufox_process.port + camoufox_process.id, camoufox_process.processId ); match camoufox_launcher @@ -819,12 +819,12 @@ impl BrowserRunner { if stopped { println!( "Successfully stopped Camoufox process: {} (PID: {:?})", - camoufox_process.id, camoufox_process.port + camoufox_process.id, camoufox_process.processId ); } else { println!( "Failed to stop Camoufox process: {} (PID: {:?})", - camoufox_process.id, camoufox_process.port + camoufox_process.id, camoufox_process.processId ); } } diff --git a/src-tauri/src/browser_version_service.rs b/src-tauri/src/browser_version_service.rs index 16b791a..34f1413 100644 --- a/src-tauri/src/browser_version_service.rs +++ b/src-tauri/src/browser_version_service.rs @@ -967,8 +967,8 @@ impl BrowserVersionService { #[cfg(test)] mod tests { use super::*; - use wiremock::matchers::{method, path}; - use wiremock::{Mock, MockServer, ResponseTemplate}; + + use wiremock::MockServer; async fn setup_mock_server() -> MockServer { MockServer::start().await diff --git a/src-tauri/src/camoufox.rs b/src-tauri/src/camoufox.rs index f9cf180..aba3286 100644 --- a/src-tauri/src/camoufox.rs +++ b/src-tauri/src/camoufox.rs @@ -96,9 +96,8 @@ impl Default for CamoufoxConfig { #[allow(non_snake_case)] pub struct CamoufoxLaunchResult { pub id: String, - pub port: Option, - #[serde(alias = "ws_endpoint")] - pub wsEndpoint: Option, + #[serde(alias = "process_id")] + pub processId: Option, #[serde(alias = "profile_path")] pub profilePath: Option, pub url: Option, @@ -108,8 +107,7 @@ pub struct CamoufoxLaunchResult { struct CamoufoxInstance { #[allow(dead_code)] id: String, - port: Option, - ws_endpoint: Option, + process_id: Option, profile_path: Option, url: Option, } @@ -190,6 +188,8 @@ impl CamoufoxNodecarLauncher { debug: Some(true), enable_cache: Some(true), headless: Some(false), // Not headless for testing + disable_theming: Some(true), + showcursor: Some(false), ..Default::default() } @@ -422,7 +422,9 @@ impl CamoufoxNodecarLauncher { } if let Some(showcursor) = config.showcursor { - if !showcursor { + if showcursor { + args.push("--showcursor".to_string()); + } else { args.push("--no-showcursor".to_string()); } } @@ -456,8 +458,7 @@ impl CamoufoxNodecarLauncher { // Store the instance let instance = CamoufoxInstance { id: launch_result.id.clone(), - port: launch_result.port, - ws_endpoint: launch_result.wsEndpoint.clone(), + process_id: launch_result.processId, profile_path: launch_result.profilePath.clone(), url: launch_result.url.clone(), }; @@ -533,13 +534,12 @@ impl CamoufoxNodecarLauncher { if instance_path == target_path { // Verify the server is actually running by checking the process - if let Some(port) = instance.port { - if self.is_server_running(port).await { + if let Some(process_id) = instance.process_id { + if self.is_server_running(process_id).await { println!("Found running Camoufox instance for profile: {profile_path}"); return Ok(Some(CamoufoxLaunchResult { id: id.clone(), - port: instance.port, - wsEndpoint: instance.ws_endpoint.clone(), + processId: instance.process_id, profilePath: instance.profile_path.clone(), url: instance.url.clone(), })); @@ -566,16 +566,16 @@ impl CamoufoxNodecarLauncher { let inner = self.inner.lock().await; for (id, instance) in inner.instances.iter() { - if let Some(port) = instance.port { - // Check if the process is still alive (port is actually PID) - if !self.is_server_running(port).await { + if let Some(process_id) = instance.process_id { + // Check if the process is still alive + if !self.is_server_running(process_id).await { // Process is dead - println!("Camoufox instance {id} (PID: {port}) is no longer running"); + println!("Camoufox instance {id} (PID: {process_id}) is no longer running"); dead_instances.push(id.clone()); instances_to_remove.push(id.clone()); } } else { - // No port/PID means it's likely a dead instance + // No process_id means it's likely a dead instance println!("Camoufox instance {id} has no PID, marking as dead"); dead_instances.push(id.clone()); instances_to_remove.push(id.clone()); @@ -595,14 +595,13 @@ impl CamoufoxNodecarLauncher { Ok(dead_instances) } - /// Check if a Camoufox server is running on the given port (which is actually a PID) - async fn is_server_running(&self, port: u32) -> bool { - // For Camoufox, the "port" is actually the process PID + /// Check if a Camoufox server is running with the given process ID + async fn is_server_running(&self, process_id: u32) -> bool { // Check if the process is still running use sysinfo::{Pid, System}; let system = System::new_all(); - if let Some(process) = system.process(Pid::from(port as usize)) { + if let Some(process) = system.process(Pid::from(process_id as usize)) { // Check if this is actually a Camoufox process by looking at the command line let cmd = process.cmd(); let is_camoufox = cmd.iter().any(|arg| { @@ -611,7 +610,7 @@ impl CamoufoxNodecarLauncher { }); if is_camoufox { - println!("Found running Camoufox process with PID: {port}"); + println!("Found running Camoufox process with PID: {process_id}"); return true; } } diff --git a/src-tauri/src/profile/manager.rs b/src-tauri/src/profile/manager.rs index 1804473..7c6122b 100644 --- a/src-tauri/src/profile/manager.rs +++ b/src-tauri/src/profile/manager.rs @@ -683,7 +683,7 @@ impl ProfileManager { 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.port; + 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}"); } @@ -695,7 +695,7 @@ impl ProfileManager { println!( "Camoufox profile '{}' is running with PID: {:?}", - profile.name, camoufox_process.port + profile.name, camoufox_process.processId ); Ok(true) } diff --git a/src/types.ts b/src/types.ts index 1de6863..4171304 100644 --- a/src/types.ts +++ b/src/types.ts @@ -110,8 +110,7 @@ export interface CamoufoxConfig { export interface CamoufoxLaunchResult { id: string; - port?: number; - wsEndpoint?: string; + processId?: number; profilePath?: string; url?: string; }