diff --git a/src-tauri/src/update.rs b/src-tauri/src/update.rs index 1a9b052..9004c3c 100644 --- a/src-tauri/src/update.rs +++ b/src-tauri/src/update.rs @@ -103,7 +103,7 @@ const PACKAGE_BASE_URL: &str = "https://git.data-it-solution.de/api/packages/data/generic/claude-desktop/latest/"; /// Version der laufenden App. Wird von der CI als APP_VERSION zur Build-Zeit gesetzt. -/// Lokaler Build ohne Env-Var → "dev" → Update-Check wird übersprungen. +/// Lokaler Build ohne Env-Var → "dev" → Update wird trotzdem geprüft (jede Remote-Version gilt als neuer). const CURRENT_VERSION: &str = match option_env!("APP_VERSION") { Some(v) => v, None => "dev", @@ -171,36 +171,43 @@ fn authed_get(client: &reqwest::Client, url: &str) -> reqwest::RequestBuilder { } /// Prüft ob ein Update verfügbar ist. -/// Lokale Dev-Builds ohne APP_VERSION-Env geben sofort available=false zurück. +/// Auch Dev-Builds prüfen — jede Remote-Version gilt dann als neuer. #[tauri::command] pub async fn check_for_update() -> Result { - // Dev-Build → kein Update-Check - if CURRENT_VERSION == "dev" { + let client = reqwest::Client::new(); + let response = match authed_get(&client, UPDATE_JSON_URL).send().await { + Ok(r) => r, + Err(e) => { + // Netzwerkfehler → kein Crash, einfach "kein Update gefunden" + return Ok(UpdateStatus { + available: false, + current_version: CURRENT_VERSION.to_string(), + latest_version: None, + release_notes: Some(format!("Update-Check fehlgeschlagen (Netzwerk): {}", e)), + download_url: None, + download_size: None, + sha256: None, + }); + } + }; + + if !response.status().is_success() { + // 401/403 ohne Token oder mit falschem Token → kein Crash, nur Hinweis return Ok(UpdateStatus { available: false, current_version: CURRENT_VERSION.to_string(), latest_version: None, - release_notes: Some("Entwicklungs-Build — Updates deaktiviert.".to_string()), + release_notes: Some(format!( + "Update-Check fehlgeschlagen (HTTP {}). Token konfiguriert: {}", + response.status(), + UPDATE_TOKEN.is_some() + )), download_url: None, download_size: None, sha256: None, }); } - let client = reqwest::Client::new(); - let response = authed_get(&client, UPDATE_JSON_URL) - .send() - .await - .map_err(|e| format!("Netzwerkfehler beim Update-Check: {}", e))?; - - if !response.status().is_success() { - return Err(format!( - "Manifest-Abruf fehlgeschlagen ({}). Token konfiguriert: {}", - response.status(), - UPDATE_TOKEN.is_some() - )); - } - let manifest: UpdateManifest = response .json() .await @@ -448,13 +455,26 @@ pub fn get_current_version() -> String { CURRENT_VERSION.to_string() } +/// Prüft ob eine Version ein gültiges Zeitstempel-Format hat (nur Ziffern und Bindestriche). +/// Beispiel: "20260420-1300" → true, "dev" → false, "dev-local" → false +fn is_timestamp_version(v: &str) -> bool { + !v.is_empty() && v.chars().all(|c| c.is_ascii_digit() || c == '-') +} + /// String-Vergleich für `YYYYMMDD-HHMM`-Versionen. /// Lexikographisch > ist bei Zeitstempel-Format korrekt. -/// "dev" ist immer "nicht neuer". +/// Wenn die lokale Version kein gültiger Zeitstempel ist (z.B. "dev", "dev-local"), +/// gilt jede Remote-Version als neuer → Update immer anbieten. fn is_newer(candidate: &str, current: &str) -> bool { - if candidate == "dev" || current == "dev" { + // Remote-Version muss ein gültiger Zeitstempel sein + if !is_timestamp_version(candidate) { return false; } + // Lokale Version kein Zeitstempel → jede gültige Remote-Version ist neuer + if !is_timestamp_version(current) { + return true; + } + // Beide gültig → lexikographischer Vergleich candidate > current } @@ -471,9 +491,28 @@ mod tests { } #[test] - fn test_is_newer_dev_always_false() { + fn test_is_newer_dev_local_immer_update() { + // Lokale Version "dev" oder "dev-local" → jede gültige Remote-Version ist neuer + assert!(is_newer("20260420-1200", "dev")); + assert!(is_newer("20260420-1200", "dev-local")); + assert!(is_newer("20260101-0000", "dev")); + } + + #[test] + fn test_is_newer_remote_dev_nie() { + // Remote-Version "dev" → niemals als neuer behandeln assert!(!is_newer("dev", "20260420-1200")); - assert!(!is_newer("20260420-1200", "dev")); assert!(!is_newer("dev", "dev")); + assert!(!is_newer("dev-local", "dev")); + } + + #[test] + fn test_is_timestamp_version() { + assert!(is_timestamp_version("20260420-1300")); + assert!(is_timestamp_version("20260101-0000")); + assert!(!is_timestamp_version("dev")); + assert!(!is_timestamp_version("dev-local")); + assert!(!is_timestamp_version("v1.0.0")); + assert!(!is_timestamp_version("")); } }