From 4a723668630e3e3bd0dc97deb790b8971cb55548 Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Thu, 30 Apr 2026 15:05:14 +0800 Subject: [PATCH] feat: add update checking functionality and UI support --- src-tauri/src/commands/mod.rs | 1 + src-tauri/src/commands/update.rs | 98 ++++++++++++++++++++++++++++++++ src-tauri/src/lib.rs | 1 + src/App.vue | 79 ++++++++++++++++++++++++- src/i18n/locales/en.ts | 10 ++++ src/i18n/locales/zh-CN.ts | 10 ++++ src/lib/tauri.ts | 14 +++++ 7 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 src-tauri/src/commands/update.rs diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 82aa9206d6..4c62e8d2bd 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -5,3 +5,4 @@ pub mod mongo_cmd; pub mod query; pub mod redis_cmd; pub mod schema; +pub mod update; diff --git a/src-tauri/src/commands/update.rs b/src-tauri/src/commands/update.rs new file mode 100644 index 0000000000..fdf9ef7c23 --- /dev/null +++ b/src-tauri/src/commands/update.rs @@ -0,0 +1,98 @@ +use serde::{Deserialize, Serialize}; + +const LATEST_RELEASE_URL: &str = "https://api.github.com/repos/t8y2/dbx/releases/latest"; + +#[derive(Debug, Deserialize)] +struct GithubRelease { + tag_name: String, + name: Option, + html_url: String, + body: Option, +} + +#[derive(Debug, Serialize)] +pub struct UpdateInfo { + pub current_version: String, + pub latest_version: String, + pub update_available: bool, + pub release_name: String, + pub release_url: String, + pub release_notes: String, +} + +#[tauri::command] +pub async fn check_for_updates() -> Result { + let client = reqwest::Client::new(); + let release = client + .get(LATEST_RELEASE_URL) + .header(reqwest::header::USER_AGENT, "dbx-update-checker") + .send() + .await + .map_err(|e| format!("Failed to check updates: {e}"))? + .error_for_status() + .map_err(|e| format!("Failed to check updates: {e}"))? + .json::() + .await + .map_err(|e| format!("Failed to parse update response: {e}"))?; + + let current_version = env!("CARGO_PKG_VERSION").to_string(); + let latest_version = normalize_version(&release.tag_name); + + Ok(UpdateInfo { + update_available: is_newer_version(&latest_version, ¤t_version), + current_version, + latest_version, + release_name: release.name.unwrap_or_else(|| release.tag_name.clone()), + release_url: release.html_url, + release_notes: release.body.unwrap_or_default(), + }) +} + +fn normalize_version(version: &str) -> String { + version.trim().trim_start_matches('v').to_string() +} + +fn parse_version(version: &str) -> Vec { + normalize_version(version) + .split(['.', '-', '+']) + .map(|part| part.parse::().unwrap_or(0)) + .collect() +} + +fn is_newer_version(latest: &str, current: &str) -> bool { + let latest_parts = parse_version(latest); + let current_parts = parse_version(current); + let max_len = latest_parts.len().max(current_parts.len()); + + for i in 0..max_len { + let latest_part = *latest_parts.get(i).unwrap_or(&0); + let current_part = *current_parts.get(i).unwrap_or(&0); + if latest_part > current_part { + return true; + } + if latest_part < current_part { + return false; + } + } + + false +} + +#[cfg(test)] +mod tests { + use super::{is_newer_version, normalize_version}; + + #[test] + fn normalizes_tag_versions() { + assert_eq!(normalize_version("v1.2.3"), "1.2.3"); + assert_eq!(normalize_version(" 0.2.0 "), "0.2.0"); + } + + #[test] + fn compares_semver_like_versions() { + assert!(is_newer_version("0.2.1", "0.2.0")); + assert!(is_newer_version("1.0.0", "0.9.9")); + assert!(!is_newer_version("0.2.0", "0.2.0")); + assert!(!is_newer_version("0.1.9", "0.2.0")); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 8806375248..ca72984220 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -75,6 +75,7 @@ pub fn run() { commands::history::load_history, commands::history::clear_history, commands::history::delete_history_entry, + commands::update::check_for_updates, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/src/App.vue b/src/App.vue index a1c0da0219..a638c288f5 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,7 +1,7 @@