@@ -146,10 +146,11 @@ func (h *HTTPFileStager) doUpload(ctx context.Context, addr, nodeID, localPath,
146146 defer f .Close ()
147147
148148 var body io.Reader = f
149- // For files > 100MB, wrap with progress logging
149+ cb := StagingProgressFromContext (ctx )
150+ // For files > 100MB or when a progress callback is set, wrap with progress reporting
150151 const progressThreshold = 100 << 20
151- if fileSize > progressThreshold {
152- body = newProgressReader (f , fileSize , filepath .Base (localPath ), nodeID )
152+ if fileSize > progressThreshold || cb != nil {
153+ body = newProgressReader (f , fileSize , filepath .Base (localPath ), nodeID , cb )
153154 }
154155
155156 req , err := http .NewRequestWithContext (ctx , http .MethodPut , url , body )
@@ -268,26 +269,30 @@ func (h *HTTPFileStager) probeExisting(ctx context.Context, addr, localPath, key
268269}
269270
270271// progressReader wraps an io.Reader and logs upload progress periodically.
272+ // If a StagingProgressCallback is present in the context, it also calls it
273+ // for UI-visible progress updates.
271274type progressReader struct {
272- reader io.Reader
273- total int64
274- read int64
275- file string
276- node string
277- lastLog time.Time
278- lastPct int
279- start time.Time
280- mu sync.Mutex
275+ reader io.Reader
276+ total int64
277+ read int64
278+ file string
279+ node string
280+ lastLog time.Time
281+ lastPct int
282+ start time.Time
283+ mu sync.Mutex
284+ progressCb StagingProgressCallback
281285}
282286
283- func newProgressReader (r io.Reader , total int64 , file , node string ) * progressReader {
287+ func newProgressReader (r io.Reader , total int64 , file , node string , cb StagingProgressCallback ) * progressReader {
284288 return & progressReader {
285- reader : r ,
286- total : total ,
287- file : file ,
288- node : node ,
289- start : time .Now (),
290- lastLog : time .Now (),
289+ reader : r ,
290+ total : total ,
291+ file : file ,
292+ node : node ,
293+ start : time .Now (),
294+ lastLog : time .Now (),
295+ progressCb : cb ,
291296 }
292297}
293298
@@ -313,6 +318,10 @@ func (pr *progressReader) Read(p []byte) (int, error) {
313318 pr .lastLog = now
314319 pr .lastPct = pct
315320 }
321+ // Call external progress callback for UI visibility
322+ if pr .progressCb != nil {
323+ pr .progressCb (pr .file , pr .read , pr .total )
324+ }
316325 pr .mu .Unlock ()
317326 }
318327 return n , err
@@ -385,7 +394,19 @@ func (h *HTTPFileStager) FetchRemoteByKey(ctx context.Context, nodeID, key, loca
385394 }
386395 defer f .Close ()
387396
388- written , err := io .Copy (f , resp .Body )
397+ // Wrap response body with progress reporting if callback is set or file is large
398+ var src io.Reader = resp .Body
399+ cb := StagingProgressFromContext (ctx )
400+ totalSize := resp .ContentLength
401+ const progressThreshold = 100 << 20
402+ if totalSize > progressThreshold || cb != nil {
403+ if totalSize <= 0 {
404+ totalSize = 0 // unknown size — progress reader will still report bytes
405+ }
406+ src = newProgressReader (resp .Body , totalSize , filepath .Base (key ), nodeID , cb )
407+ }
408+
409+ written , err := io .Copy (f , src )
389410 if err != nil {
390411 os .Remove (localDst )
391412 return fmt .Errorf ("writing to %s: %w" , localDst , err )
0 commit comments