Add Disk Info and Speed Test buttons to Remotes screen
- Disk Info: runs df -h and df -i on remote via SSH (or locally) - Speed Test: uploads/downloads 10MB test file via rsync, measures Mbps - Both available as CLI commands: gniza remotes disk-info/speed-test --name=NAME Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
12
bin/gniza
12
bin/gniza
@@ -274,8 +274,18 @@ run_cli() {
|
||||
validate_remote "$name"
|
||||
echo "Remote '$name' is valid."
|
||||
;;
|
||||
disk-info)
|
||||
[[ -z "$name" ]] && die "remotes disk-info requires --name=NAME"
|
||||
load_remote "$name"
|
||||
remote_disk_info
|
||||
;;
|
||||
speed-test)
|
||||
[[ -z "$name" ]] && die "remotes speed-test requires --name=NAME"
|
||||
load_remote "$name"
|
||||
remote_speed_test
|
||||
;;
|
||||
*)
|
||||
die "Unknown remotes action: $action (expected list|add|delete|show|test)"
|
||||
die "Unknown remotes action: $action (expected list|add|delete|show|test|disk-info|speed-test)"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
@@ -287,3 +287,101 @@ get_target_remotes() {
|
||||
log_error "No remotes configured. Create one in $CONFIG_DIR/remotes.d/"
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Disk info ────────────────────────────────────────────────
|
||||
|
||||
remote_disk_info() {
|
||||
local base="${REMOTE_BASE:-/}"
|
||||
case "${REMOTE_TYPE:-ssh}" in
|
||||
ssh)
|
||||
echo "Disk usage on ${REMOTE_USER}@${REMOTE_HOST}:${base}"
|
||||
echo "──────────────────────────────────────────"
|
||||
remote_exec "df -h '$base' 2>/dev/null && echo '' && df -i '$base' 2>/dev/null"
|
||||
;;
|
||||
local)
|
||||
echo "Disk usage on ${base}"
|
||||
echo "──────────────────────────────────────────"
|
||||
df -h "$base" 2>/dev/null
|
||||
echo ""
|
||||
df -i "$base" 2>/dev/null
|
||||
;;
|
||||
*)
|
||||
echo "Disk info not supported for remote type: ${REMOTE_TYPE}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ── Speed test ───────────────────────────────────────────────
|
||||
|
||||
remote_speed_test() {
|
||||
local test_size="10M"
|
||||
local test_file="/tmp/.gniza_speedtest_$$"
|
||||
local remote_file="${REMOTE_BASE:-.}/.gniza_speedtest_$$"
|
||||
|
||||
case "${REMOTE_TYPE:-ssh}" in
|
||||
ssh)
|
||||
echo "Speed test to ${REMOTE_USER}@${REMOTE_HOST}"
|
||||
echo "Test file size: ${test_size}"
|
||||
echo "──────────────────────────────────────────"
|
||||
|
||||
# Create local test file
|
||||
dd if=/dev/urandom of="$test_file" bs=1M count=10 2>/dev/null
|
||||
|
||||
# Upload test
|
||||
echo ""
|
||||
echo "Upload test..."
|
||||
local ssh_cmd
|
||||
ssh_cmd=$(build_rsync_ssh_cmd)
|
||||
local start_up end_up duration_up speed_up
|
||||
start_up=$(date +%s%N)
|
||||
# shellcheck disable=SC2086
|
||||
if rsync -e "$ssh_cmd" --progress "$test_file" "${REMOTE_USER}@${REMOTE_HOST}:${remote_file}" 2>/dev/null; then
|
||||
end_up=$(date +%s%N)
|
||||
duration_up=$(( (end_up - start_up) / 1000000 ))
|
||||
if [[ "$duration_up" -gt 0 ]]; then
|
||||
speed_up=$(( 10 * 1000 * 8 / duration_up ))
|
||||
echo " Upload: ${speed_up} Mbps (${duration_up} ms)"
|
||||
else
|
||||
echo " Upload: too fast to measure"
|
||||
fi
|
||||
else
|
||||
echo " Upload: FAILED"
|
||||
fi
|
||||
|
||||
# Download test
|
||||
echo ""
|
||||
echo "Download test..."
|
||||
local dl_file="${test_file}_dl"
|
||||
local start_dn end_dn duration_dn speed_dn
|
||||
start_dn=$(date +%s%N)
|
||||
# shellcheck disable=SC2086
|
||||
if rsync -e "$ssh_cmd" --progress "${REMOTE_USER}@${REMOTE_HOST}:${remote_file}" "$dl_file" 2>/dev/null; then
|
||||
end_dn=$(date +%s%N)
|
||||
duration_dn=$(( (end_dn - start_dn) / 1000000 ))
|
||||
if [[ "$duration_dn" -gt 0 ]]; then
|
||||
speed_dn=$(( 10 * 1000 * 8 / duration_dn ))
|
||||
echo " Download: ${speed_dn} Mbps (${duration_dn} ms)"
|
||||
else
|
||||
echo " Download: too fast to measure"
|
||||
fi
|
||||
else
|
||||
echo " Download: FAILED"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -f "$test_file" "$dl_file" 2>/dev/null
|
||||
remote_exec "rm -f '$remote_file'" 2>/dev/null || true
|
||||
|
||||
echo ""
|
||||
echo "Done."
|
||||
;;
|
||||
local)
|
||||
echo "Speed test not applicable for local remotes."
|
||||
;;
|
||||
*)
|
||||
echo "Speed test not supported for remote type: ${REMOTE_TYPE}"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ class RemotesScreen(Screen):
|
||||
yield Button("Add", variant="primary", id="btn-add")
|
||||
yield Button("Edit", id="btn-edit")
|
||||
yield Button("Test", variant="warning", id="btn-test")
|
||||
yield Button("Disk Info", id="btn-disk")
|
||||
yield Button("Speed Test", id="btn-speed")
|
||||
yield Button("Delete", variant="error", id="btn-delete")
|
||||
yield Button("Back", id="btn-back")
|
||||
yield Footer()
|
||||
@@ -71,6 +73,18 @@ class RemotesScreen(Screen):
|
||||
self._test_remote(name)
|
||||
else:
|
||||
self.notify("Select a remote first", severity="warning")
|
||||
elif event.button.id == "btn-disk":
|
||||
name = self._selected_remote()
|
||||
if name:
|
||||
self._disk_info(name)
|
||||
else:
|
||||
self.notify("Select a remote first", severity="warning")
|
||||
elif event.button.id == "btn-speed":
|
||||
name = self._selected_remote()
|
||||
if name:
|
||||
self._speed_test(name)
|
||||
else:
|
||||
self.notify("Select a remote first", severity="warning")
|
||||
elif event.button.id == "btn-delete":
|
||||
name = self._selected_remote()
|
||||
if name:
|
||||
@@ -96,6 +110,32 @@ class RemotesScreen(Screen):
|
||||
log_screen.write(f"\n[red]Connection test failed (exit code {rc}).[/red]")
|
||||
log_screen.finish()
|
||||
|
||||
@work
|
||||
async def _disk_info(self, name: str) -> None:
|
||||
log_screen = OperationLog(f"Disk Info: {name}", show_spinner=False)
|
||||
self.app.push_screen(log_screen)
|
||||
rc, stdout, stderr = await run_cli("remotes", "disk-info", f"--name={name}")
|
||||
if stdout:
|
||||
log_screen.write(stdout)
|
||||
if stderr:
|
||||
log_screen.write(stderr)
|
||||
if rc != 0:
|
||||
log_screen.write(f"\n[red]Failed to get disk info (exit code {rc}).[/red]")
|
||||
log_screen.finish()
|
||||
|
||||
@work
|
||||
async def _speed_test(self, name: str) -> None:
|
||||
log_screen = OperationLog(f"Speed Test: {name}")
|
||||
self.app.push_screen(log_screen)
|
||||
rc, stdout, stderr = await run_cli("remotes", "speed-test", f"--name={name}")
|
||||
if stdout:
|
||||
log_screen.write(stdout)
|
||||
if stderr:
|
||||
log_screen.write(stderr)
|
||||
if rc != 0:
|
||||
log_screen.write(f"\n[red]Speed test failed (exit code {rc}).[/red]")
|
||||
log_screen.finish()
|
||||
|
||||
def _delete_remote(self, name: str) -> None:
|
||||
conf = CONFIG_DIR / "remotes.d" / f"{name}.conf"
|
||||
if conf.is_file():
|
||||
|
||||
Reference in New Issue
Block a user