From e32520659d7b43490bdee37c9274def81704fa4b Mon Sep 17 00:00:00 2001 From: Codinget Date: Thu, 16 Apr 2026 19:04:02 +0000 Subject: [PATCH] fix(taildrop): restore incoming file progress notifications The io.Copy in PutFile was writing directly to wc, bypassing the incomingFile wrapper whose Write method increments f.copied and fires a throttled sendFileNotify on progress. As a result, notifyIncomingFiles on the JS side only ever fired once (on completion) with received=0, making progress UI impossible. The original inFile wrapping was lost during the Android SAF refactor. Also surface the PartialFile.Done flag through jsIncomingFile so JS can distinguish the final "transfer complete" notification from in-progress updates. Co-Authored-By: Claude Opus 4.7 --- cmd/tsconnect/wasm/wasm_js.go | 2 ++ feature/taildrop/send.go | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/tsconnect/wasm/wasm_js.go b/cmd/tsconnect/wasm/wasm_js.go index 38f44a9bc..b76f23de0 100644 --- a/cmd/tsconnect/wasm/wasm_js.go +++ b/cmd/tsconnect/wasm/wasm_js.go @@ -405,6 +405,7 @@ func (i *jsIPN) run(jsCallbacks js.Value) { Started: f.Started.UnixMilli(), DeclaredSize: f.DeclaredSize, Received: f.Received, + Done: f.Done, } } if b, err := json.Marshal(files); err == nil { @@ -967,6 +968,7 @@ type jsIncomingFile struct { Started int64 `json:"started"` // Unix milliseconds; use new Date(started) in JS DeclaredSize int64 `json:"declaredSize"` // -1 if unknown Received int64 `json:"received"` // bytes received so far + Done bool `json:"done"` // true once the file has been fully received } // jsOutgoingFile is the JSON representation of an outgoing file transfer diff --git a/feature/taildrop/send.go b/feature/taildrop/send.go index 668166d44..6b5327f83 100644 --- a/feature/taildrop/send.go +++ b/feature/taildrop/send.go @@ -134,8 +134,9 @@ func (m *manager) PutFile(id clientID, baseName string, r io.Reader, offset, len } } - // Copy the contents of the file to the writer. - copyLength, err := io.Copy(wc, r) + // Copy via inFile (which wraps wc) so [incomingFile.Write] can track + // progress and fire periodic sendFileNotify callbacks. + copyLength, err := io.Copy(inFile, r) if err != nil { return 0, m.redactAndLogError("Copy", err) }