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:
@@ -57,6 +57,7 @@ func WireDataChannel(
|
||||
peerConn := &PeerConn{
|
||||
Info: proto.PeerInfo{ID: peerID, Alias: string(peerID.Short())},
|
||||
Send: sendCh,
|
||||
PC: pc,
|
||||
}
|
||||
m.AddPeer(peerConn)
|
||||
|
||||
@@ -211,6 +212,16 @@ func dispatchPeerMessage(msg proto.PeerMessage, from proto.PeerID, m *Mesh) {
|
||||
PeerID: peerIDPtr(from),
|
||||
Offer: &proto.FileOffer{Xid: msg.Xid, Name: msg.Name, Size: msg.Size, SHA256: msg.SHA256},
|
||||
})
|
||||
m.acceptIncoming(msg, from)
|
||||
|
||||
case proto.MsgFileAccept:
|
||||
m.startSend(msg.Xid, from)
|
||||
|
||||
case proto.MsgFileCancel:
|
||||
log.Printf("mesh: file-cancel from %s xid=%s reason=%s", from.Short(), msg.Xid, msg.Reason)
|
||||
|
||||
case proto.MsgFileDone:
|
||||
log.Printf("mesh: file-done from %s xid=%s", from.Short(), msg.Xid)
|
||||
|
||||
case proto.MsgPeerGossip:
|
||||
if msg.Gossip != nil {
|
||||
|
||||
Reference in New Issue
Block a user