From 90d8e782deacf0fc88650f642cebb3e636232a88 Mon Sep 17 00:00:00 2001 From: zhom <2717306+zhom@users.noreply.github.com> Date: Sat, 9 Aug 2025 12:42:46 +0400 Subject: [PATCH] refactor: handle missing mmdb --- src-tauri/src/browser_runner.rs | 48 ++++++++++++++++++ src-tauri/src/lib.rs | 62 +++++++++++++++++++++--- src/app/page.tsx | 39 +++++++++++---- src/components/create-profile-dialog.tsx | 24 ++++++++- 4 files changed, 156 insertions(+), 17 deletions(-) diff --git a/src-tauri/src/browser_runner.rs b/src-tauri/src/browser_runner.rs index 0a7352e..56e2ceb 100644 --- a/src-tauri/src/browser_runner.rs +++ b/src-tauri/src/browser_runner.rs @@ -1044,6 +1044,27 @@ impl BrowserRunner { Ok(missing_binaries) } + /// Check if GeoIP database is missing for Camoufox profiles + pub fn check_missing_geoip_database( + &self, + ) -> Result> { + // Get all profiles + let profiles = self + .list_profiles() + .map_err(|e| format!("Failed to list profiles: {e}"))?; + + // Check if there are any Camoufox profiles + let has_camoufox_profiles = profiles.iter().any(|profile| profile.browser == "camoufox"); + + if has_camoufox_profiles { + // Check if GeoIP database is available + use crate::geoip_downloader::GeoIPDownloader; + return Ok(!GeoIPDownloader::is_geoip_database_available()); + } + + Ok(false) + } + /// Automatically download missing binaries for all profiles pub async fn ensure_all_binaries_exist( &self, @@ -1082,6 +1103,25 @@ impl BrowserRunner { } } + // Check if GeoIP database is missing for Camoufox profiles + if self.check_missing_geoip_database()? { + println!("GeoIP database is missing for Camoufox profiles, downloading..."); + + use crate::geoip_downloader::GeoIPDownloader; + let geoip_downloader = GeoIPDownloader::instance(); + + match geoip_downloader.download_geoip_database(app_handle).await { + Ok(_) => { + downloaded.push("GeoIP database for Camoufox".to_string()); + println!("GeoIP database downloaded successfully"); + } + Err(e) => { + eprintln!("Failed to download GeoIP database: {e}"); + // Don't fail the entire operation if GeoIP download fails + } + } + } + Ok(downloaded) } @@ -1794,6 +1834,14 @@ pub async fn check_missing_binaries() -> Result, S .map_err(|e| format!("Failed to check missing binaries: {e}")) } +#[tauri::command] +pub async fn check_missing_geoip_database() -> Result { + let browser_runner = BrowserRunner::instance(); + browser_runner + .check_missing_geoip_database() + .map_err(|e| format!("Failed to check missing GeoIP database: {e}")) +} + #[tauri::command] pub async fn ensure_all_binaries_exist( app_handle: tauri::AppHandle, diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index daf2091..9eb1622 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -31,13 +31,13 @@ mod version_updater; extern crate lazy_static; use browser_runner::{ - check_browser_exists, check_browser_status, check_missing_binaries, create_browser_profile_new, - delete_profile, download_browser, ensure_all_binaries_exist, fetch_browser_versions_cached_first, - fetch_browser_versions_with_count, fetch_browser_versions_with_count_cached_first, - get_browser_release_types, get_downloaded_browser_versions, get_supported_browsers, - is_browser_supported_on_platform, kill_browser_profile, launch_browser_profile, - list_browser_profiles, rename_profile, update_camoufox_config, update_profile_proxy, - update_profile_version, + check_browser_exists, check_browser_status, check_missing_binaries, check_missing_geoip_database, + create_browser_profile_new, delete_profile, download_browser, ensure_all_binaries_exist, + fetch_browser_versions_cached_first, fetch_browser_versions_with_count, + fetch_browser_versions_with_count_cached_first, get_browser_release_types, + get_downloaded_browser_versions, get_supported_browsers, is_browser_supported_on_platform, + kill_browser_profile, launch_browser_profile, list_browser_profiles, rename_profile, + update_camoufox_config, update_profile_proxy, update_profile_version, }; use settings_manager::{ @@ -69,6 +69,8 @@ use group_manager::{ get_groups_with_profile_counts, get_profile_groups, update_profile_group, }; +use geoip_downloader::GeoIPDownloader; + // Trait to extend WebviewWindow with transparent titlebar functionality pub trait WindowExt { #[cfg(target_os = "macos")] @@ -173,6 +175,20 @@ async fn delete_stored_proxy(proxy_id: String) -> Result<(), String> { .map_err(|e| format!("Failed to delete stored proxy: {e}")) } +#[tauri::command] +async fn is_geoip_database_available() -> Result { + Ok(GeoIPDownloader::is_geoip_database_available()) +} + +#[tauri::command] +async fn download_geoip_database(app_handle: tauri::AppHandle) -> Result<(), String> { + let downloader = GeoIPDownloader::instance(); + downloader + .download_geoip_database(&app_handle) + .await + .map_err(|e| format!("Failed to download GeoIP database: {e}")) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { let args: Vec = env::args().collect(); @@ -386,6 +402,35 @@ pub fn run() { } }); + // Check and download GeoIP database at startup if needed + let app_handle_geoip = app.handle().clone(); + tauri::async_runtime::spawn(async move { + // Wait a bit for the app to fully initialize + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + + let browser_runner = crate::browser_runner::BrowserRunner::instance(); + match browser_runner.check_missing_geoip_database() { + Ok(true) => { + println!("GeoIP database is missing for Camoufox profiles, downloading at startup..."); + let geoip_downloader = GeoIPDownloader::instance(); + if let Err(e) = geoip_downloader + .download_geoip_database(&app_handle_geoip) + .await + { + eprintln!("Failed to download GeoIP database at startup: {e}"); + } else { + println!("GeoIP database downloaded successfully at startup"); + } + } + Ok(false) => { + // No Camoufox profiles or GeoIP database already available + } + Err(e) => { + eprintln!("Failed to check GeoIP database status at startup: {e}"); + } + } + }); + // Start proxy cleanup task for dead browser processes let app_handle_proxy_cleanup = app.handle().clone(); tauri::async_runtime::spawn(async move { @@ -487,6 +532,7 @@ pub fn run() { detect_existing_profiles, import_browser_profile, check_missing_binaries, + check_missing_geoip_database, ensure_all_binaries_exist, create_stored_proxy, get_stored_proxies, @@ -500,6 +546,8 @@ pub fn run() { delete_profile_group, assign_profiles_to_group, delete_selected_profiles, + is_geoip_database_available, + download_geoip_database, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/app/page.tsx b/src/app/page.tsx index 87ce5c9..ede8b6e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -93,8 +93,18 @@ export default function Home() { "check_missing_binaries", ); - if (missingBinaries.length > 0) { - console.log("Found missing binaries:", missingBinaries); + // Also check for missing GeoIP database + const missingGeoIP = await invoke( + "check_missing_geoip_database", + ); + + if (missingBinaries.length > 0 || missingGeoIP) { + if (missingBinaries.length > 0) { + console.log("Found missing binaries:", missingBinaries); + } + if (missingGeoIP) { + console.log("Found missing GeoIP database for Camoufox"); + } // Group missing binaries by browser type to avoid concurrent downloads const browserMap = new Map(); @@ -109,34 +119,45 @@ export default function Home() { } // Show a toast notification about missing binaries and auto-download them - const missingList = Array.from(browserMap.entries()) + let missingList = Array.from(browserMap.entries()) .map(([browser, versions]) => `${browser}: ${versions.join(", ")}`) .join(", "); - console.log(`Downloading missing binaries: ${missingList}`); + if (missingGeoIP) { + if (missingList) { + missingList += ", GeoIP database for Camoufox"; + } else { + missingList = "GeoIP database for Camoufox"; + } + } + + console.log(`Downloading missing components: ${missingList}`); try { - // Download missing binaries sequentially by browser type to prevent conflicts + // Download missing binaries and GeoIP database sequentially to prevent conflicts const downloaded = await invoke( "ensure_all_binaries_exist", ); if (downloaded.length > 0) { console.log( - "Successfully downloaded missing binaries:", + "Successfully downloaded missing components:", downloaded, ); } } catch (downloadError) { - console.error("Failed to download missing binaries:", downloadError); + console.error( + "Failed to download missing components:", + downloadError, + ); setError( - `Failed to download missing binaries: ${JSON.stringify( + `Failed to download missing components: ${JSON.stringify( downloadError, )}`, ); } } } catch (err: unknown) { - console.error("Failed to check missing binaries:", err); + console.error("Failed to check missing components:", err); } }, []); diff --git a/src/components/create-profile-dialog.tsx b/src/components/create-profile-dialog.tsx index 8167e2d..ace563a 100644 --- a/src/components/create-profile-dialog.tsx +++ b/src/components/create-profile-dialog.tsx @@ -164,6 +164,20 @@ export function CreateProfileDialog({ } }, []); + const checkAndDownloadGeoIPDatabase = useCallback(async () => { + try { + const isAvailable = await invoke("is_geoip_database_available"); + if (!isAvailable) { + console.log("GeoIP database not available, downloading..."); + await invoke("download_geoip_database"); + console.log("GeoIP database downloaded successfully"); + } + } catch (error) { + console.error("Failed to check/download GeoIP database:", error); + // Don't show error to user as this is not critical for profile creation + } + }, []); + const loadReleaseTypes = useCallback( async (browser: string) => { // Set loading state @@ -205,8 +219,16 @@ export function CreateProfileDialog({ void loadStoredProxies(); // Load camoufox release types when dialog opens void loadReleaseTypes("camoufox"); + // Check and download GeoIP database if needed for Camoufox + void checkAndDownloadGeoIPDatabase(); } - }, [isOpen, loadSupportedBrowsers, loadStoredProxies, loadReleaseTypes]); + }, [ + isOpen, + loadSupportedBrowsers, + loadStoredProxies, + loadReleaseTypes, + checkAndDownloadGeoIPDatabase, + ]); // Load release types when browser selection changes useEffect(() => {