feat: implement §9 file transfer over dedicated binary DataChannels
File chunks travel over a per-transfer "f:<xid>" WebRTC DataChannel —
direct DTLS-encrypted P2P, the anchor never sees file data. Once the
initial handshake is done the anchor can disappear and transfers continue.
Key design choices:
- Receiver sends "ok" on the file DC before sender streams, eliminating
a race where tiny files could be fully sent/closed before the receiver's
OnMessage handler is registered (open-race §6 analogue for data DCs).
- Auto-accept: receiver accepts every incoming offer immediately.
- Download dir: per-network at <data-dir>/downloads-<netid>/.
- Backpressure: bufferedAmountLowThreshold to avoid overwhelming the DC.
- SHA-256 verified on receive; mismatches emit EvtError and discard temp file.
- IPC: send_file {peer_id, path} → offers the named file from share dir.
- EvtFileComplete {transfer_id, path} emitted on success.
IPC command: {"type":"send_file","peer_id":"<hex>","path":"<filename>"}
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,26 @@ pretty() {
|
||||
echo -e "${color}${BOLD}[${label}]${RESET} ${BOLD}💬 #${room}${RESET} ${DIM}<${from}…>${RESET} ${body}"
|
||||
fi
|
||||
;;
|
||||
incoming_file)
|
||||
local name size xid
|
||||
name=$(echo "$line" | jq -r '.offer.name // "?"' 2>/dev/null)
|
||||
size=$(echo "$line" | jq -r '.offer.size // 0' 2>/dev/null)
|
||||
xid=$(echo "$line" | jq -r '.offer.xid[:8] // "?"' 2>/dev/null)
|
||||
echo -e "${color}${BOLD}[${label}]${RESET} ${YELLOW}↓ incoming_file${RESET} ${BOLD}${name}${RESET} (${size}B) xid=${DIM}${xid}…${RESET}"
|
||||
;;
|
||||
file_progress)
|
||||
local xid rx total
|
||||
xid=$(echo "$line" | jq -r '.transfer_id[:8] // "?"' 2>/dev/null)
|
||||
rx=$(echo "$line" | jq -r '.bytes_received // 0' 2>/dev/null)
|
||||
total=$(echo "$line" | jq -r '.total_bytes // 0' 2>/dev/null)
|
||||
echo -e "${color}${BOLD}[${label}]${RESET} ${DIM}file_progress${RESET} xid=${xid}… ${rx}/${total}B"
|
||||
;;
|
||||
file_complete)
|
||||
local xid path
|
||||
xid=$(echo "$line" | jq -r '.transfer_id[:8] // "?"' 2>/dev/null)
|
||||
path=$(echo "$line" | jq -r '.path // "?"' 2>/dev/null)
|
||||
echo -e "${color}${BOLD}[${label}]${RESET} ${GREEN}✓ file_complete${RESET} xid=${DIM}${xid}…${RESET} → ${BOLD}${path}${RESET}"
|
||||
;;
|
||||
error)
|
||||
local msg
|
||||
msg=$(echo "$line" | jq -r '.error_message // .' 2>/dev/null)
|
||||
@@ -364,6 +384,40 @@ for peer_ipc in "$ALICE_IPC" "$BOB_IPC" "$CHARLIE_IPC"; do
|
||||
done
|
||||
sleep 0.5
|
||||
|
||||
# ── file transfer ────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
echo -e "file transfer (alice → bob: notes.txt)"
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
|
||||
ipc "$ALICE_IPC" "$(jq -cn --arg peer "$BOB_ID" --arg path "notes.txt" \
|
||||
'{"type":"send_file","peer_id":$peer,"path":$path}')"
|
||||
|
||||
# Wait up to 10s for bob to receive the file (glob over downloads-* dir)
|
||||
received=0
|
||||
for i in $(seq 1 50); do
|
||||
sleep 0.2
|
||||
if ls "$DATA_ROOT/bob/downloads-"*/notes.txt 2>/dev/null | grep -q .; then
|
||||
received=1; break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$received" = "1" ]; then
|
||||
rx_file=$(ls "$DATA_ROOT/bob/downloads-"*/notes.txt 2>/dev/null | head -1)
|
||||
orig_sha=$(sha256sum "$DATA_ROOT/alice/share/notes.txt" | awk '{print $1}')
|
||||
rx_sha=$(sha256sum "$rx_file" | awk '{print $1}')
|
||||
if [ "$orig_sha" = "$rx_sha" ]; then
|
||||
echo -e " ${GREEN}✓ notes.txt received by bob, sha256 matches${RESET}"
|
||||
else
|
||||
echo -e " ${RED}✗ notes.txt received but sha256 mismatch!${RESET}"
|
||||
echo -e " orig: $orig_sha"
|
||||
echo -e " got: $rx_sha"
|
||||
fi
|
||||
else
|
||||
echo -e " ${RED}✗ notes.txt not received by bob within 10s${RESET}"
|
||||
fi
|
||||
sleep 0.5
|
||||
|
||||
# ── leave ─────────────────────────────────────────────────────────────────────
|
||||
echo ""
|
||||
echo -e "${DIM}────────────────────────────────────────────────────────${RESET}"
|
||||
|
||||
Reference in New Issue
Block a user