fix: Virtual Mode laedt neue lokale Dateien jetzt hoch

Problem: Im Virtual Mode wurden nur .cloud Platzhalter fuer
Server-Dateien erstellt, aber neue lokale Dateien wurden nie
hochgeladen. Der Watcher hat die Aenderung erkannt aber der
Sync hat sie ignoriert.

Fix: sync_upload_new() wird jetzt auch im Virtual Mode aufgerufen.
Scannt den lokalen Ordner nach Dateien die auf dem Server nicht
existieren und laedt sie hoch. Auch geaenderte lokale Dateien
(Checksum-Vergleich) werden aktualisiert. Gesperrte Dateien
werden zurueckgehalten.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Hacker 2026-04-12 01:04:03 +02:00
parent 607d18a7e2
commit 81574c8991
1 changed files with 68 additions and 0 deletions

View File

@ -67,6 +67,8 @@ impl SyncEngine {
match sp.mode {
SyncMode::Virtual => {
self.sync_virtual(&entries, &local_dir, &sp.server_path, &mut log).await;
// Also upload new local files (not on server yet)
self.sync_upload_new(&entries, &local_dir, sp.server_folder_id, &mut log).await;
}
SyncMode::Full => {
self.sync_full_download(&entries, &local_dir, &mut log).await;
@ -147,6 +149,72 @@ impl SyncEngine {
}
}
/// Upload new local files that don't exist on server yet (for both Virtual + Full mode)
async fn sync_upload_new(&self, server_entries: &[FileEntry], local_dir: &Path,
parent_id: Option<i64>, log: &mut Vec<String>) {
let server_names: std::collections::HashSet<String> = server_entries.iter()
.map(|e| e.name.clone()).collect();
let entries = match std::fs::read_dir(local_dir) {
Ok(e) => e,
Err(_) => return,
};
for entry in entries.flatten() {
let name = entry.file_name().to_string_lossy().to_string();
let path = entry.path();
// Skip hidden, temp, .cloud files
if name.starts_with('.') || name.starts_with('~')
|| name.ends_with(".tmp") || name.ends_with(".cloud") {
continue;
}
if path.is_dir() {
// New folder: create on server + recurse
if !server_names.contains(&name) {
match self.api.create_folder(&name, parent_id).await {
Ok(folder) => {
log.push(format!("Ordner erstellt: {}", name));
Box::pin(self.sync_upload_new(&[], &path, Some(folder.id), log)).await;
}
Err(e) => log.push(format!("Ordner-Fehler {}: {}", name, e)),
}
} else {
// Existing folder: recurse into it
let sub = server_entries.iter().find(|e| e.name == name);
let children = sub.and_then(|e| e.children.as_ref())
.map(|c| c.as_slice()).unwrap_or(&[]);
let sub_id = sub.map(|e| e.id);
Box::pin(self.sync_upload_new(children, &path, sub_id, log)).await;
}
} else {
// New file: upload
if !server_names.contains(&name) {
match self.api.upload_file(&path, parent_id).await {
Ok(_) => log.push(format!("Hochgeladen: {}", name)),
Err(e) => log.push(format!("Upload-Fehler {}: {}", name, e)),
}
} else {
// Existing file: check if changed (checksum compare)
if let Some(se) = server_entries.iter().find(|e| e.name == name) {
if !se.locked.unwrap_or(false) {
let local_hash = compute_file_hash(&path);
if local_hash != se.checksum.as_deref().unwrap_or("") {
match self.api.upload_file(&path, parent_id).await {
Ok(_) => log.push(format!("Aktualisiert: {}", name)),
Err(e) => log.push(format!("Upload-Fehler {}: {}", name, e)),
}
}
} else {
log.push(format!("Zurueckgehalten (gesperrt): {}", name));
}
}
}
}
}
}
/// Full sync: download all files from server
async fn sync_full_download(&self, entries: &[FileEntry], local_dir: &Path,
log: &mut Vec<String>) {