feat:更新自动化测试kcp脚本

This commit is contained in:
nnbcccscdscdsc
2026-03-26 23:48:29 +08:00
parent 665a908421
commit fd7c2364c9
2 changed files with 873 additions and 0 deletions

5
.gitignore vendored
View File

@@ -4,3 +4,8 @@ inbox/*
*.html
peer-b-latency.*
*.bin
.vscode/settings.json
*.log
root@117.78.11.244

868
scripts/run-kcp-batch-test.sh Executable file
View File

@@ -0,0 +1,868 @@
#!/usr/bin/env bash
set -euo pipefail
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_dir="$(cd "$script_dir/.." && pwd)"
script_name="$(basename "$0")"
server_ssh=""
peerb_ssh=""
server_addr=""
log_prefix=""
listen_addr="0.0.0.0:10909"
server_workdir="$repo_dir"
peerb_workdir="$repo_dir"
local_workdir="$repo_dir"
ready_timeout=60
send_interval=1
drain_wait=5
repeat_count=1
declare -a peerb_files=()
server_started=0
peer_b_started=0
peer_a_pid=""
usage() {
printf 'Usage:\n'
printf ' %s --server-ssh <ssh-target> --peerb-ssh <ssh-target> --server-addr <host:port> \\\n' "$script_name"
printf ' --log-prefix <prefix> --file <peer-b-path> [--file <peer-b-path> ...] [options]\n'
printf '\n'
printf 'Required arguments:\n'
printf ' --server-ssh <ssh-target> SSH target for the server machine\n'
printf ' --peerb-ssh <ssh-target> SSH target for the peer-b machine\n'
printf ' --server-addr <host:port> Server address used by peer-a and peer-b\n'
printf ' --log-prefix <prefix> Log directory prefix; logs go under <prefix>logs/\n'
printf ' --file <peer-b-path> Existing file path on peer-b; repeat for multiple files\n'
printf '\n'
printf 'Options:\n'
printf ' --listen-addr <addr> Server listen address (default: %s)\n' "$listen_addr"
printf ' --server-workdir <dir> Server-side workdir (default: %s)\n' "$server_workdir"
printf ' --peerb-workdir <dir> Peer-b-side workdir (default: %s)\n' "$peerb_workdir"
printf ' --local-workdir <dir> Local peer-a workdir (default: %s)\n' "$local_workdir"
printf ' --ready-timeout <seconds> Startup wait timeout (default: %s)\n' "$ready_timeout"
printf ' --repeat <count> Repeat the full --file list this many rounds (default: %s)\n' "$repeat_count"
printf ' --send-interval <seconds> Delay between file commands (default: %s)\n' "$send_interval"
printf ' --drain-wait <seconds> Wait after the last file before quit (default: %s)\n' "$drain_wait"
printf ' -h, --help Show this help\n'
printf '\n'
printf 'Example:\n'
printf ' %s \\\n' "$script_name"
printf ' --server-ssh root@server-host \\\n'
printf ' --peerb-ssh root@peer-b-host \\\n'
printf ' --server-addr 203.0.113.10:10909 \\\n'
printf ' --log-prefix case01- \\\n'
printf ' --repeat 30 \\\n'
printf ' --file /tmp/test125.bin \\\n'
printf ' --file /tmp/test5.bin\n'
}
log() {
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
}
die() {
printf >&2 '[%s] error: %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
exit 1
}
join_path() {
local base="${1%/}"
printf '%s/%s' "$base" "$2"
}
build_quoted_command() {
local out_var="$1"
shift
local command=""
local part=""
local quoted=""
for part in "$@"; do
printf -v quoted '%q' "$part"
if [[ -n "$command" ]]; then
command+=" "
fi
command+="$quoted"
done
printf -v "$out_var" '%s' "$command"
}
run_remote_script() {
local target="$1"
local script="$2"
shift 2
local parts=("env")
local assignment=""
for assignment in "$@"; do
parts+=("$assignment")
done
parts+=("bash" "-s" "--")
local remote_cmd=""
build_quoted_command remote_cmd "${parts[@]}"
ssh -T "$target" "$remote_cmd" <<<"$script"
}
validate_positive_integer() {
local name="$1"
local value="$2"
if [[ ! "$value" =~ ^[1-9][0-9]*$ ]]; then
die "$name must be a positive integer, got: $value"
fi
}
validate_sleep_value() {
local name="$1"
local value="$2"
if [[ ! "$value" =~ ^([0-9]+([.][0-9]+)?|[.][0-9]+)$ ]]; then
die "$name must be a non-negative number understood by sleep, got: $value"
fi
}
dump_local_log_head() {
local path="$1"
if [[ -f "$path" ]]; then
sed -n '1,120p' "$path" >&2 || true
fi
}
dump_remote_log_head() {
local target="$1"
local log_file="$2"
local label="$3"
local script=""
script="$(cat <<'EOF'
set -euo pipefail
if [[ -f "$LOG_FILE" ]]; then
sed -n '1,120p' "$LOG_FILE"
fi
EOF
)"
log "showing $label log head from $target"
run_remote_script "$target" "$script" "LOG_FILE=$log_file" || true
}
check_local_dependencies() {
command -v ssh >/dev/null 2>&1 || die "ssh is required"
command -v scp >/dev/null 2>&1 || die "scp is required"
command -v go >/dev/null 2>&1 || die "go is required for local peer-a"
}
copy_remote_file_to_local() {
local remote_source="$1"
local local_dest="$2"
local local_dir=""
local local_tmp=""
local_dir="$(dirname "$local_dest")"
mkdir -p "$local_dir"
local_tmp="$(mktemp "$local_dir/.copy.tmp.XXXXXX")"
if scp "$remote_source" "$local_tmp"; then
mv -f "$local_tmp" "$local_dest"
else
local status=$?
rm -f "$local_tmp"
return "$status"
fi
}
remove_local_log_dir() {
if [[ -e "$local_log_dir" ]]; then
log "removing local log dir: $local_log_dir"
rm -rf "$local_log_dir"
fi
}
remove_remote_log_dir() {
local target="$1"
local log_dir="$2"
local label="$3"
local pid_file="${4:-}"
local script=""
script="$(cat <<'EOF'
set -euo pipefail
if [[ -n "${PID_FILE:-}" && -f "$PID_FILE" ]]; then
existing_pid="$(<"$PID_FILE")"
if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
printf >&2 'refusing to remove log dir while process %s is still running\n' "$existing_pid"
exit 1
fi
fi
rm -rf "$LOG_DIR"
EOF
)"
log "removing $label log dir on $target: $log_dir"
run_remote_script "$target" "$script" \
"LOG_DIR=$log_dir" \
"PID_FILE=$pid_file"
}
clean_log_directories() {
remove_local_log_dir
remove_remote_log_dir "$server_ssh" "$server_log_dir" "server" "$server_pid_file"
remove_remote_log_dir "$peerb_ssh" "$peerb_log_dir" "peer-b"
}
fetch_remote_peer_b_logs() {
log "copying peer-b logs from $peerb_ssh:$peerb_log_dir to $local_log_dir"
copy_remote_file_to_local "$peerb_ssh:$peerb_stdout_log" "$local_peer_b_stdout_log"
copy_remote_file_to_local "$peerb_ssh:$peerb_latency_log" "$local_peer_b_latency_log"
copy_remote_file_to_local "$peerb_ssh:$peerb_ts_debug_log" "$local_peer_b_ts_debug_log"
copy_remote_file_to_local "$peerb_ssh:$peerb_session_stats_log" "$local_peer_b_session_stats_log"
}
run_local_latency_summary() {
[[ -f "$local_peer_a_latency_log" ]] || die "local peer-a latency log not found: $local_peer_a_latency_log"
[[ -f "$local_peer_b_latency_log" ]] || die "local peer-b latency log not found: $local_peer_b_latency_log"
log "generating local latency summary: $local_kcp_latency_summary_log"
(
cd "$repo_dir"
exec go run ./cmd/latencysummary \
-input "$local_peer_a_latency_log" \
-input "$local_peer_b_latency_log" \
-output "$local_kcp_latency_summary_log"
)
}
check_remote_peerb_files() {
local script=""
local file=""
script="$(cat <<'EOF'
set -euo pipefail
cd "$PEERB_WORKDIR"
if [[ ! -f "$FILE_PATH" ]]; then
printf >&2 'peer-b file not found: %s\n' "$FILE_PATH"
exit 1
fi
EOF
)"
for file in "${peerb_files[@]}"; do
log "checking peer-b file exists: $file"
run_remote_script "$peerb_ssh" "$script" \
"PEERB_WORKDIR=$peerb_workdir" \
"FILE_PATH=$file"
done
}
start_remote_server() {
local script=""
script="$(cat <<'EOF'
set -euo pipefail
cd "$SERVER_WORKDIR"
mkdir -p "$LOG_DIR"
if [[ -f "$PID_FILE" ]]; then
existing_pid="$(<"$PID_FILE")"
if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
printf >&2 'server already running with pid %s\n' "$existing_pid"
exit 1
fi
fi
: > "$STDOUT_LOG"
nohup ./kcpserver \
-listen "$LISTEN_ADDR" \
>>"$STDOUT_LOG" 2>&1 </dev/null &
echo "$!" > "$PID_FILE"
EOF
)"
log "starting remote kcpserver on $server_ssh"
run_remote_script "$server_ssh" "$script" \
"SERVER_WORKDIR=$server_workdir" \
"LOG_DIR=$server_log_dir" \
"PID_FILE=$server_pid_file" \
"STDOUT_LOG=$server_stdout_log" \
"LISTEN_ADDR=$listen_addr"
server_started=1
}
wait_for_remote_server_ready() {
local pattern="kcp server listening"
local script=""
local start_time="$SECONDS"
local status=0
script="$(cat <<'EOF'
set -euo pipefail
if [[ -f "$LOG_FILE" ]] && grep -Fq -- "$READY_PATTERN" "$LOG_FILE"; then
exit 0
fi
if [[ -f "$PID_FILE" ]]; then
pid="$(<"$PID_FILE")"
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
exit 10
fi
fi
exit 20
EOF
)"
while (( SECONDS - start_time < ready_timeout )); do
if run_remote_script "$server_ssh" "$script" \
"LOG_FILE=$server_stdout_log" \
"READY_PATTERN=$pattern" \
"PID_FILE=$server_pid_file"; then
log "remote server is ready"
return 0
fi
status=$?
case "$status" in
10)
sleep 1
;;
20)
log "remote server exited before readiness"
dump_remote_log_head "$server_ssh" "$server_stdout_log" "server"
return 1
;;
*)
log "remote server readiness check failed with status $status"
dump_remote_log_head "$server_ssh" "$server_stdout_log" "server"
return 1
;;
esac
done
log "timed out waiting for remote server readiness after ${ready_timeout}s"
dump_remote_log_head "$server_ssh" "$server_stdout_log" "server"
return 1
}
stop_remote_server() {
local script=""
script="$(cat <<'EOF'
set -euo pipefail
if [[ ! -f "$PID_FILE" ]]; then
exit 0
fi
pid="$(<"$PID_FILE")"
if [[ -z "$pid" ]]; then
rm -f "$PID_FILE"
exit 0
fi
if ! kill -0 "$pid" 2>/dev/null; then
rm -f "$PID_FILE"
exit 0
fi
kill "$pid" 2>/dev/null || true
for _ in 1 2 3 4 5; do
if ! kill -0 "$pid" 2>/dev/null; then
rm -f "$PID_FILE"
exit 0
fi
sleep 1
done
kill -9 "$pid" 2>/dev/null || true
rm -f "$PID_FILE"
EOF
)"
run_remote_script "$server_ssh" "$script" "PID_FILE=$server_pid_file"
}
start_local_peer_a() {
log "starting local peer-a"
mkdir -p "$local_log_dir" "$local_peer_a_inbox"
: > "$local_peer_a_stdout_log"
(
cd "$local_workdir"
exec go run ./cmd/kcppeer \
-id peer-a \
-server "$server_addr" \
-inbox-dir "$local_peer_a_inbox" \
-latency-log "$local_peer_a_latency_log" \
-kcp-ts-debug-log "$local_peer_a_ts_debug_log" \
-kcp-session-stats-log "$local_peer_a_session_stats_log" \
-interactive=false \
>>"$local_peer_a_stdout_log" 2>&1
) &
peer_a_pid="$!"
}
wait_for_local_peer_a_ready() {
local pattern="connected to $server_addr as peer-a (KCP)"
local start_time="$SECONDS"
while (( SECONDS - start_time < ready_timeout )); do
if [[ -f "$local_peer_a_stdout_log" ]] && grep -Fq -- "$pattern" "$local_peer_a_stdout_log"; then
log "local peer-a is ready"
return 0
fi
if [[ -n "$peer_a_pid" ]] && ! kill -0 "$peer_a_pid" 2>/dev/null; then
log "local peer-a exited before readiness"
dump_local_log_head "$local_peer_a_stdout_log"
return 1
fi
sleep 1
done
log "timed out waiting for local peer-a readiness after ${ready_timeout}s"
dump_local_log_head "$local_peer_a_stdout_log"
return 1
}
stop_local_peer_a() {
if [[ -z "$peer_a_pid" ]]; then
return 0
fi
if kill -0 "$peer_a_pid" 2>/dev/null; then
kill "$peer_a_pid" 2>/dev/null || true
wait "$peer_a_pid" 2>/dev/null || true
else
wait "$peer_a_pid" 2>/dev/null || true
fi
peer_a_pid=""
}
start_remote_peer_b() {
local script=""
script="$(cat <<'EOF'
set -euo pipefail
cd "$PEERB_WORKDIR"
mkdir -p "$LOG_DIR" "$INBOX_DIR"
if [[ -f "$PID_FILE" ]]; then
existing_pid="$(<"$PID_FILE")"
if [[ -n "$existing_pid" ]] && kill -0 "$existing_pid" 2>/dev/null; then
printf >&2 'peer-b already running with pid %s\n' "$existing_pid"
exit 1
fi
fi
: > "$STDOUT_LOG"
: > "$COMMAND_FILE"
peer_b_cmd="$(cat <<'INNER'
tail -n +1 -f "$COMMAND_FILE" | exec ./bin/kcppeer \
-id peer-b \
-server "$SERVER_ADDR" \
-inbox-dir "$INBOX_DIR" \
-latency-log "$LATENCY_LOG" \
-kcp-ts-debug-log "$TS_DEBUG_LOG" \
-kcp-session-stats-log "$SESSION_STATS_LOG"
INNER
)"
nohup bash -lc "$peer_b_cmd" >>"$STDOUT_LOG" 2>&1 </dev/null &
echo "$!" > "$PID_FILE"
EOF
)"
log "starting remote peer-b on $peerb_ssh"
run_remote_script "$peerb_ssh" "$script" \
"PEERB_WORKDIR=$peerb_workdir" \
"LOG_DIR=$peerb_log_dir" \
"INBOX_DIR=$peerb_inbox_dir" \
"STDOUT_LOG=$peerb_stdout_log" \
"COMMAND_FILE=$peerb_command_file" \
"PID_FILE=$peerb_pid_file" \
"SERVER_ADDR=$server_addr" \
"LATENCY_LOG=$peerb_latency_log" \
"TS_DEBUG_LOG=$peerb_ts_debug_log" \
"SESSION_STATS_LOG=$peerb_session_stats_log"
peer_b_started=1
}
wait_for_remote_peer_b_ready() {
local pattern="connected to $server_addr as peer-b (KCP)"
local script=""
local start_time="$SECONDS"
local status=0
script="$(cat <<'EOF'
set -euo pipefail
if [[ -f "$LOG_FILE" ]] && grep -Fq -- "$READY_PATTERN" "$LOG_FILE"; then
exit 0
fi
if [[ -f "$PID_FILE" ]]; then
pid="$(<"$PID_FILE")"
if [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null; then
exit 10
fi
fi
exit 20
EOF
)"
while (( SECONDS - start_time < ready_timeout )); do
if run_remote_script "$peerb_ssh" "$script" \
"LOG_FILE=$peerb_stdout_log" \
"READY_PATTERN=$pattern" \
"PID_FILE=$peerb_pid_file"; then
log "remote peer-b is ready"
return 0
fi
status=$?
case "$status" in
10)
sleep 1
;;
20)
log "remote peer-b exited before readiness"
dump_remote_log_head "$peerb_ssh" "$peerb_stdout_log" "peer-b"
return 1
;;
*)
log "remote peer-b readiness check failed with status $status"
dump_remote_log_head "$peerb_ssh" "$peerb_stdout_log" "peer-b"
return 1
;;
esac
done
log "timed out waiting for remote peer-b readiness after ${ready_timeout}s"
dump_remote_log_head "$peerb_ssh" "$peerb_stdout_log" "peer-b"
return 1
}
run_remote_peer_b_batch() {
local script=""
local batch_commands=""
local round=0
local i=0
local send_index=0
local total_sends=$(( ${#peerb_files[@]} * repeat_count ))
local file=""
local command_line=""
local quoted_command=""
local quoted_sleep=""
for (( round = 1; round <= repeat_count; round++ )); do
for (( i = 0; i < ${#peerb_files[@]}; i++ )); do
file="${peerb_files[$i]}"
send_index=$(( send_index + 1 ))
log "queueing peer-b -> peer-a file (round $round/$repeat_count, send $send_index/$total_sends): $file"
printf -v command_line 'file peer-a %s' "$file"
printf -v quoted_command '%q' "$command_line"
batch_commands+="printf '%s\n' ${quoted_command} >> \"\$COMMAND_FILE\""$'\n'
if (( send_index < total_sends )); then
printf -v quoted_sleep '%q' "$send_interval"
batch_commands+="sleep ${quoted_sleep}"$'\n'
fi
done
done
printf -v quoted_sleep '%q' "$drain_wait"
batch_commands+="sleep ${quoted_sleep}"$'\n'
batch_commands+="printf '%s\n' quit >> \"\$COMMAND_FILE\""$'\n'
script="$(cat <<EOF
set -euo pipefail
if [[ ! -f "\$PID_FILE" ]]; then
printf >&2 'peer-b pid file not found: %s\n' "\$PID_FILE"
exit 1
fi
pid="\$(<"\$PID_FILE")"
if [[ -z "\$pid" ]] || ! kill -0 "\$pid" 2>/dev/null; then
printf >&2 'peer-b is not running\n'
exit 1
fi
$batch_commands
for (( i = 0; i < READY_TIMEOUT; i++ )); do
if ! kill -0 "\$pid" 2>/dev/null; then
rm -f "\$PID_FILE" "\$COMMAND_FILE"
exit 0
fi
sleep 1
done
printf >&2 'peer-b did not exit after quit within %s seconds\n' "\$READY_TIMEOUT"
exit 1
EOF
)"
log "sending ${#peerb_files[@]} files across $repeat_count rounds ($total_sends sends total) from peer-b"
run_remote_script "$peerb_ssh" "$script" \
"PID_FILE=$peerb_pid_file" \
"COMMAND_FILE=$peerb_command_file" \
"READY_TIMEOUT=$ready_timeout"
peer_b_started=0
}
stop_remote_peer_b() {
local script=""
script="$(cat <<'EOF'
set -euo pipefail
if [[ ! -f "$PID_FILE" ]]; then
rm -f "$COMMAND_FILE"
exit 0
fi
pid="$(<"$PID_FILE")"
if [[ -z "$pid" ]]; then
rm -f "$PID_FILE" "$COMMAND_FILE"
exit 0
fi
if kill -0 "$pid" 2>/dev/null; then
printf 'quit\n' >> "$COMMAND_FILE" 2>/dev/null || true
for _ in 1 2 3 4 5; do
if ! kill -0 "$pid" 2>/dev/null; then
rm -f "$PID_FILE" "$COMMAND_FILE"
exit 0
fi
sleep 1
done
kill "$pid" 2>/dev/null || true
for _ in 1 2 3 4 5; do
if ! kill -0 "$pid" 2>/dev/null; then
rm -f "$PID_FILE" "$COMMAND_FILE"
exit 0
fi
sleep 1
done
kill -9 "$pid" 2>/dev/null || true
fi
rm -f "$PID_FILE" "$COMMAND_FILE"
EOF
)"
run_remote_script "$peerb_ssh" "$script" \
"PID_FILE=$peerb_pid_file" \
"COMMAND_FILE=$peerb_command_file"
}
cleanup() {
local exit_code="$?"
trap - EXIT INT TERM
if [[ -n "$peer_a_pid" ]]; then
log "stopping local peer-a"
stop_local_peer_a
fi
if (( peer_b_started == 1 )); then
log "stopping remote peer-b on $peerb_ssh"
stop_remote_peer_b || true
fi
if (( server_started == 1 )); then
log "stopping remote server on $server_ssh"
stop_remote_server || true
fi
exit "$exit_code"
}
handle_interrupt() {
log "received interrupt signal"
exit 130
}
handle_terminate() {
log "received terminate signal"
exit 143
}
while [[ $# -gt 0 ]]; do
case "$1" in
--server-ssh)
[[ $# -ge 2 ]] || die "--server-ssh requires a value"
server_ssh="$2"
shift 2
;;
--peerb-ssh)
[[ $# -ge 2 ]] || die "--peerb-ssh requires a value"
peerb_ssh="$2"
shift 2
;;
--server-addr)
[[ $# -ge 2 ]] || die "--server-addr requires a value"
server_addr="$2"
shift 2
;;
--log-prefix)
[[ $# -ge 2 ]] || die "--log-prefix requires a value"
log_prefix="$2"
shift 2
;;
--listen-addr)
[[ $# -ge 2 ]] || die "--listen-addr requires a value"
listen_addr="$2"
shift 2
;;
--server-workdir)
[[ $# -ge 2 ]] || die "--server-workdir requires a value"
server_workdir="$2"
shift 2
;;
--peerb-workdir)
[[ $# -ge 2 ]] || die "--peerb-workdir requires a value"
peerb_workdir="$2"
shift 2
;;
--local-workdir)
[[ $# -ge 2 ]] || die "--local-workdir requires a value"
local_workdir="$2"
shift 2
;;
--ready-timeout)
[[ $# -ge 2 ]] || die "--ready-timeout requires a value"
ready_timeout="$2"
shift 2
;;
--repeat)
[[ $# -ge 2 ]] || die "--repeat requires a value"
repeat_count="$2"
shift 2
;;
--send-interval)
[[ $# -ge 2 ]] || die "--send-interval requires a value"
send_interval="$2"
shift 2
;;
--drain-wait)
[[ $# -ge 2 ]] || die "--drain-wait requires a value"
drain_wait="$2"
shift 2
;;
--file)
[[ $# -ge 2 ]] || die "--file requires a value"
peerb_files+=("$2")
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
die "unknown argument: $1"
;;
esac
done
[[ -n "$server_ssh" ]] || die "--server-ssh is required"
[[ -n "$peerb_ssh" ]] || die "--peerb-ssh is required"
[[ -n "$server_addr" ]] || die "--server-addr is required"
[[ -n "$log_prefix" ]] || die "--log-prefix is required"
(( ${#peerb_files[@]} > 0 )) || die "at least one --file is required"
validate_positive_integer "--ready-timeout" "$ready_timeout"
validate_positive_integer "--repeat" "$repeat_count"
validate_sleep_value "--send-interval" "$send_interval"
validate_sleep_value "--drain-wait" "$drain_wait"
check_local_dependencies
log_dir_name="${log_prefix}logs"
inbox_dir_name="${log_prefix}inbox"
local_log_dir="$(join_path "$local_workdir" "$log_dir_name")"
local_peer_a_inbox="$(join_path "$local_workdir" "$inbox_dir_name/peer-a")"
local_peer_a_stdout_log="$(join_path "$local_log_dir" "peer-a.stdout.log")"
local_peer_a_latency_log="$(join_path "$local_log_dir" "peer-a-kcp-latency.jsonl")"
local_peer_a_ts_debug_log="$(join_path "$local_log_dir" "peer-a-kcp-packet-debug.jsonl")"
local_peer_a_session_stats_log="$(join_path "$local_log_dir" "peer-a-kcp-session-stats.jsonl")"
local_peer_b_stdout_log="$(join_path "$local_log_dir" "peer-b.stdout.log")"
local_peer_b_latency_log="$(join_path "$local_log_dir" "peer-b-kcp-latency.jsonl")"
local_peer_b_ts_debug_log="$(join_path "$local_log_dir" "peer-b-kcp-packet-debug.jsonl")"
local_peer_b_session_stats_log="$(join_path "$local_log_dir" "peer-b-kcp-session-stats.jsonl")"
local_kcp_latency_summary_log="$(join_path "$local_log_dir" "kcp-latency-summary.jsonl")"
server_log_dir="$(join_path "$server_workdir" "$log_dir_name")"
server_pid_file="$(join_path "$server_log_dir" "server.pid")"
server_stdout_log="$(join_path "$server_log_dir" "server.stdout.log")"
peerb_log_dir="$(join_path "$peerb_workdir" "$log_dir_name")"
peerb_inbox_dir="$(join_path "$peerb_workdir" "$inbox_dir_name/peer-b")"
peerb_stdout_log="$(join_path "$peerb_log_dir" "peer-b.stdout.log")"
peerb_latency_log="$(join_path "$peerb_log_dir" "peer-b-kcp-latency.jsonl")"
peerb_ts_debug_log="$(join_path "$peerb_log_dir" "peer-b-kcp-packet-debug.jsonl")"
peerb_session_stats_log="$(join_path "$peerb_log_dir" "peer-b-kcp-session-stats.jsonl")"
peerb_pid_file="$(join_path "$peerb_log_dir" "peer-b.pid")"
peerb_command_file="$(join_path "$peerb_log_dir" "peer-b.commands")"
trap cleanup EXIT
trap handle_interrupt INT
trap handle_terminate TERM
clean_log_directories
mkdir -p "$local_log_dir" "$local_peer_a_inbox"
log "local peer-a logs: $local_log_dir"
log "remote server logs: $server_log_dir"
log "remote peer-b logs: $peerb_log_dir"
check_remote_peerb_files
start_remote_server
wait_for_remote_server_ready
start_local_peer_a
start_remote_peer_b
wait_for_local_peer_a_ready
wait_for_remote_peer_b_ready
run_remote_peer_b_batch
log "batch send completed"
if [[ -n "$peer_a_pid" ]]; then
log "stopping local peer-a after batch"
stop_local_peer_a
fi
if (( server_started == 1 )); then
log "stopping remote server on $server_ssh after batch"
if stop_remote_server; then
server_started=0
else
log "failed to stop remote server cleanly; cleanup will retry"
fi
fi
fetch_remote_peer_b_logs
run_local_latency_summary