refactor: better camoufox creationg handling

This commit is contained in:
zhom
2025-08-10 14:49:01 +04:00
parent ff4aa572fe
commit 8f24410f11
3 changed files with 117 additions and 61 deletions
+7 -19
View File
@@ -1220,25 +1220,13 @@ impl BrowserRunner {
{
Ok(path) => path,
Err(e) => {
// Check if the expected archive is already present (manual download)
let expected_archive_path = browser_dir.join(&download_info.filename);
if expected_archive_path.exists() {
println!(
"Download failed, but found existing archive at {}. Continuing with extraction.",
expected_archive_path.display()
);
expected_archive_path
} else {
// Remove only the registry entry; keep any files (including a partially downloaded archive)
let _ = registry.remove_browser(&browser_str, &version);
let _ = registry.save();
// Remove browser-version pair from downloading set on error
{
let mut downloading = DOWNLOADING_BROWSERS.lock().unwrap();
downloading.remove(&download_key);
}
return Err(format!("Failed to download browser: {e}").into());
}
// Do NOT continue with extraction on failed downloads. Partial files may exist but are invalid.
// Clean registry entry and stop here so the UI can show a single, clear error.
let _ = registry.remove_browser(&browser_str, &version);
let _ = registry.save();
let mut downloading = DOWNLOADING_BROWSERS.lock().unwrap();
downloading.remove(&download_key);
return Err(format!("Failed to download browser: {e}").into());
}
};
+41 -31
View File
@@ -1,7 +1,7 @@
"use client";
import { invoke } from "@tauri-apps/api/core";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { GoPlus } from "react-icons/go";
import { LoadingButton } from "@/components/loading-button";
import { ProxyFormDialog } from "@/components/proxy-form-dialog";
@@ -109,12 +109,13 @@ export function CreateProfileDialog({
const [activeTab, setActiveTab] = useState("anti-detect");
// Regular browser states
const [selectedBrowser, setSelectedBrowser] = useState<BrowserTypeString>();
const [selectedBrowser, setSelectedBrowser] =
useState<BrowserTypeString | null>("camoufox");
const [selectedProxyId, setSelectedProxyId] = useState<string>();
const handleTabChange = (value: string) => {
if (value === "regular") {
setSelectedBrowser(undefined);
setSelectedBrowser(null);
} else if (value === "anti-detect") {
setSelectedBrowser("camoufox");
}
@@ -355,7 +356,7 @@ export function CreateProfileDialog({
// Reset all states
setProfileName("");
setSelectedBrowser(undefined);
setSelectedBrowser(null);
setSelectedProxyId(undefined);
setAvailableReleaseTypes({});
setCamoufoxReleaseTypes({});
@@ -366,40 +367,49 @@ export function CreateProfileDialog({
onClose();
};
const isCreateDisabled = () => {
if (!profileName.trim()) return true;
if (!selectedBrowser) return true;
if (isBrowserCurrentlyDownloading(selectedBrowser)) return true;
if (!isBrowserVersionAvailable(selectedBrowser)) return true;
if (selectedBrowser === "camoufox") {
return !getBestAvailableVersion(camoufoxReleaseTypes, selectedBrowser);
}
return !getBestAvailableVersion(availableReleaseTypes, selectedBrowser);
};
const updateCamoufoxConfig = (key: keyof CamoufoxConfig, value: unknown) => {
setCamoufoxConfig((prev) => ({ ...prev, [key]: value }));
};
// Check if browser version is downloaded and available
const isBrowserVersionAvailable = (browserStr: string) => {
const releaseTypes =
browserStr === "camoufox" ? camoufoxReleaseTypes : availableReleaseTypes;
const bestVersion = getBestAvailableVersion(releaseTypes, browserStr);
return bestVersion && isVersionDownloaded(bestVersion.version);
};
const isBrowserVersionAvailable = useCallback(
(browserStr: string) => {
const releaseTypes =
browserStr === "camoufox"
? camoufoxReleaseTypes
: availableReleaseTypes;
const bestVersion = getBestAvailableVersion(releaseTypes, browserStr);
return bestVersion && isVersionDownloaded(bestVersion.version);
},
[
camoufoxReleaseTypes,
availableReleaseTypes,
isVersionDownloaded,
getBestAvailableVersion,
],
);
// Check if browser is currently downloading
const isBrowserCurrentlyDownloading = (browserStr: string) => {
return isBrowserDownloading(browserStr);
};
const isBrowserCurrentlyDownloading = useCallback(
(browserStr: string) => {
return isBrowserDownloading(browserStr);
},
[isBrowserDownloading],
);
console.log(selectedBrowser);
const isCreateDisabled = useMemo(() => {
if (!profileName.trim()) return true;
if (!selectedBrowser) return true;
if (isBrowserCurrentlyDownloading(selectedBrowser)) return true;
if (!isBrowserVersionAvailable(selectedBrowser)) return true;
return false;
}, [
profileName,
selectedBrowser,
isBrowserCurrentlyDownloading,
isBrowserVersionAvailable,
]);
return (
<Dialog open={isOpen} onOpenChange={handleClose}>
@@ -639,7 +649,7 @@ export function CreateProfileDialog({
<LoadingButton
onClick={handleCreate}
isLoading={isCreating}
disabled={isCreateDisabled()}
disabled={isCreateDisabled}
>
Create
</LoadingButton>
+69 -11
View File
@@ -1,4 +1,5 @@
import { invoke } from "@tauri-apps/api/core";
import type { Event as TauriEvent } from "@tauri-apps/api/event";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import { getBrowserDisplayName } from "@/lib/browser-utils";
@@ -7,6 +8,7 @@ import {
showDownloadToast,
showErrorToast,
showSuccessToast,
showToast,
} from "@/lib/toast-utils";
interface GithubRelease {
@@ -257,21 +259,22 @@ export function useBrowserDownload() {
// Legacy isDownloading for backwards compatibility
const isDownloading = downloadingBrowsers.size > 0;
// Listen for download progress events
// Listen for download progress events (browsers) and GeoIP progress events
useEffect(() => {
let unlistenFn: (() => void) | null = null;
let unlistenBrowser: (() => void) | null = null;
let unlistenGeoip: (() => void) | null = null;
const setupListener = async () => {
const setupListeners = async () => {
try {
unlistenFn = await listen<DownloadProgress>(
// Browser binaries download progress
unlistenBrowser = await listen<DownloadProgress>(
"download-progress",
(event) => {
async (event: TauriEvent<DownloadProgress>) => {
const progress = event.payload;
setDownloadProgress(progress);
const browserName = getBrowserDisplayName(progress.browser);
// Show toast with progress
if (progress.stage === "downloading") {
const speedMBps = (
progress.speed_bytes_per_sec /
@@ -291,6 +294,16 @@ export function useBrowserDownload() {
} else if (progress.stage === "verifying") {
showDownloadToast(browserName, progress.version, "verifying");
} else if (progress.stage === "completed") {
// On completion, refresh the downloaded versions for this browser and also refresh camoufox,
// since the Create dialog implicitly uses camoufox on the anti-detect tab
try {
await Promise.all([
loadDownloadedVersions(progress.browser),
progress.browser !== "camoufox"
? loadDownloadedVersions("camoufox")
: Promise.resolve([]),
]);
} catch {}
showDownloadToast(browserName, progress.version, "completed");
setDownloadProgress(null);
}
@@ -299,20 +312,65 @@ export function useBrowserDownload() {
} catch (error) {
console.error("Failed to setup download progress listener:", error);
}
try {
// GeoIP database download progress
unlistenGeoip = await listen<{
stage: string;
percentage: number;
message: string;
}>(
"geoip-download-progress",
(
event: TauriEvent<{
stage: string;
percentage: number;
message: string;
}>,
) => {
const { stage, percentage } = event.payload;
if (stage === "downloading") {
showToast({
id: "geoip-download",
type: "download",
title: "Downloading GeoIP database",
stage: "downloading",
progress: { percentage },
});
} else if (stage === "completed") {
showToast({
id: "geoip-download",
type: "download",
title: "GeoIP database downloaded successfully!",
stage: "completed",
});
}
},
);
} catch (error) {
console.error("Failed to setup GeoIP progress listener:", error);
}
};
setupListener();
void setupListeners();
return () => {
if (unlistenFn) {
if (unlistenBrowser) {
try {
unlistenFn();
unlistenBrowser();
} catch (error) {
console.error("Failed to cleanup download progress listener:", error);
console.error("Failed to cleanup browser download listener:", error);
}
}
if (unlistenGeoip) {
try {
unlistenGeoip();
} catch (error) {
console.error("Failed to cleanup GeoIP progress listener:", error);
}
}
};
}, [formatTime]);
}, [formatTime, loadDownloadedVersions]);
return {
availableVersions,