Compare commits

...

2 Commits

Author SHA1 Message Date
Stefan Hacker 0714d96668 fix: .cloud Platzhalter werden bei Server-Aenderung aktualisiert
Vorher: Platzhalter wurde nur erstellt wenn er nicht existierte.
Wenn sich die Datei auf dem Server aenderte (neue Groesse, neuer
Checksum), blieb der Platzhalter mit den alten Metadaten.

Jetzt: Bei jedem Sync wird der Checksum im Platzhalter mit dem
Server-Checksum verglichen. Bei Unterschied -> Platzhalter neu
schreiben mit aktueller Groesse, Checksum und Datum.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:43:09 +02:00
Stefan Hacker b6afc05148 fix: .cloud Oeffnen - besseres Error-Handling + Fallback-Dateiname
- Dateiname: Erst aus JSON "name" Feld, Fallback: .cloud von Dateiname strippen
- Alle Fehler werden jetzt gemeldet statt verschluckt (download, lock, open)
- open::that Fehler wird zurueckgegeben statt ignoriert
- Ausfuehrliches Logging: Pfade, Groesse, Lock-Status
- Pruefung ob Download-Datei existiert bevor geoeffnet wird

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 02:41:58 +02:00
2 changed files with 59 additions and 18 deletions
+45 -15
View File
@@ -230,36 +230,66 @@ async fn run_sync_now(state: State<'_, AppState>) -> Result<Vec<String>, String>
#[tauri::command]
async fn open_cloud_file(state: State<'_, AppState>, cloud_path: String) -> Result<String, String> {
let engine = state.api.lock().unwrap().clone()
.ok_or("Nicht eingeloggt")?;
let api = state.api.lock().unwrap().clone()
.ok_or("Nicht eingeloggt - bitte zuerst anmelden")?;
let path = PathBuf::from(&cloud_path);
let content = std::fs::read_to_string(&path).map_err(|e| e.to_string())?;
let placeholder: serde_json::Value = serde_json::from_str(&content).map_err(|e| e.to_string())?;
let file_id = placeholder.get("id").and_then(|v| v.as_i64()).ok_or("Keine ID")?;
let file_name = placeholder.get("name").and_then(|v| v.as_str()).unwrap_or("file");
if !path.exists() {
return Err(format!("Datei nicht gefunden: {}", cloud_path));
}
let real_path = path.parent().unwrap().join(file_name);
// Read placeholder JSON
let content = std::fs::read_to_string(&path)
.map_err(|e| format!("Platzhalter lesen: {}", e))?;
let placeholder: serde_json::Value = serde_json::from_str(&content)
.map_err(|e| format!("Platzhalter ungueltig: {}", e))?;
let file_id = placeholder.get("id").and_then(|v| v.as_i64())
.ok_or("Keine Datei-ID im Platzhalter")?;
// Download
engine.download_file(file_id, &real_path).await?;
// Get real filename: from JSON "name" field, or strip .cloud from filename
let file_name = placeholder.get("name")
.and_then(|v| v.as_str())
.map(|s| s.to_string())
.unwrap_or_else(|| {
let name = path.file_name().unwrap().to_string_lossy().to_string();
name.strip_suffix(".cloud").unwrap_or(&name).to_string()
});
// Remove placeholder
let real_path = path.parent().unwrap().join(&file_name);
eprintln!("[OpenCloud] {} -> {} (ID: {})", cloud_path, real_path.display(), file_id);
// Download the actual file
api.download_file(file_id, &real_path).await
.map_err(|e| format!("Download fehlgeschlagen: {}", e))?;
// Verify file was downloaded
if !real_path.exists() {
return Err(format!("Download fehlgeschlagen - Datei nicht vorhanden: {}", real_path.display()));
}
eprintln!("[OpenCloud] Downloaded {} bytes", std::fs::metadata(&real_path).map(|m| m.len()).unwrap_or(0));
// Remove .cloud placeholder
std::fs::remove_file(&path).ok();
// Lock on server
let _ = engine.lock_file(file_id, "Desktop Sync Client").await;
let cloud_name = path.file_name().unwrap().to_string_lossy().to_string();
match api.lock_file(file_id, "Desktop Sync Client").await {
Ok(_) => eprintln!("[OpenCloud] Locked file {}", file_id),
Err(e) => eprintln!("[OpenCloud] Lock failed (continuing): {}", e),
}
state.locked_files.lock().unwrap().push(file_id);
// Track opened file for auto-close detection
// Track for auto-close detection
state.opened_files.lock().unwrap().insert(file_id, OpenedFile {
_file_id: file_id,
real_path: real_path.clone(),
cloud_name: path.file_name().unwrap().to_string_lossy().to_string(),
cloud_name,
});
// Open with default application
let _ = open::that(&real_path);
// Open with default application for this file type
eprintln!("[OpenCloud] Opening with default app: {}", real_path.display());
open::that(&real_path)
.map_err(|e| format!("Oeffnen fehlgeschlagen: {} - {}", real_path.display(), e))?;
Ok(real_path.to_string_lossy().to_string())
}
+14 -3
View File
@@ -154,9 +154,18 @@ impl SyncEngine {
continue;
}
// Create .cloud placeholder
// Create or update .cloud placeholder
let cloud_path = local_dir.join(format!("{}.cloud", entry.name));
if !cloud_path.exists() {
let needs_update = if cloud_path.exists() {
// Check if server version changed
if let Ok(content) = std::fs::read_to_string(&cloud_path) {
if let Ok(old) = serde_json::from_str::<CloudPlaceholder>(&content) {
old.checksum != entry.checksum.as_deref().unwrap_or("")
} else { true }
} else { true }
} else { true };
if needs_update {
let placeholder = CloudPlaceholder {
id: entry.id,
name: entry.name.clone(),
@@ -167,7 +176,9 @@ impl SyncEngine {
};
if let Ok(json) = serde_json::to_string_pretty(&placeholder) {
std::fs::write(&cloud_path, json).ok();
log.push(format!("Platzhalter: {}.cloud", entry.name));
if !cloud_path.exists() {
log.push(format!("Platzhalter: {}.cloud", entry.name));
}
}
}
}