feat: Use atomic writes for progress updates (#1319)

This commit is contained in:
Kroese
2026-07-23 04:10:09 +02:00
committed by GitHub
parent 222b5649b0
commit 41c76198fa
3 changed files with 103 additions and 12 deletions
+64 -5
View File
@@ -2,6 +2,7 @@
set -Eeuo pipefail
info="/run/shm/msg.html"
info_tmp="${info}.${BASHPID}.tmp"
escape() {
@@ -17,6 +18,23 @@ escape() {
return 0
}
writeInfo() {
local content="$1"
if ! printf '%s\n' "$content" > "$info_tmp"; then
rm -f -- "$info_tmp"
return 1
fi
if ! mv -f -- "$info_tmp" "$info"; then
rm -f -- "$info_tmp"
return 1
fi
return 0
}
getBytes() {
local path="$1"
@@ -48,6 +66,24 @@ getBytes() {
return 0
}
getStatus() {
local file="$1"
local bytes total extra=""
[ -r "$file" ] || return 1
read -r bytes total extra < "$file" || return 1
if [[ ! "$bytes" =~ ^[0-9]+$ ||
! "$total" =~ ^[0-9]+$ ||
-n "$extra" ]]; then
return 1
fi
printf '%s %s\n' "$bytes" "$total"
return 0
}
formatSize() {
local bytes="$1"
@@ -117,7 +153,9 @@ printSizeProgress() {
return 0
}
finishLogProgress() {
finishProgress() {
rm -f -- "$info_tmp"
if [[ "$output" == "log" && "$printed" == "Y" ]]; then
printf '\n'
@@ -132,6 +170,7 @@ body=$(escape "$3")
output="${4:-}"
step_bytes="${5:-536870912}"
mode="${6:-apparent}"
status_file="${7:-}"
if [[ -n "$total" && ! "$total" =~ ^(0|[1-9][0-9]*)$ ]]; then
printf 'Invalid total size: %s\n' "$total" >&2
@@ -168,7 +207,7 @@ if [ -z "$total" ] || [[ "$total" == "0" ]]; then
log_mode="size"
fi
trap finishLogProgress EXIT
trap finishProgress EXIT
trap 'exit 0' HUP INT QUIT TERM
if [[ "$body" == *"..." ]]; then
@@ -178,12 +217,32 @@ fi
while true; do
bytes=$(getBytes "$path" "$mode")
effective_total="$total"
if [ -n "$status_file" ] && status=$(getStatus "$status_file"); then
read -r status_bytes status_total <<< "$status"
bytes="$status_bytes"
if (( status_total > 0 )); then
effective_total="$status_total"
fi
fi
# A real total may become available shortly after aria2 starts.
if [[ "$log_mode" == "size" &&
"$printed" == "N" &&
-n "$effective_total" &&
"$effective_total" != "0" ]]; then
log_mode="percent"
fi
if (( bytes > 4096 )); then
write_html="Y"
if [ -z "$total" ] || [[ "$total" == "0" ]] || (( bytes > total )); then
if [ -z "$effective_total" ] ||
[[ "$effective_total" == "0" ]] ||
(( bytes > effective_total )); then
size=$(formatSize "$bytes")
if [[ "$output" == "log" ]]; then
@@ -197,7 +256,7 @@ while true; do
fi
else
# Truncate to one decimal so progress is never reported early.
progress=$((bytes * 1000 / total))
progress=$((bytes * 1000 / effective_total))
(( progress > 1000 )) && progress=1000
percent=$((progress / 10))
@@ -219,7 +278,7 @@ while true; do
fi
if [[ "$write_html" == "Y" ]]; then
printf '%s\n' "${body//(\[P\])/($size)}" > "$info"
writeInfo "${body//(\[P\])/($size)}"
fi
fi
+18 -5
View File
@@ -3,6 +3,8 @@ set -Eeuo pipefail
lastmsg=""
path="/run/shm/msg.html"
dir=$(dirname -- "$path")
name=$(basename -- "$path")
refresh() {
@@ -17,15 +19,26 @@ refresh() {
lastmsg="$msg"
echo "s: $msg"
return 0
}
refresh
inotifywait -m "$path" |
while read -r fp event fn; do
inotifywait \
-m -q \
-e close_write,moved_to,delete \
--format '%e %f' \
"$dir" |
while read -r event file; do
[[ "$file" == "$name" ]] || continue
case "${event,,}" in
"modify"* ) refresh ;;
"delete_self" ) echo "c: vnc" ;;
esac
"delete"* )
echo "c: vnc" ;;
"close_write"* | "moved_to"* )
refresh ;;
esac
done
+21 -2
View File
@@ -300,6 +300,25 @@ writeFile() {
return 0
}
writeAtomic() {
local path="$1"
local content="$2"
local tmp="${path}.${BASHPID}.tmp"
if ! printf '%s\n' "$content" > "$tmp"; then
rm -f -- "$tmp"
return 1
fi
if ! mv -f -- "$tmp" "$path"; then
rm -f -- "$tmp"
return 1
fi
return 0
}
readFile() {
local path="$1"
@@ -411,8 +430,8 @@ html() {
HTML="${HTML/\[4\]/$footer}"
HTML="${HTML/\[5\]/$FOOTER2}"
echo "$HTML" > "$PAGE" || return 1
echo "$body" > "$INFO" || return 1
writeAtomic "$PAGE" "$HTML" || return 1
writeAtomic "$INFO" "$body" || return 1
return 0
}