diff --git a/pub_event[rungame,endgame](sync).ash b/pub_event[rungame,endgame](sync).ash index 66ab900..90454d4 100644 --- a/pub_event[rungame,endgame](sync).ash +++ b/pub_event[rungame,endgame](sync).ash @@ -1,4 +1,4 @@ #!/bin/ash -# +#shellcheck shell=dash PAYLOAD=$(cat /tmp/es_state.inf) echo "EVENT:$PAYLOAD" >/tmp/savesync_pipe diff --git a/savesync.conf b/savesync.conf new file mode 100644 index 0000000..9191f58 --- /dev/null +++ b/savesync.conf @@ -0,0 +1,3 @@ +#!/bin/ash +#shellcheck shell=dash +export REMOTE_BASE="saves:gamepi-tv" diff --git a/savesync[start](permanent).ash b/savesync[start](permanent).ash index 9a01f9a..d3564a9 100644 --- a/savesync[start](permanent).ash +++ b/savesync[start](permanent).ash @@ -1,98 +1,77 @@ #!/bin/ash +# shellcheck shell=dash . /recalbox/share/system/configs/savesync/savesync.conf PIPE="/tmp/savesync_pipe" LOG_FILE="/recalbox/share/system/logs/savesync.log" -mkfifo "$PIPE" +# Setup the pipe if it doesn't exist +[ -p "$PIPE" ] || mkfifo "$PIPE" chmod 666 "$PIPE" -# Function to write to disk write_log() { - printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >>"$LOG_FILE" + printf "[%s] %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "$1" >> "$LOG_FILE" } -# The listener loop +write_log "--- Daemon Started ---" + while true; do - if read -r line <"$PIPE"; then - case "$line" in - LOG:*) - # Remove the "LOG:" prefix and write - write_log "${line#LOG:}" - ;; - EVENT:*) - # Handle Game Events (forked to background) - ( - - PIPE="/tmp/savesync_pipe" - event_data="${line#EVENT:}" + # Read one line from the pipe + if read -r line < "$PIPE"; then + case "$line" in + LOG:*) + write_log "${line#LOG:}" + ;; + EVENT:*) + # Fork the event handling + ( + event_data="${line#EVENT:}" + + # Process the multi-line event data + # We use echo and a pipe to feed the while loop + echo "$event_data" | tr -d '\r' | while IFS="=" read -r key val; do + case "$key" in + "SystemId") sid="$val" ;; + "GamePath") + gp="$val" + sp=$(echo "$val" | sed 's|roms|saves|; s|\.[^.]*$|.srm|') + bp=$(echo "$sp" | sed 's|saves|archives|') + ;; + "Action") act="$val" ;; + "State") + st="$val" - # Clean input - $(echo "$event_data" | tr -d '\r') - - while IFS= read -r key val; do - case "$key" in - "SystemId") sid="$val" ;; - "GamePath") - gp="$val" - # Fast path transformation using sed - sp=$(echo "$val" | sed 's|roms|saves|; s|\.[^.]*$|.srm|') - bp=$(echo "$sp" | sed 's|saves|archives|') - ;; - "Action") act="$val" ;; - "State") - st="$val" + if [ "$st" = "playing" ] && [ "$act" = "rungame" ]; then + write_log "Sync START: $(basename "$gp")" + + remote_f="$REMOTE_BASE/$sid/$(basename "$sp")" + loc_sz=$(stat -c %s "$sp" 2>/dev/null || echo 0) + rem_sz=$(rclone lsjson "$remote_f" 2>/dev/null | grep -o '"Size":[0-9]*' | cut -d: -f2) + : "${rem_sz:=0}" - # Check if we have the full "Start Game" context - if [ "$st" = "playing" ] && [ "$act" = "rungame" ]; then - # FORK to background, but keep current variables! - ( - printf "%s %s\n" "LOG:" "Syncing START for $(basename "$gp")" >${PIPE} + if [ "$loc_sz" -lt "$rem_sz" ]; then + write_log "Cloud save larger ($rem_sz). Restoring..." + mkdir -p "$(dirname "$bp")" + rclone copyto "$remote_f" "$sp" --backup-dir "$(dirname "$bp")" + else + write_log "Local save current. Updating..." + rclone update "$remote_f" "$sp" + fi + + # Signal back to the publisher via MQTT or a second Response Pipe + #mosquitto_pub -t "$RESPONSE_TOPIC" -m "SaveSync=0" 2>/dev/null - remote_f="$REMOTE_BASE/$sid/$(basename "$sp")" - loc_sz=$(stat -c %s "$sp" 2>/dev/null || echo 0) - - # Fetch remote size - rem_sz=$(rclone lsjson "$remote_f" 2>/dev/null | grep -o '"Size":[0-9]*' | cut -d: -f2) - : "${rem_sz:=0}" - - if [ "$loc_sz" -lt "$rem_sz" ]; then - printf "%s %s\n" "LOG:" "Cloud save larger. Restoring..." >${PIPE} - mkdir -p "$(dirname "$bp")" - rclone copyto "$remote_f" "$sp" --backup-dir "$(dirname "$bp")" - else - printf "%s %s\n" "LOG:" "Local save current. Updating..."> >${PIPE} - rclone update "$remote_f" "$sp" - fi - - # SIGNAL SUCCESS (Key must match Publisher's expectation) - printf "%s %s\n" "LOG:" "Save synced successfully" >${PIPE} - ) & - - elif [ "$st" = "endgame" ]; then - # Syncing on end - we don't necessarily need to block here - ( - printf "%s %s\n" "LOG:" "Syncing END for $(basename "$sp")" >${PIPE} - rclone update "$sp" "$REMOTE_BASE/$sid/" - printf "%s %s\n" "LOG:" "Final Sync Done." >${PIPE} - - ) & - fi - - # Clear variables for next burst of events - sid="" - gp="" - sp="" - bp="" - act="" - st="" - ;; - esac - done<$(printf "%s\n" "$event_data" | tr -d '\r') - - printf '%s\n' "LOG:Sync complete for $sp" >"$PIPE" - ) & - ;; - esac - fi + elif [ "$st" = "endgame" ]; then + write_log "Sync END: $(basename "$sp")" + rclone update "$sp" "$REMOTE_BASE/$sid/" + write_log "Final Sync Done." + #mosquitto_pub -t "$RESPONSE_TOPIC" -m "SaveSync=0" 2>/dev/null + fi + ;; + esac + done + ) & + ;; + esac + fi done