Fix file transfer, signaling reliability, and DC callback races
- wireFileRecv: replace OnMessage/OnClose channel approach with pion Detach API so SCTP buffers data regardless of callback timing — fixes 0-byte files caused by pion dispatching data goroutines before OnMessage was registered - yaw DC: same Detach API treatment for the control channel - connectTo: use DetachDataChannels SettingEngine, replace stale PCs (Connecting/Failed/Disconnected state) instead of returning early; isCurrent guard in OnConnectionStateChange prevents stale-PC close from firing OnDisconnected - offerByOrder: gate maybeOffer on peer ID order so only one side creates the yaw DC and SDP offer — fixes signaling glare causing triple connected (verified) logs - pendingRecvs: promote single pendingRecv slot to map[string]*recvState so concurrent file offers don't overwrite each other - peer-left: stop calling resetPeer() so active file DCs aren't closed before data arrives - signaling ping: wrap conn.Ping with 10s timeout context so a dead TCP connection is detected within 30s rather than hanging forever - signaling read: 3-minute read deadline forces reconnect if anchor silently evicts the peer from the room (idle timeout) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -115,6 +115,7 @@ func runDaemon(ctx context.Context) {
|
||||
// reconnecting with exponential backoff whenever the connection drops.
|
||||
func runPeerLoop(ctx context.Context, tc transport.Config, myID string, peer peerConfig, downloadDir string) {
|
||||
room := transport.PairRoomName(myID, peer.ID)
|
||||
log.Printf("[%s] room: %s", peer.Label, room)
|
||||
backoff := 2 * time.Second
|
||||
|
||||
for {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// flit — headless CLI for ephemeral, E2E-encrypted file transfer.
|
||||
//
|
||||
// flit id print this device's peer ID (hex Ed25519 pubkey)
|
||||
// flit send <path> generate a one-shot room, print QR + invite, wait for a peer, send
|
||||
// flit recv <invite|code> join a room from an invite string, accept the offered file
|
||||
// flit daemon run as a persistent receiver for trusted peers (reads ~/.flit/daemon.toml)
|
||||
@@ -100,6 +101,8 @@ func main() {
|
||||
defer stop()
|
||||
|
||||
switch os.Args[1] {
|
||||
case "id":
|
||||
printID()
|
||||
case "send":
|
||||
if len(os.Args) < 3 {
|
||||
fmt.Println("usage: flit send <path>")
|
||||
@@ -115,11 +118,20 @@ func main() {
|
||||
case "daemon":
|
||||
runDaemon(ctx)
|
||||
default:
|
||||
fmt.Println("usage: flit send <path> | flit recv <invite> | flit daemon")
|
||||
fmt.Println("usage: flit id | flit send <path> | flit recv <invite> | flit daemon")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func printID() {
|
||||
sess, err := transport.NewSession(dataDir(), transport.Config{})
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "flit:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println(sess.PeerID())
|
||||
}
|
||||
|
||||
func send(ctx context.Context, path string) {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "flit:", err)
|
||||
|
||||
Reference in New Issue
Block a user