copier: прогресс по байтам, скорость и ETA
- Прогрессбар по скопированным байтам (doneBytes / totalBytes) - SpeedBPS и ETASec добавлены в Task - Dashboard показывает скорость (МБ/с) и ETA справа от прогрессбара Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"jukebox_maker/internal/config"
|
||||
"jukebox_maker/internal/db"
|
||||
@@ -150,36 +151,63 @@ func (c *Copier) run(ctx context.Context, taskID string, opts Options, database
|
||||
return
|
||||
}
|
||||
|
||||
// суммарный объём для прогресса (всех файлов в списке)
|
||||
var totalBytes int64
|
||||
for _, f := range files {
|
||||
totalBytes += f.size
|
||||
}
|
||||
|
||||
total := len(files)
|
||||
copied := 0
|
||||
var doneBytes int64
|
||||
startTime := time.Now()
|
||||
|
||||
for i, f := range files {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
c.tasks.Update(taskID, func(t *task.Task) {
|
||||
t.Status = task.StatusCanceled
|
||||
t.Message = "Отменено"
|
||||
t.SpeedBPS = 0
|
||||
t.ETASec = 0
|
||||
})
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
||||
if f.size > available {
|
||||
// файл не влезает — пробуем следующий
|
||||
continue
|
||||
}
|
||||
|
||||
prog := int(float64(i+1) / float64(total) * 100)
|
||||
elapsed := time.Since(startTime).Seconds()
|
||||
var speedBPS, etaSec int64
|
||||
if elapsed > 0 && doneBytes > 0 {
|
||||
speedBPS = int64(float64(doneBytes) / elapsed)
|
||||
remaining := totalBytes - doneBytes
|
||||
if speedBPS > 0 {
|
||||
etaSec = remaining / speedBPS
|
||||
}
|
||||
}
|
||||
|
||||
prog := int(float64(doneBytes) / float64(totalBytes) * 100)
|
||||
msg := fmt.Sprintf("Копирование %s (%d/%d)", filepath.Base(f.srcAbs), i+1, total)
|
||||
setStatus(task.StatusRunning, msg, prog)
|
||||
|
||||
// destination mirrors source structure under destRoot
|
||||
c.tasks.Update(taskID, func(t *task.Task) {
|
||||
t.Status = task.StatusRunning
|
||||
t.Message = msg
|
||||
t.Progress = prog
|
||||
t.SpeedBPS = speedBPS
|
||||
t.ETASec = int(etaSec)
|
||||
})
|
||||
|
||||
dstAbs := filepath.Join(destRoot, f.relPath)
|
||||
|
||||
if err := rsyncFile(ctx, f.srcAbs, dstAbs); err != nil {
|
||||
if errors.Is(err, context.Canceled) {
|
||||
c.tasks.Update(taskID, func(t *task.Task) {
|
||||
t.Status = task.StatusCanceled
|
||||
t.Message = "Отменено"
|
||||
t.SpeedBPS = 0
|
||||
t.ETASec = 0
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -187,6 +215,7 @@ func (c *Copier) run(ctx context.Context, taskID string, opts Options, database
|
||||
}
|
||||
|
||||
available -= f.size
|
||||
doneBytes += f.size
|
||||
copied++
|
||||
_ = database.RecordCopy(db.CopyRecord{
|
||||
DiskID: opts.DiskID,
|
||||
|
||||
Reference in New Issue
Block a user