Bring wire protocol into full YAW/2 spec compliance
Five interop issues fixed against PROTOCOL.md:
- Join signature now covers nonce_raw || net_ascii (64-char UTF-8 hex
string) as specified in §5.1, not net_raw_bytes. Both anchor server
and client updated to match.
- Chat wire fields renamed to spec names: text/ts (Unix ms int64)
replacing body/sent_at (ISO timestamp). Flat layout on PeerMessage
matches §8 exactly; store and TUI updated accordingly.
- Direct messages now use the spec "pm" type (flat {type,mid,text,ts})
instead of chat+to. Receiver reconstructs a ChatMessage with
dm:<short-id> room for IPC/storage. §8 compliant.
- File transfer message types changed to spec hyphenated names:
file-offer, file-accept, file-cancel, file-done with spec field
names (name/size not filename/size_bytes). §9 compliant.
- DataChannel open-race (§14 gotcha #3) fixed with sync.Once: doOpen
fires on OnOpen callback or immediately if the channel is already
open when WireDataChannel is called (answerer race).
Also fixes two bugs found during testing:
- mid was missing from outgoing wire messages, causing all received
messages to arrive with mid="" and collide on the UNIQUE DB
constraint. mid is now included on all sent chat/pm messages; a
random mid is generated for any received message that omits it.
- Test scripts hardened: kill -9 + active lsof polling replaces blind
sleep for port cleanup; join_network sent before peer_field queries
(local_peer is now network-scoped and nil until joined).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,21 @@ DATA_ROOT="/tmp/waste-test"
|
||||
rm -rf "$DATA_ROOT"
|
||||
mkdir -p "$DATA_ROOT/bin"
|
||||
|
||||
# Kill any leftover processes from a previous run holding our fixed ports.
|
||||
for port in "$ANCHOR_PORT" "$ALICE_IPC" "$BOB_IPC" "$CHARLIE_IPC"; do
|
||||
pid=$(lsof -ti tcp:"$port" 2>/dev/null || true)
|
||||
[ -n "$pid" ] && kill -9 $pid 2>/dev/null || true
|
||||
done
|
||||
# Wait until all ports are actually free before proceeding.
|
||||
for port in "$ANCHOR_PORT" "$ALICE_IPC" "$BOB_IPC" "$CHARLIE_IPC"; do
|
||||
n=0
|
||||
while lsof -ti tcp:"$port" >/dev/null 2>&1; do
|
||||
sleep 0.1
|
||||
n=$(( n + 1 ))
|
||||
[ "$n" -gt 30 ] && echo -e "${RED}port ${port} still in use after 3s${RESET}" >&2 && break
|
||||
done
|
||||
done
|
||||
|
||||
# ── cleanup ───────────────────────────────────────────────────────────────────
|
||||
PIDS=()
|
||||
cleanup() {
|
||||
@@ -35,7 +50,6 @@ cleanup() {
|
||||
done
|
||||
wait 2>/dev/null || true
|
||||
echo -e "${DIM}data left at: ${DATA_ROOT}${RESET}"
|
||||
echo -e "${DIM} inspect: sqlite3 /tmp/waste-test/alice/messages.db${RESET}"
|
||||
echo -e "${DIM}done.${RESET}"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
@@ -80,7 +94,7 @@ pretty() {
|
||||
message_received)
|
||||
local from body room to_field
|
||||
from=$(echo "$line" | jq -r '.message.from[:8] // "?"' 2>/dev/null)
|
||||
body=$(echo "$line" | jq -r '.message.body // ""' 2>/dev/null)
|
||||
body=$(echo "$line" | jq -r '.message.text // ""' 2>/dev/null)
|
||||
room=$(echo "$line" | jq -r '.message.room // ""' 2>/dev/null)
|
||||
to_field=$(echo "$line" | jq -r '.message.to // ""' 2>/dev/null)
|
||||
if [ -n "$to_field" ]; then
|
||||
@@ -221,24 +235,6 @@ 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
|
||||
|
||||
# ── resolve peer IDs ──────────────────────────────────────────────────────────
|
||||
# Each daemon knows its own id from the state_snapshot.
|
||||
ALICE_ID=$(peer_field "$ALICE_IPC" '.local_peer.id')
|
||||
BOB_ID=$(peer_field "$BOB_IPC" '.local_peer.id')
|
||||
CHARLIE_ID=$(peer_field "$CHARLIE_IPC" '.local_peer.id')
|
||||
|
||||
log "$ANCHOR_COLOR" "ids" "alice = ${ALICE_ID:0:16}…"
|
||||
log "$ANCHOR_COLOR" "ids" "bob = ${BOB_ID:0:16}…"
|
||||
log "$ANCHOR_COLOR" "ids" "charlie = ${CHARLIE_ID:0:16}…"
|
||||
echo ""
|
||||
|
||||
# ── join network ──────────────────────────────────────────────────────────────
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
echo -e "joining all peers to network: ${BOLD}${NETWORK_NAME}${RESET}"
|
||||
@@ -250,6 +246,24 @@ sleep 0.2
|
||||
ipc "$BOB_IPC" "$JOIN"
|
||||
sleep 0.2
|
||||
ipc "$CHARLIE_IPC" "$JOIN"
|
||||
sleep 0.3
|
||||
|
||||
# ── resolve peer IDs ──────────────────────────────────────────────────────────
|
||||
# Peer IDs are network-scoped (derived identity), so we query AFTER joining.
|
||||
ALICE_ID=$(peer_field "$ALICE_IPC" '.local_peer.id')
|
||||
BOB_ID=$(peer_field "$BOB_IPC" '.local_peer.id')
|
||||
CHARLIE_ID=$(peer_field "$CHARLIE_IPC" '.local_peer.id')
|
||||
|
||||
log "$ANCHOR_COLOR" "ids" "alice = ${ALICE_ID:0:16}…"
|
||||
log "$ANCHOR_COLOR" "ids" "bob = ${BOB_ID:0:16}…"
|
||||
log "$ANCHOR_COLOR" "ids" "charlie = ${CHARLIE_ID:0:16}…"
|
||||
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"
|
||||
|
||||
echo -e "${DIM}waiting for ICE / DataChannel setup (up to 10s)…${RESET}"
|
||||
sleep 6
|
||||
@@ -318,19 +332,25 @@ echo -e "${DIM}─────────────────────
|
||||
echo -e "file listing"
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
|
||||
alice_nets=$(echo '{"type":"get_state"}' | timeout 2 nc 127.0.0.1 "$ALICE_IPC" 2>/dev/null \
|
||||
| grep '"type":"state_snapshot"' | head -1 \
|
||||
| jq -r '[.networks[].network_name] | join(", ")' 2>/dev/null || echo "?")
|
||||
echo -e "${DIM} alice networks: [${alice_nets:-none}]${RESET}"
|
||||
|
||||
for peer_ipc in "$ALICE_IPC" "$BOB_IPC" "$CHARLIE_IPC"; do
|
||||
if [ "$peer_ipc" = "$ALICE_IPC" ]; then peer_name="alice"
|
||||
elif [ "$peer_ipc" = "$BOB_IPC" ]; then peer_name="bob"
|
||||
else peer_name="charlie"; fi
|
||||
result=$(echo '{"type":"get_file_list"}' \
|
||||
| timeout 2 nc 127.0.0.1 "$peer_ipc" 2>/dev/null \
|
||||
| grep '"type":"file_list"' | head -1)
|
||||
raw=$(echo '{"type":"get_file_list"}' \
|
||||
| nc -q 2 127.0.0.1 "$peer_ipc" 2>/dev/null || true)
|
||||
result=$(echo "$raw" | grep '"type":"file_list"' | head -1 || true)
|
||||
if [ -n "$result" ]; then
|
||||
count=$(echo "$result" | jq '.files | length' 2>/dev/null || echo "?")
|
||||
files=$(echo "$result" | jq -r '.files[].name' 2>/dev/null | tr '\n' ' ')
|
||||
files=$(echo "$result" | jq -r '[.files[].name] | join(" ")' 2>/dev/null || true)
|
||||
echo -e " ${BOLD}${peer_name}${RESET}: ${count} file(s) — ${files}"
|
||||
else
|
||||
echo -e " ${RED}${peer_name}: no file_list response${RESET}"
|
||||
types=$(echo "$raw" | jq -r '.type' 2>/dev/null | tr '\n' ',' | sed 's/,$//' || true)
|
||||
echo -e " ${RED}${peer_name}: no file_list response${RESET} ${DIM}(got: ${types:-nothing})${RESET}"
|
||||
fi
|
||||
done
|
||||
sleep 0.5
|
||||
@@ -349,15 +369,15 @@ echo -e "${DIM}─────────────────────
|
||||
echo -e "verifying persistence (SQLite)"
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
for peer in alice bob charlie; do
|
||||
db="$DATA_ROOT/$peer/messages.db"
|
||||
if [ -f "$db" ]; then
|
||||
db=$(ls "$DATA_ROOT/$peer/messages-"*.db 2>/dev/null | head -1 || true)
|
||||
if [ -n "$db" ] && [ -f "$db" ]; then
|
||||
total=$(sqlite3 "$db" "SELECT COUNT(*) FROM messages;" 2>/dev/null || echo "?")
|
||||
group=$(sqlite3 "$db" "SELECT COUNT(*) FROM messages WHERE room='general';" 2>/dev/null || echo "?")
|
||||
dms=$(sqlite3 "$db" "SELECT COUNT(*) FROM messages WHERE room LIKE 'dm:%';" 2>/dev/null || echo "?")
|
||||
peers_count=$(sqlite3 "$db" "SELECT COUNT(*) FROM peers;" 2>/dev/null || echo "?")
|
||||
echo -e " ${BOLD}${peer}${RESET}: ${total} total (${group} group, ${dms} DM), ${peers_count} known peers"
|
||||
else
|
||||
echo -e " ${RED}${peer}: no messages.db found${RESET}"
|
||||
echo -e " ${RED}${peer}: no messages-*.db found${RESET}"
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user