mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-09-30 13:09:34 +02:00
refactor: browser auto-update
This commit is contained in:
1 parent
607ed66e29
commit
130f8b86d1
6 files changed
+187
-8
No files matched your search
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use tauri::Emitter;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct UpdateNotification {
|
pub struct UpdateNotification {
|
||||||
@@ -121,6 +122,53 @@ impl AutoUpdater {
|
|||||||
Ok(notifications)
|
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
|
/// Check if a specific profile has an available update
|
||||||
fn check_profile_update(
|
fn check_profile_update(
|
||||||
&self,
|
&self,
|
||||||
@@ -426,6 +474,14 @@ pub async fn complete_browser_update_with_auto_update(
|
|||||||
.map_err(|e| format!("Failed to complete browser update: {e}"))
|
.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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -1913,7 +1913,10 @@ impl BrowserRunner {
|
|||||||
if let Ok(settings) = settings_manager.load_settings() {
|
if let Ok(settings) = settings_manager.load_settings() {
|
||||||
if settings.auto_delete_unused_binaries {
|
if settings.auto_delete_unused_binaries {
|
||||||
// Perform cleanup in the background after profile deletion
|
// 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}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,13 @@ pub fn run() {
|
|||||||
version_updater::VersionUpdater::run_background_task().await;
|
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();
|
let app_handle_update = app.handle().clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
println!("Starting app update check at startup...");
|
println!("Starting app update check at startup...");
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use tauri::Emitter;
|
|||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tokio::time::interval;
|
use tokio::time::interval;
|
||||||
|
|
||||||
|
use crate::auto_updater::AutoUpdater;
|
||||||
use crate::browser_version_service::BrowserVersionService;
|
use crate::browser_version_service::BrowserVersionService;
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
@@ -47,6 +48,7 @@ impl Default for BackgroundUpdateState {
|
|||||||
|
|
||||||
pub struct VersionUpdater {
|
pub struct VersionUpdater {
|
||||||
version_service: BrowserVersionService,
|
version_service: BrowserVersionService,
|
||||||
|
auto_updater: AutoUpdater,
|
||||||
app_handle: Option<tauri::AppHandle>,
|
app_handle: Option<tauri::AppHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ impl VersionUpdater {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
version_service: BrowserVersionService::new(),
|
version_service: BrowserVersionService::new(),
|
||||||
|
auto_updater: AutoUpdater::new(),
|
||||||
app_handle: None,
|
app_handle: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -379,9 +382,11 @@ impl VersionUpdater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Small delay between browsers to avoid overwhelming APIs
|
// 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
|
// Emit completion event
|
||||||
let progress = VersionUpdateProgress {
|
let progress = VersionUpdateProgress {
|
||||||
current_browser: "".to_string(),
|
current_browser: "".to_string(),
|
||||||
|
|||||||
+4
-4
@@ -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 updateNotifications = useUpdateNotifications(loadProfiles);
|
||||||
const { checkForUpdates, isUpdating } = updateNotifications;
|
const { checkForUpdates, isUpdating } = updateNotifications;
|
||||||
|
|
||||||
// Version updater for handling version fetching progress events
|
|
||||||
useVersionUpdater();
|
|
||||||
|
|
||||||
// Profiles loader with update check (for initial load and manual refresh)
|
// Profiles loader with update check (for initial load and manual refresh)
|
||||||
const loadProfilesWithUpdateCheck = useCallback(async () => {
|
const loadProfilesWithUpdateCheck = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { getBrowserDisplayName } from "@/lib/browser-utils";
|
import { getBrowserDisplayName } from "@/lib/browser-utils";
|
||||||
import {
|
import {
|
||||||
dismissToast,
|
dismissToast,
|
||||||
|
showAutoUpdateToast,
|
||||||
showErrorToast,
|
showErrorToast,
|
||||||
showSuccessToast,
|
showSuccessToast,
|
||||||
showUnifiedVersionUpdateToast,
|
showUnifiedVersionUpdateToast,
|
||||||
@@ -32,6 +33,13 @@ interface BrowserVersionsResult {
|
|||||||
total_versions_count: number;
|
total_versions_count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface AutoUpdateEvent {
|
||||||
|
browser: string;
|
||||||
|
new_version: string;
|
||||||
|
notification_id: string;
|
||||||
|
affected_profiles: string[];
|
||||||
|
}
|
||||||
|
|
||||||
export function useVersionUpdater() {
|
export function useVersionUpdater() {
|
||||||
const [isUpdating, setIsUpdating] = useState(false);
|
const [isUpdating, setIsUpdating] = useState(false);
|
||||||
const [lastUpdateTime, setLastUpdateTime] = useState<number | null>(null);
|
const [lastUpdateTime, setLastUpdateTime] = useState<number | null>(null);
|
||||||
@@ -86,7 +94,8 @@ export function useVersionUpdater() {
|
|||||||
if (progress.new_versions_found > 0) {
|
if (progress.new_versions_found > 0) {
|
||||||
showSuccessToast("Browser versions updated successfully", {
|
showSuccessToast("Browser versions updated successfully", {
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
description: "Updates will start automatically.",
|
description:
|
||||||
|
"Auto-downloads will start shortly for available updates.",
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
showSuccessToast("No new browser versions found", {
|
showSuccessToast("No new browser versions found", {
|
||||||
@@ -117,6 +126,105 @@ export function useVersionUpdater() {
|
|||||||
};
|
};
|
||||||
}, [loadUpdateStatus]);
|
}, [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
|
// Load update status on mount and periodically
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
void loadUpdateStatus();
|
void loadUpdateStatus();
|
||||||
@@ -156,7 +264,7 @@ export function useVersionUpdater() {
|
|||||||
});
|
});
|
||||||
} else if (totalNewVersions > 0) {
|
} else if (totalNewVersions > 0) {
|
||||||
showSuccessToast("Browser versions updated successfully", {
|
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,
|
duration: 4000,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in new issue
Block a user