webui: replace nautctl web server with a loadable plugin
Drop the web UI that was compiled into nautctl and serve the torrent-ui front end (../torrent-ui/public) from a native plugin (plugins/webui) loaded via `nautd --plugin`. The plugin talks to the engine only through the host call_rpc ABI and adapts the daemon's RPC surface to the qBittorrent-style contract the UI expects (snapshot/SSE, torrent detail tabs, add/delete, cookie auth). Also folds in the daemon refactor that owns per-torrent worker threads and the swarm engine (naut_swarm) used by the plugin's data source. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
50a357968a
commit
8dde48c05a
27 changed files with 2706 additions and 403 deletions
|
|
@ -9,6 +9,11 @@ tmp=$(mktemp -d)
|
|||
socket="$tmp/nautd.sock"
|
||||
daemon_log="$tmp/nautd.log"
|
||||
events_log="$tmp/events.log"
|
||||
seeder_log="$tmp/seeder.log"
|
||||
root_dir=$(cd "$(dirname "$script")/../.." && pwd)
|
||||
seeder="$root_dir/tests/integration/seeder.py"
|
||||
torrent="$(dirname "$script")/single_v1.torrent"
|
||||
seed_data="$(dirname "$script")/data"
|
||||
|
||||
cleanup() {
|
||||
result=$?
|
||||
|
|
@ -20,16 +25,36 @@ cleanup() {
|
|||
kill "$events_pid" 2>/dev/null || true
|
||||
wait "$events_pid" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -n "${seeder_pid:-}" ]]; then
|
||||
kill "$seeder_pid" 2>/dev/null || true
|
||||
wait "$seeder_pid" 2>/dev/null || true
|
||||
fi
|
||||
if [[ "$result" -ne 0 ]]; then
|
||||
cat "$daemon_log" >&2 2>/dev/null || true
|
||||
cat "$events_log" >&2 2>/dev/null || true
|
||||
cat "$seeder_log" >&2 2>/dev/null || true
|
||||
fi
|
||||
rm -rf "$tmp"
|
||||
return "$result"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
"$daemon" --socket "$socket" --plugin "$plugin" --script "$script" \
|
||||
python3 -c 'import libtorrent' 2>/dev/null || {
|
||||
echo "SKIP: python libtorrent not available"
|
||||
exit 77
|
||||
}
|
||||
|
||||
python3 "$seeder" "$torrent" "$seed_data" >"$seeder_log" 2>&1 &
|
||||
seeder_pid=$!
|
||||
port=
|
||||
for _ in $(seq 1 100); do
|
||||
port=$(grep -oP 'PORT \K[0-9]+' "$seeder_log" 2>/dev/null || true)
|
||||
[[ -n "$port" && "$port" != 0 ]] && break
|
||||
sleep 0.05
|
||||
done
|
||||
[[ -n "$port" && "$port" != 0 ]]
|
||||
|
||||
"$daemon" --socket "$socket" --plugin "$plugin" \
|
||||
>"$daemon_log" 2>&1 &
|
||||
daemon_pid=$!
|
||||
|
||||
|
|
@ -41,24 +66,28 @@ done
|
|||
|
||||
"$ctl" --socket "$socket" ping | grep -q '"service": "nautd"'
|
||||
"$ctl" --socket "$socket" plugins | grep -q '"memory"'
|
||||
"$ctl" --socket "$socket" script "$script" | grep -q '"ok": true'
|
||||
|
||||
timeout 5 "$ctl" --socket "$socket" events >"$events_log" &
|
||||
events_pid=$!
|
||||
sleep 0.1
|
||||
"$ctl" --socket "$socket" emit \
|
||||
'{"type":"torrent_finished","torrent_id":7}' >/dev/null
|
||||
root="$tmp/torrent-data"
|
||||
"$ctl" --socket "$socket" add "$torrent" "$root" "127.0.0.1:$port" \
|
||||
| grep -q '"ok": true'
|
||||
|
||||
status=
|
||||
for _ in $(seq 1 100); do
|
||||
status=$("$ctl" --socket "$socket" status)
|
||||
if grep -q '"move_commands": 1' <<<"$status" &&
|
||||
grep -q '"handled": 1' <<<"$status"; then
|
||||
break
|
||||
fi
|
||||
sleep 0.02
|
||||
listing=
|
||||
for _ in $(seq 1 200); do
|
||||
listing=$("$ctl" --socket "$socket" list)
|
||||
grep -q '"state": "complete"' <<<"$listing" &&
|
||||
[[ -f "$root/single.bin.moved" ]] && break
|
||||
sleep 0.05
|
||||
done
|
||||
grep -q '"state": "complete"' <<<"$listing"
|
||||
cmp "$root/single.bin.moved" "$seed_data/single.bin"
|
||||
|
||||
status=$("$ctl" --socket "$socket" status)
|
||||
grep -q '"move_commands": 1' <<<"$status"
|
||||
grep -q '"handled": 1' <<<"$status"
|
||||
grep -q '"handled": 2' <<<"$status"
|
||||
grep -q '"errors": 0' <<<"$status"
|
||||
|
||||
plugin_status=$("$ctl" --socket "$socket" example.events)
|
||||
|
|
@ -70,28 +99,13 @@ for _ in $(seq 1 100); do
|
|||
done
|
||||
grep -q '"event": "torrent_finished"' "$events_log"
|
||||
|
||||
# --- end-to-end move-as-you-finish: register a real torrent's storage, fire a
|
||||
# file_complete event, and confirm the script-driven move actually relocates the
|
||||
# file on disk (script thread -> bounded queue -> owner thread -> storage). ----
|
||||
fixtures=$(dirname "$script")
|
||||
root="$tmp/torrent-data"
|
||||
"$ctl" --socket "$socket" add_torrent \
|
||||
"{\"torrent_id\":42,\"torrent\":\"$fixtures/single_v1.torrent\",\"root\":\"$root\"}" \
|
||||
| grep -q '"ok": true'
|
||||
|
||||
src=$(find "$root" -type f | head -n1)
|
||||
[[ -n "$src" ]]
|
||||
|
||||
"$ctl" --socket "$socket" emit \
|
||||
"{\"type\":\"file_complete\",\"torrent_id\":42,\"index\":0,\"path\":\"$src\"}" \
|
||||
>/dev/null
|
||||
|
||||
"$ctl" --socket "$socket" remove 1 >/dev/null
|
||||
for _ in $(seq 1 100); do
|
||||
[[ -f "$src.moved" ]] && break
|
||||
listing=$("$ctl" --socket "$socket" list)
|
||||
grep -q '"result": \[\]' <<<"$listing" && break
|
||||
sleep 0.02
|
||||
done
|
||||
[[ -f "$src.moved" ]]
|
||||
[[ ! -f "$src" ]]
|
||||
grep -q '"result": \[\]' <<<"$listing"
|
||||
|
||||
"$ctl" --socket "$socket" shutdown >/dev/null
|
||||
wait "$daemon_pid"
|
||||
|
|
|
|||
|
|
@ -70,7 +70,8 @@ if [ "$MODE" = "udp" ]; then
|
|||
else
|
||||
announce="http://127.0.0.1:$tracker_port/announce"
|
||||
fi
|
||||
python3 - "$SOURCE_TOR" "$tor" "$announce" <<'PY'
|
||||
backup="http://127.0.0.1:1/lower-tier-should-not-be-contacted"
|
||||
python3 - "$SOURCE_TOR" "$tor" "$announce" "$backup" <<'PY'
|
||||
import sys
|
||||
|
||||
|
||||
|
|
@ -90,7 +91,8 @@ def skip(data, pos):
|
|||
return colon + 1 + size
|
||||
|
||||
|
||||
source, target, announce = sys.argv[1], sys.argv[2], sys.argv[3].encode()
|
||||
source, target = sys.argv[1], sys.argv[2]
|
||||
announce, backup = sys.argv[3].encode(), sys.argv[4].encode()
|
||||
data = open(source, "rb").read()
|
||||
pos = 1
|
||||
raw_info = None
|
||||
|
|
@ -107,6 +109,8 @@ while data[pos] != ord("e"):
|
|||
assert raw_info is not None
|
||||
rewritten = (
|
||||
b"d8:announce" + str(len(announce)).encode() + b":" + announce
|
||||
+ b"13:announce-listll" + str(len(announce)).encode() + b":" + announce
|
||||
+ b"el" + str(len(backup)).encode() + b":" + backup + b"ee"
|
||||
+ b"4:info" + raw_info + b"e"
|
||||
)
|
||||
open(target, "wb").write(rewritten)
|
||||
|
|
@ -125,5 +129,10 @@ if ! grep -q "REQUEST" "$tracker_log"; then
|
|||
echo "FAIL: tracker received no announce"
|
||||
exit 1
|
||||
fi
|
||||
if grep -q "$backup" "$swarm_log"; then
|
||||
echo "FAIL: lower tracker tier was contacted after primary success"
|
||||
cat "$swarm_log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "PASS: $MODE tracker discovery produced byte-identical output"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue