refactor: browser auto-update

This commit is contained in:
zhom
2025-06-17 06:55:52 +04:00
parent 607ed66e29
commit 130f8b86d1
6 changed files with 187 additions and 8 deletions
+56
View File
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::PathBuf;
use tauri::Emitter;
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UpdateNotification {
@@ -120,6 +121,53 @@ impl AutoUpdater {
Ok(notifications)
}
pub async fn check_for_updates_with_progress(
&self,
app_handle: &tauri::AppHandle,
) {
// Check for browser updates and trigger auto-downloads
match self.check_for_updates().await {
Ok(update_notifications) => {
if !update_notifications.is_empty() {
println!(
"Found {} browser updates to auto-download",
update_notifications.len()
);
// Trigger automatic downloads for each update
for notification in update_notifications {
println!(
"Auto-downloading {} version {}",
notification.browser, notification.new_version
);
// Emit a custom event to trigger auto-download
let auto_update_event = serde_json::json!({
"browser": notification.browser,
"new_version": notification.new_version,
"notification_id": notification.id,
"affected_profiles": notification.affected_profiles
});
if let Err(e) = app_handle.emit("browser-auto-update-available", &auto_update_event) {
eprintln!(
"Failed to emit auto-update event for {}: {e}",
notification.browser
);
} else {
println!("Emitted auto-update event for {}", notification.browser);
}
}
} else {
println!("No browser updates needed");
}
}
Err(e) => {
eprintln!("Failed to check for browser updates: {e}");
}
}
}
/// Check if a specific profile has an available update
fn check_profile_update(
@@ -426,6 +474,14 @@ pub async fn complete_browser_update_with_auto_update(
.map_err(|e| format!("Failed to complete browser update: {e}"))
}
#[tauri::command]
pub async fn check_for_updates_with_progress(
app_handle: tauri::AppHandle,
) {
let updater = AutoUpdater::new();
updater.check_for_updates_with_progress(&app_handle).await;
}
#[cfg(test)]
mod tests {
use super::*;
+4 -1
View File
@@ -1913,7 +1913,10 @@ impl BrowserRunner {
if let Ok(settings) = settings_manager.load_settings() {
if settings.auto_delete_unused_binaries {
// Perform cleanup in the background after profile deletion
let _ = self.cleanup_unused_binaries_internal();
// Ignore errors since this is not critical for profile deletion
if let Err(e) = self.cleanup_unused_binaries_internal() {
println!("Warning: Failed to cleanup unused binaries: {e}");
}
}
}
+7
View File
@@ -297,6 +297,13 @@ pub fn run() {
version_updater::VersionUpdater::run_background_task().await;
});
let app_handle_auto_updater = app.handle().clone();
// Start the auto-update check task separately
tauri::async_runtime::spawn(async move {
auto_updater::check_for_updates_with_progress(app_handle_auto_updater).await;
});
let app_handle_update = app.handle().clone();
tauri::async_runtime::spawn(async move {
println!("Starting app update check at startup...");
+6 -1
View File
@@ -9,6 +9,7 @@ use tauri::Emitter;
use tokio::sync::Mutex;
use tokio::time::interval;
use crate::auto_updater::AutoUpdater;
use crate::browser_version_service::BrowserVersionService;
#[derive(Debug, Serialize, Deserialize, Clone)]
@@ -47,6 +48,7 @@ impl Default for BackgroundUpdateState {
pub struct VersionUpdater {
version_service: BrowserVersionService,
auto_updater: AutoUpdater,
app_handle: Option<tauri::AppHandle>,
}
@@ -54,6 +56,7 @@ impl VersionUpdater {
pub fn new() -> Self {
Self {
version_service: BrowserVersionService::new(),
auto_updater: AutoUpdater::new(),
app_handle: None,
}
}
@@ -379,9 +382,11 @@ impl VersionUpdater {
}
// Small delay between browsers to avoid overwhelming APIs
tokio::time::sleep(Duration::from_millis(500)).await;
tokio::time::sleep(Duration::from_millis(200)).await;
}
self.auto_updater.check_for_updates_with_progress(app_handle).await;
// Emit completion event
let progress = VersionUpdateProgress {
current_browser: "".to_string(),
+4 -4
View File
@@ -82,13 +82,13 @@ export default function Home() {
}
}, []);
// Auto-update functionality - pass loadProfiles to refresh profiles after updates
// Version updater for handling version fetching progress events and auto-updates
useVersionUpdater();
// Auto-update functionality - use the existing hook for compatibility
const updateNotifications = useUpdateNotifications(loadProfiles);
const { checkForUpdates, isUpdating } = updateNotifications;
// Version updater for handling version fetching progress events
useVersionUpdater();
// Profiles loader with update check (for initial load and manual refresh)
const loadProfilesWithUpdateCheck = useCallback(async () => {
try {
+110 -2
View File
@@ -1,6 +1,7 @@
import { getBrowserDisplayName } from "@/lib/browser-utils";
import {
dismissToast,
showAutoUpdateToast,
showErrorToast,
showSuccessToast,
showUnifiedVersionUpdateToast,
@@ -32,6 +33,13 @@ interface BrowserVersionsResult {
total_versions_count: number;
}
interface AutoUpdateEvent {
browser: string;
new_version: string;
notification_id: string;
affected_profiles: string[];
}
export function useVersionUpdater() {
const [isUpdating, setIsUpdating] = useState(false);
const [lastUpdateTime, setLastUpdateTime] = useState<number | null>(null);
@@ -86,7 +94,8 @@ export function useVersionUpdater() {
if (progress.new_versions_found > 0) {
showSuccessToast("Browser versions updated successfully", {
duration: 5000,
description: "Updates will start automatically.",
description:
"Auto-downloads will start shortly for available updates.",
});
} else {
showSuccessToast("No new browser versions found", {
@@ -117,6 +126,105 @@ export function useVersionUpdater() {
};
}, [loadUpdateStatus]);
// Listen for browser auto-update events
useEffect(() => {
const unlisten = listen<AutoUpdateEvent>(
"browser-auto-update-available",
(event) => {
const handleAutoUpdate = async () => {
const { browser, new_version, notification_id } = event.payload;
console.log("Browser auto-update event received:", event.payload);
const browserDisplayName = getBrowserDisplayName(browser);
try {
// Show auto-update start notification
showAutoUpdateToast(browserDisplayName, new_version, {
description: `Downloading ${browserDisplayName} ${new_version} automatically. Progress will be shown below.`,
});
// Dismiss the update notification in the backend
await invoke("dismiss_update_notification", {
notificationId: notification_id,
});
// Check if browser already exists before downloading
const isDownloaded = await invoke<boolean>("check_browser_exists", {
browserStr: browser,
version: new_version,
});
if (isDownloaded) {
// Browser already exists, skip download and go straight to profile update
console.log(
`${browserDisplayName} ${new_version} already exists, skipping download`,
);
showSuccessToast(
`${browserDisplayName} ${new_version} already available`,
{
description: "Updating profile configurations...",
duration: 3000,
},
);
} else {
// Download the browser - this will trigger download progress events automatically
await invoke("download_browser", {
browserStr: browser,
version: new_version,
});
}
// Complete the update with auto-update of profile versions
const updatedProfiles = await invoke<string[]>(
"complete_browser_update_with_auto_update",
{
browser,
newVersion: new_version,
},
);
// Show success message based on whether profiles were updated
if (updatedProfiles.length > 0) {
const profileText =
updatedProfiles.length === 1
? `Profile "${updatedProfiles[0]}" has been updated`
: `${updatedProfiles.length} profiles have been updated`;
showSuccessToast(`${browserDisplayName} update completed`, {
description: `${profileText} to version ${new_version}. You can now launch your browsers with the latest version.`,
duration: 6000,
});
} else {
showSuccessToast(`${browserDisplayName} update completed`, {
description: `Version ${new_version} is now available. Running profiles will use the new version when restarted.`,
duration: 6000,
});
}
} catch (error) {
console.error("Failed to handle browser auto-update:", error);
showErrorToast(`Failed to auto-update ${browserDisplayName}`, {
description:
error instanceof Error
? error.message
: "Unknown error occurred",
duration: 8000,
});
}
};
// Call the async handler
void handleAutoUpdate();
},
);
return () => {
void unlisten.then((fn) => {
fn();
});
};
}, []);
// Load update status on mount and periodically
useEffect(() => {
void loadUpdateStatus();
@@ -156,7 +264,7 @@ export function useVersionUpdater() {
});
} else if (totalNewVersions > 0) {
showSuccessToast("Browser versions updated successfully", {
description: `Found ${totalNewVersions} new versions across ${successfulUpdates} browsers. Updates will start automatically.`,
description: `Found ${totalNewVersions} new versions across ${successfulUpdates} browsers. Auto-downloads will start shortly.`,
duration: 4000,
});
} else {