brows3r_lib/commands/updater_cmd.rs
1//! Tauri commands for auto-update operations.
2//!
3//! # Commands
4//!
5//! - `updater_check` — checks the update endpoint; emits `updater:status`
6//! transitions (`Checking` → `Available`/`UpToDate`/`Error`).
7//! - `updater_install` — downloads and installs a pending update; emits
8//! `Downloading { progress }` → `Ready` (or `Error`).
9//!
10//! # OCP
11//!
12//! New updater commands are additive — each is an independent `#[tauri::command]`
13//! registered in `lib.rs`. `UpdateStatus` variants in `updater/mod.rs` extend
14//! without touching these handlers.
15
16use tauri::AppHandle;
17
18use crate::{
19 error::AppError,
20 events::{self, EventKind},
21 updater::{self, UpdateStatus},
22};
23
24// ---------------------------------------------------------------------------
25// updater_restart
26// ---------------------------------------------------------------------------
27
28/// Restart the application after a successful `updater_install`.
29///
30/// The frontend's "Restart now" button used to call
31/// `window.location.reload()` which only reloaded the WebView inside the
32/// still-running old binary — the staged update never took effect.
33/// `app.restart()` exits and re-execs into the freshly-installed binary.
34#[tauri::command]
35pub fn updater_restart(app: AppHandle) {
36 updater::restart(&app);
37}
38
39// ---------------------------------------------------------------------------
40// updater_check
41// ---------------------------------------------------------------------------
42
43/// Check the configured update endpoint for a newer release.
44///
45/// Emits `updater:status` events:
46/// 1. `{ "status": "checking" }` — immediately on entry.
47/// 2. `{ "status": "available", "version": "…", "notes": "…" }` — when a
48/// newer version is found.
49/// 3. `{ "status": "upToDate" }` — when already on latest.
50/// 4. `{ "status": "error", "message": "…" }` — on any failure.
51///
52/// Returns the final `UpdateStatus` for callers who prefer a synchronous result
53/// (the frontend can use either the return value or the events).
54#[tauri::command]
55pub async fn updater_check(app: AppHandle) -> Result<UpdateStatus, AppError> {
56 // Emit "checking" immediately so the UI can show a spinner.
57 let _ = events::emit(&app, EventKind::UpdaterStatus, &UpdateStatus::Checking);
58
59 let status = updater::check_for_update(&app).await?;
60
61 // Emit the terminal state.
62 let _ = events::emit(&app, EventKind::UpdaterStatus, &status);
63
64 Ok(status)
65}
66
67// ---------------------------------------------------------------------------
68// updater_install
69// ---------------------------------------------------------------------------
70
71/// Download and install the pending update.
72///
73/// Must be called after `updater_check` returned `Available`.
74///
75/// Emits `updater:status` events:
76/// 1. `{ "status": "downloading", "progress": null }` — download started.
77/// 2. `{ "status": "ready" }` — download + install complete; restart pending.
78/// 3. `{ "status": "error", "message": "…" }` — on any failure.
79#[tauri::command]
80pub async fn updater_install(app: AppHandle) -> Result<(), AppError> {
81 let _ = events::emit(
82 &app,
83 EventKind::UpdaterStatus,
84 &UpdateStatus::Downloading { progress: None },
85 );
86
87 match updater::install_update(&app).await {
88 Ok(()) => {
89 let _ = events::emit(&app, EventKind::UpdaterStatus, &UpdateStatus::Ready);
90 Ok(())
91 }
92 Err(e) => {
93 let status = UpdateStatus::Error {
94 message: e.message(),
95 };
96 let _ = events::emit(&app, EventKind::UpdaterStatus, &status);
97 Err(e)
98 }
99 }
100}