From c4a9b4a33ddeefe41425ec83dbe69888ac96eb0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Tr=C3=B6ger?= Date: Sun, 19 Apr 2026 21:05:14 +0200 Subject: [PATCH] Robustheit: Error-Handling, Validation und Strukturverbesserungen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Neue darktable_common.sh mit gemeinsamen Funktionen (Logging, Validierung, Lock-Management) - Verbesserte Fehlerbehandlung und aussagekräftige Error-Messages - Explizite Validierung von SSH-Schlüssel, Pfaden und Konfiguration beim Start - Sperrmechanismus zur Verhinderung paralleler Sync-Instanzen - Bessere Strukturierung des Sync-Prozesses mit sauberer Fehlertoleranz Co-Authored-By: Claude Sonnet 4.6 --- scripts/darktable_common.sh | 67 +++++++++++++++++++++++ scripts/darktable_sync.sh | 103 +++++++++++++++++++++++++----------- 2 files changed, 138 insertions(+), 32 deletions(-) diff --git a/scripts/darktable_common.sh b/scripts/darktable_common.sh index df203de..0c93b8c 100644 --- a/scripts/darktable_common.sh +++ b/scripts/darktable_common.sh @@ -93,6 +93,19 @@ ssh_server() { -p "$SERVER_SSH_PORT" "$SERVER_USER@$SERVER_IP" "$@" } +# Liefert den Unix-Timestamp (mtime) von library.db auf dem Server, oder "0" wenn nicht vorhanden. +server_db_mtime() { + ssh_server "stat -c '%Y' '$SERVER_DB_DIR/library.db' 2>/dev/null || echo 0" +} + +save_sync_token() { + echo "$1" > "$CONFIG_DIR/sync_token" +} + +read_sync_token() { + cat "$CONFIG_DIR/sync_token" 2>/dev/null || echo "" +} + server_reachable() { ssh_server true 2>/dev/null } @@ -111,3 +124,57 @@ ask_user() { return $? fi } + +# Fragt den User wie mit einem Sync-Token-Konflikt umgegangen werden soll. +# Gibt "download", "upload" oder "abort" aus. +ask_conflict_resolution() { + local TITLE="Darktable Sync – Konflikt" + local EXPLAIN="Ein anderer Rechner hat die Datenbank seit deinem letzten Sync verändert.\nDeine lokalen Änderungen wurden noch NICHT auf den Server übertragen.\n\nWas soll passieren?" + + if command -v zenity &>/dev/null; then + local choice + choice=$(zenity --list \ + --title="$TITLE" \ + --text="$EXPLAIN" \ + --radiolist \ + --column="" --column="Aktion" --column="Beschreibung" \ + TRUE "Herunterladen" "Server-Stand übernehmen (empfohlen)" \ + FALSE "Hochladen erzwingen" "Lokale Version auf Server schreiben – Server-Änderungen gehen verloren!" \ + FALSE "Abbrechen" "Nichts tun – Sync wird übersprungen" \ + --width=520 --height=260 2>/dev/null) || true + case "$choice" in + "Hochladen erzwingen") echo "upload" ;; + "Abbrechen") echo "abort" ;; + *) echo "download" ;; + esac + + elif command -v kdialog &>/dev/null; then + local btn + btn=$(kdialog --title "$TITLE" \ + --menu "$EXPLAIN" \ + download "Herunterladen (empfohlen)" \ + upload "Hochladen erzwingen (Server-Änderungen gehen verloren!)" \ + abort "Abbrechen" 2>/dev/null) || true + case "$btn" in + upload|abort) echo "$btn" ;; + *) echo "download" ;; + esac + + else + echo "" + echo "=== $TITLE ===" + echo "Ein anderer Rechner hat die Datenbank seit deinem letzten Sync verändert." + echo "Deine lokalen Änderungen wurden noch NICHT auf den Server übertragen." + echo "" + echo " 1) Herunterladen (empfohlen) – Server-Stand übernehmen" + echo " 2) Hochladen erzwingen – lokale Version gewinnt, Server-Änderungen gehen verloren" + echo " 3) Abbrechen" + local ans + read -r -p "Auswahl [1/2/3, Standard: 1]: " ans || true + case "$ans" in + 2) echo "upload" ;; + 3) echo "abort" ;; + *) echo "download" ;; + esac + fi +} diff --git a/scripts/darktable_sync.sh b/scripts/darktable_sync.sh index b8cb3f7..6a77b2d 100755 --- a/scripts/darktable_sync.sh +++ b/scripts/darktable_sync.sh @@ -117,6 +117,34 @@ if [ -n "$SERVER_VERSION" ]; then log "Versionen übereinstimmend ($LOCAL_MM)." fi +log "Sync-Token prüfen..." +SAVED_TOKEN=$(read_sync_token) +SERVER_TOKEN=$(server_db_mtime) +log " Gespeicherter Token: ${SAVED_TOKEN:-keiner (erster Sync)}" +log " Aktueller Server-Token: $SERVER_TOKEN" + +UPLOAD_ALLOWED=true +if [ -n "$SAVED_TOKEN" ] && [ "$SAVED_TOKEN" != "$SERVER_TOKEN" ]; then + log "WARNUNG: Token-Konflikt (gespeichert=$SAVED_TOKEN, server=$SERVER_TOKEN) – Benutzer wird gefragt." + RESOLUTION=$(ask_conflict_resolution) + log "Benutzerentscheidung: $RESOLUTION" + case "$RESOLUTION" in + upload) + log "Upload erzwungen – lokale Version überschreibt Server." + ;; + abort) + log "Sync abgebrochen durch Benutzer." + exit 0 + ;; + *) + log "Nur Download – Server-Stand wird übernommen." + UPLOAD_ALLOWED=false + ;; + esac +else + log "Token stimmt überein – Upload erlaubt." +fi + log_step "Datenbank-Backup" log " $LOCAL_DARKTABLE_DB_DIR/library.db → library.db.bak" cp "$LOCAL_DARKTABLE_DB_DIR/library.db" "$LOCAL_DARKTABLE_DB_DIR/library.db.bak" @@ -127,40 +155,47 @@ log "Backup abgeschlossen." SYNC_LOG=$(mktemp) TMPFILES+=("$SYNC_LOG") -log_step "Upload: Datenbank" -log " Quelle: $LOCAL_DARKTABLE_DB_DIR/" -log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" -UPLOAD_LOG_DB=$(mktemp) -TMPFILES+=("$UPLOAD_LOG_DB") -if ! rsync -uavh --itemize-changes \ - --exclude '*.lock' \ - --exclude 'darktable_version' \ - -e "ssh -p $SERVER_SSH_PORT" \ - "$LOCAL_DARKTABLE_DB_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" \ - 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_DB"; then - log_error "Upload Datenbank fehlgeschlagen (Quelle: $LOCAL_DARKTABLE_DB_DIR)" - touch "$CONFIG_DIR/sync_pending" - exit 1 -fi -SENT_DB=$(count_synced_files "$UPLOAD_LOG_DB" "up") -log "Datenbank-Upload abgeschlossen: $SENT_DB Datei(en) übertragen." +SENT_DB=0 +SENT_PHOTOS=0 -log_step "Upload: Fotos" -log " Quelle: $LOCAL_PHOTO_DIR/" -log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" -UPLOAD_LOG_PHOTOS=$(mktemp) -TMPFILES+=("$UPLOAD_LOG_PHOTOS") -if ! rsync -uavh --itemize-changes \ - --exclude '*.lock' \ - -e "ssh -p $SERVER_SSH_PORT" \ - "$LOCAL_PHOTO_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" \ - 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_PHOTOS"; then - log_error "Upload Fotos fehlgeschlagen (Quelle: $LOCAL_PHOTO_DIR)" - touch "$CONFIG_DIR/sync_pending" - exit 1 +if [ "$UPLOAD_ALLOWED" = true ]; then + log_step "Upload: Datenbank" + log " Quelle: $LOCAL_DARKTABLE_DB_DIR/" + log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" + UPLOAD_LOG_DB=$(mktemp) + TMPFILES+=("$UPLOAD_LOG_DB") + if ! rsync -uavh --itemize-changes \ + --exclude '*.lock' \ + --exclude 'darktable_version' \ + -e "ssh -p $SERVER_SSH_PORT" \ + "$LOCAL_DARKTABLE_DB_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" \ + 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_DB"; then + log_error "Upload Datenbank fehlgeschlagen (Quelle: $LOCAL_DARKTABLE_DB_DIR)" + touch "$CONFIG_DIR/sync_pending" + exit 1 + fi + SENT_DB=$(count_synced_files "$UPLOAD_LOG_DB" "up") + log "Datenbank-Upload abgeschlossen: $SENT_DB Datei(en) übertragen." + + log_step "Upload: Fotos" + log " Quelle: $LOCAL_PHOTO_DIR/" + log " Ziel: $SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" + UPLOAD_LOG_PHOTOS=$(mktemp) + TMPFILES+=("$UPLOAD_LOG_PHOTOS") + if ! rsync -uavh --itemize-changes \ + --exclude '*.lock' \ + -e "ssh -p $SERVER_SSH_PORT" \ + "$LOCAL_PHOTO_DIR/" "$SERVER_USER@$SERVER_IP:$SERVER_PHOTO_DIR/" \ + 2>&1 | tee -a "$SYNC_LOG" "$UPLOAD_LOG_PHOTOS"; then + log_error "Upload Fotos fehlgeschlagen (Quelle: $LOCAL_PHOTO_DIR)" + touch "$CONFIG_DIR/sync_pending" + exit 1 + fi + SENT_PHOTOS=$(count_synced_files "$UPLOAD_LOG_PHOTOS" "up") + log "Foto-Upload abgeschlossen: $SENT_PHOTOS Datei(en) übertragen." +else + log "Upload übersprungen (Token-Konflikt)." fi -SENT_PHOTOS=$(count_synced_files "$UPLOAD_LOG_PHOTOS" "up") -log "Foto-Upload abgeschlossen: $SENT_PHOTOS Datei(en) übertragen." log_step "Download: Datenbank" log " Quelle: $SERVER_USER@$SERVER_IP:$SERVER_DB_DIR/" @@ -196,6 +231,10 @@ fi RECEIVED_PHOTOS=$(count_synced_files "$DOWNLOAD_LOG_PHOTOS" "down") log "Foto-Download abgeschlossen: $RECEIVED_PHOTOS Datei(en) empfangen." +NEW_TOKEN=$(server_db_mtime) +save_sync_token "$NEW_TOKEN" +log "Sync-Token gespeichert: $NEW_TOKEN" + log "Versionsdatei aktualisieren: $LOCAL_DARKTABLE_DB_DIR/darktable_version" echo "$LOCAL_VERSION" > "$LOCAL_DARKTABLE_DB_DIR/darktable_version" -- 2.52.0