fix: register file-done channel before sending file-accept
For small files, file-done arrives before wireFileRecv's goroutine reaches the pendingDones registration — the message was discarded and the goroutine timed out. Fix by registering doneCh in AcceptOffer (before sending file-accept), carrying it through recvState, and reading it in wireFileRecv without re-registering. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -777,13 +777,20 @@ func (s *Session) AcceptOffer(offer FileOffer, downloadDir string) {
|
|||||||
if info, err := os.Stat(partPath); err == nil && info.Size() < offer.Size {
|
if info, err := os.Stat(partPath); err == nil && info.Size() < offer.Size {
|
||||||
offset = info.Size()
|
offset = info.Size()
|
||||||
}
|
}
|
||||||
s.controlSend(map[string]string{"type": "file-accept", "xid": offer.XID, "offset": fmt.Sprint(offset)})
|
// Register doneCh before sending file-accept so file-done can never arrive
|
||||||
|
// before the channel exists (small files finish before wireFileRecv runs).
|
||||||
|
doneCh := make(chan string, 1)
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
|
if s.pendingDones == nil {
|
||||||
|
s.pendingDones = make(map[string]chan string)
|
||||||
|
}
|
||||||
|
s.pendingDones[offer.XID] = doneCh
|
||||||
if s.pendingRecvs == nil {
|
if s.pendingRecvs == nil {
|
||||||
s.pendingRecvs = make(map[string]*recvState)
|
s.pendingRecvs = make(map[string]*recvState)
|
||||||
}
|
}
|
||||||
s.pendingRecvs[offer.XID] = &recvState{offer: offer, dir: downloadDir, have: offset}
|
s.pendingRecvs[offer.XID] = &recvState{offer: offer, dir: downloadDir, have: offset, doneCh: doneCh}
|
||||||
s.mu.Unlock()
|
s.mu.Unlock()
|
||||||
|
s.controlSend(map[string]string{"type": "file-accept", "xid": offer.XID, "offset": fmt.Sprint(offset)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) RejectOffer(xid string) {
|
func (s *Session) RejectOffer(xid string) {
|
||||||
@@ -791,10 +798,11 @@ func (s *Session) RejectOffer(xid string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type recvState struct {
|
type recvState struct {
|
||||||
offer FileOffer
|
offer FileOffer
|
||||||
dir string
|
dir string
|
||||||
have int64
|
have int64
|
||||||
f *os.File
|
f *os.File
|
||||||
|
doneCh chan string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Session) wireFileRecv(dc *webrtc.DataChannel) {
|
func (s *Session) wireFileRecv(dc *webrtc.DataChannel) {
|
||||||
@@ -885,13 +893,9 @@ func (s *Session) wireFileRecv(dc *webrtc.DataChannel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// §9: wait for file-done and verify sha256 before reporting success.
|
// §9: wait for file-done and verify sha256 before reporting success.
|
||||||
doneCh := make(chan string, 1)
|
// doneCh was registered in AcceptOffer before file-accept was sent,
|
||||||
s.mu.Lock()
|
// so file-done can never arrive before the channel exists.
|
||||||
if s.pendingDones == nil {
|
doneCh := rs.doneCh
|
||||||
s.pendingDones = make(map[string]chan string)
|
|
||||||
}
|
|
||||||
s.pendingDones[xid] = doneCh
|
|
||||||
s.mu.Unlock()
|
|
||||||
var expectedSHA256 string
|
var expectedSHA256 string
|
||||||
select {
|
select {
|
||||||
case expectedSHA256 = <-doneCh:
|
case expectedSHA256 = <-doneCh:
|
||||||
|
|||||||
Reference in New Issue
Block a user