Files
waste-go/test-network.sh

252 lines
12 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# test-network.sh — spin up anchor + 3 peers, connect them, exchange messages.
# Usage: ./test-network.sh
# Requires: go, nc, jq
set -euo pipefail
# ── colours ───────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
CYAN='\033[0;36m'; MAGENTA='\033[0;35m'; BLUE='\033[0;34m'
BOLD='\033[1m'; DIM='\033[2m'; RESET='\033[0m'
ANCHOR_COLOR=$YELLOW
ALICE_COLOR=$CYAN
BOB_COLOR=$MAGENTA
CHARLIE_COLOR=$GREEN
# ── config ────────────────────────────────────────────────────────────────────
ANCHOR_PORT=19339
ALICE_IPC=19337
BOB_IPC=19340
CHARLIE_IPC=19343
NETWORK_NAME="test-$(date +%s)"
DATA_ROOT=$(mktemp -d /tmp/waste-test-XXXXXX)
# ── cleanup ───────────────────────────────────────────────────────────────────
PIDS=()
cleanup() {
echo ""
echo -e "${DIM}── cleaning up ──────────────────────────────────────────${RESET}"
for pid in "${PIDS[@]:-}"; do
kill "$pid" 2>/dev/null || true
done
wait 2>/dev/null || true
rm -rf "$DATA_ROOT"
echo -e "${DIM}done.${RESET}"
}
trap cleanup EXIT INT TERM
# ── helpers ───────────────────────────────────────────────────────────────────
log() {
local color="$1"; shift
local label="$1"; shift
echo -e "${color}${BOLD}[${label}]${RESET} $*"
}
# Pretty-print a raw IPC JSON line
pretty() {
local color="$1"
local label="$2"
local line="$3"
local type
type=$(echo "$line" | jq -r '.type // "?"' 2>/dev/null)
case "$type" in
state_snapshot)
local id nick
id=$(echo "$line" | jq -r '.local_peer.id[:16]' 2>/dev/null | sed 's/.\{4\}/& /g')
nick=$(echo "$line" | jq -r '.local_peer.alias' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${DIM}state_snapshot${RESET} id=${CYAN}${id}${RESET} alias=${BOLD}${nick}${RESET}"
;;
session_ready)
local pid nick
pid=$(echo "$line" | jq -r 'if .peer_id then .peer_id[:16] else "?" end' 2>/dev/null | sed 's/.\{4\}/& /g')
nick=$(echo "$line" | jq -r '.nick // "?"' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${GREEN}✓ session_ready${RESET} peer=${BOLD}${nick}${RESET} (${DIM}${pid}${RESET})"
;;
peer_connected)
local nick
nick=$(echo "$line" | jq -r '.peer.alias // "?"' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${GREEN}→ peer_connected${RESET} ${BOLD}${nick}${RESET}"
;;
peer_disconnected)
local pid
pid=$(echo "$line" | jq -r 'if .peer_id then .peer_id[:8] else "?" end' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${RED}← peer_disconnected${RESET} ${DIM}${pid}${RESET}"
;;
message_received)
local from body room
from=$(echo "$line" | jq -r '.message.from[:8] // "?"' 2>/dev/null)
body=$(echo "$line" | jq -r '.message.body // ""' 2>/dev/null)
room=$(echo "$line" | jq -r '.message.room // ""' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${BOLD}💬 #${room}${RESET} ${DIM}<${from}…>${RESET} ${body}"
;;
error)
local msg
msg=$(echo "$line" | jq -r '.error_message // .' 2>/dev/null)
echo -e "${color}${BOLD}[${label}]${RESET} ${RED}✗ error:${RESET} ${msg}"
;;
*)
echo -e "${color}${BOLD}[${label}]${RESET} ${DIM}${line}${RESET}"
;;
esac
}
# Subscribe to a peer's IPC events in the background, pretty-printing each line.
subscribe() {
local color="$1"
local label="$2"
local port="$3"
(
set +e
nc 127.0.0.1 "$port" 2>/dev/null | while IFS= read -r line; do
pretty "$color" "$label" "$line"
done
) &
PIDS+=($!)
}
# Send a single JSON command to a peer's IPC port (fire-and-forget).
ipc() {
local port="$1"
local json="$2"
echo "$json" | nc -q 0 127.0.0.1 "$port" >/dev/null 2>&1 || true
}
# Wait until a TCP port accepts connections (up to N seconds).
wait_port() {
local port="$1"
local label="$2"
local n=0
while ! nc -z 127.0.0.1 "$port" 2>/dev/null; do
sleep 0.1
n=$(( n + 1 ))
if [ "$n" -gt 80 ]; then
echo -e "${RED}timeout waiting for ${label} on :${port}${RESET}" >&2
exit 1
fi
done
}
# ── build ─────────────────────────────────────────────────────────────────────
echo ""
echo -e "${BOLD}waste-go network test${RESET}"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "${DIM}network : ${BOLD}${NETWORK_NAME}${RESET}"
echo -e "${DIM}data : ${DATA_ROOT}${RESET}"
echo ""
echo -e "${DIM}building binaries…${RESET}"
go build -o "$DATA_ROOT/bin/waste-anchor" ./cmd/anchor
go build -o "$DATA_ROOT/bin/waste-daemon" ./cmd/daemon
echo -e "${GREEN}✓ built${RESET}"
echo ""
# ── anchor ────────────────────────────────────────────────────────────────────
log "$ANCHOR_COLOR" "anchor" "starting on :${ANCHOR_PORT}"
"$DATA_ROOT/bin/waste-anchor" -bind "127.0.0.1:${ANCHOR_PORT}" \
2> >(while IFS= read -r l; do echo -e "${ANCHOR_COLOR}${DIM}[anchor] ${l}${RESET}"; done) &
PIDS+=($!)
wait_port "$ANCHOR_PORT" "anchor"
log "$ANCHOR_COLOR" "anchor" "ready"
echo ""
# ── daemons ───────────────────────────────────────────────────────────────────
ANCHOR_URL="ws://127.0.0.1:${ANCHOR_PORT}/ws"
log "$ALICE_COLOR" "alice" "starting daemon (ipc :${ALICE_IPC})"
"$DATA_ROOT/bin/waste-daemon" \
-alias alice \
-data-dir "$DATA_ROOT/alice" \
-ipc-port "$ALICE_IPC" \
-anchor "$ANCHOR_URL" \
2> >(while IFS= read -r l; do echo -e "${ALICE_COLOR}${DIM}[alice] ${l}${RESET}"; done) &
PIDS+=($!)
log "$BOB_COLOR" "bob" "starting daemon (ipc :${BOB_IPC})"
"$DATA_ROOT/bin/waste-daemon" \
-alias bob \
-data-dir "$DATA_ROOT/bob" \
-ipc-port "$BOB_IPC" \
-anchor "$ANCHOR_URL" \
2> >(while IFS= read -r l; do echo -e "${BOB_COLOR}${DIM}[bob] ${l}${RESET}"; done) &
PIDS+=($!)
log "$CHARLIE_COLOR" "charlie" "starting daemon (ipc :${CHARLIE_IPC})"
"$DATA_ROOT/bin/waste-daemon" \
-alias charlie \
-data-dir "$DATA_ROOT/charlie" \
-ipc-port "$CHARLIE_IPC" \
-anchor "$ANCHOR_URL" \
2> >(while IFS= read -r l; do echo -e "${CHARLIE_COLOR}${DIM}[charlie]${l}${RESET}"; done) &
PIDS+=($!)
wait_port "$ALICE_IPC" "alice"
wait_port "$BOB_IPC" "bob"
wait_port "$CHARLIE_IPC" "charlie"
echo ""
# ── subscribe ─────────────────────────────────────────────────────────────────
echo -e "${DIM}subscribing to IPC event streams…${RESET}"
subscribe "$ALICE_COLOR" "alice " "$ALICE_IPC"
subscribe "$BOB_COLOR" "bob " "$BOB_IPC"
subscribe "$CHARLIE_COLOR" "charlie" "$CHARLIE_IPC"
sleep 0.3 # let state_snapshot lines arrive
# ── join network ──────────────────────────────────────────────────────────────
echo ""
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "joining all peers to network: ${BOLD}${NETWORK_NAME}${RESET}"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
JOIN=$(printf '{"type":"join_network","network_name":"%s"}' "$NETWORK_NAME")
ipc "$ALICE_IPC" "$JOIN"
sleep 0.2
ipc "$BOB_IPC" "$JOIN"
sleep 0.2
ipc "$CHARLIE_IPC" "$JOIN"
echo -e "${DIM}waiting for ICE / DataChannel setup (up to 10s)…${RESET}"
sleep 6
# ── chat ──────────────────────────────────────────────────────────────────────
echo ""
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "sending messages"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
ipc "$ALICE_IPC" '{"type":"send_message","room":"general","body":"hey everyone, alice here"}'
sleep 0.4
ipc "$BOB_IPC" '{"type":"send_message","room":"general","body":"hi alice! bob checking in"}'
sleep 0.4
ipc "$CHARLIE_IPC" '{"type":"send_message","room":"general","body":"charlie online. the mesh works!"}'
sleep 0.4
ipc "$ALICE_IPC" '{"type":"send_message","room":"general","body":"nice — three-way chat over WebRTC 🎉"}'
sleep 0.4
ipc "$BOB_IPC" '{"type":"send_message","room":"general","body":"no central server, fully peer-to-peer"}'
sleep 0.4
# ── state snapshot ────────────────────────────────────────────────────────────
echo ""
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "requesting state snapshots"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
ipc "$ALICE_IPC" '{"type":"get_state"}'
ipc "$BOB_IPC" '{"type":"get_state"}'
ipc "$CHARLIE_IPC" '{"type":"get_state"}'
sleep 0.5
# ── leave ─────────────────────────────────────────────────────────────────────
echo ""
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "charlie leaves the network"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
ipc "$CHARLIE_IPC" '{"type":"leave_network"}'
sleep 1
echo ""
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
echo -e "${GREEN}${BOLD}test complete${RESET}"
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
sleep 0.5