Add update check functionality

Implement version checking and update notifications in the GUI
This commit is contained in:
2026-06-15 14:23:30 +07:00
parent 4c9eacccb7
commit 9db52595c7
8 changed files with 446 additions and 9 deletions
+63
View File
@@ -422,6 +422,69 @@ pub async fn health(state: BridgeState<'_>) -> Result<Value, String> {
data_of(state.request(Cmd::Health).await.map_err(|e| e.to_string())?)
}
// ---- Update check ----
/// Where the GUI looks for the published app version. Overridable via
/// SPACESH_UPDATE_URL for local testing against a staging server.
const DEFAULT_UPDATE_URL: &str = "https://spaceshell.ru/download/latest.json";
#[derive(serde::Serialize)]
pub struct UpdateInfo {
current: String,
latest: String,
has_update: bool,
url: String,
}
/// Parse a `major.minor.patch` string (tolerating a leading `v` and a
/// `-prerelease` suffix) into a comparable tuple; missing parts are 0.
fn parse_ver(v: &str) -> (u64, u64, u64) {
let core = v.trim().trim_start_matches('v').split('-').next().unwrap_or("");
let mut it = core.split('.').map(|p| p.parse::<u64>().unwrap_or(0));
(it.next().unwrap_or(0), it.next().unwrap_or(0), it.next().unwrap_or(0))
}
/// Fetch the server manifest and compare against the bundled app version.
/// `current` is the Tauri package version (single source of truth: tauri.conf.json),
/// which `make dmg` bumps on every build.
#[tauri::command]
pub async fn check_update(app: AppHandle) -> Result<UpdateInfo, String> {
let current = app.package_info().version.to_string();
let manifest_url =
std::env::var("SPACESH_UPDATE_URL").ok().filter(|s| !s.is_empty()).unwrap_or_else(|| DEFAULT_UPDATE_URL.to_string());
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(10))
.build()
.map_err(|e| e.to_string())?;
let manifest: Value = client
.get(&manifest_url)
.send()
.await
.map_err(|e| e.to_string())?
.json()
.await
.map_err(|e| e.to_string())?;
let latest = manifest.get("version").and_then(|v| v.as_str()).unwrap_or("").to_string();
let url = manifest
.get("url")
.and_then(|v| v.as_str())
.unwrap_or("https://spaceshell.ru/download/spacesh.dmg")
.to_string();
let has_update = !latest.is_empty() && parse_ver(&latest) > parse_ver(&current);
Ok(UpdateInfo { current, latest, has_update, url })
}
/// Open a URL in the default browser (macOS `open`). Used by the update popover's
/// download action — the GUI itself never streams the .dmg.
#[tauri::command]
pub fn open_external(url: String) -> Result<(), String> {
std::process::Command::new("open").arg(&url).spawn().map_err(|e| e.to_string())?;
Ok(())
}
// ---- Settings commands ----
#[tauri::command]