Add update check functionality
Implement version checking and update notifications in the GUI
This commit is contained in:
@@ -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(¤t);
|
||||
|
||||
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]
|
||||
|
||||
Reference in New Issue
Block a user