mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-08-28 19:47:27 +08:00
1. 失败自动重试:rclone Pacer 指数退避,默认 10 次底层 HTTP 重试 2. 带宽限制:配置 bandwidth_limit + Settings 运行时可调 3. 上传实时进度:progressReader + LogHub SSE 推送字节级进度/速率 4. 存储空间查询:StorageAbout 可选接口,GetUsage 返回远端真实空间 5. 全 rclone 后端:backend/all 引入 70+ 后端,新增 rclone 存储类型, API 驱动的可搜索后端选择器 + 动态配置表单
53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
package service
|
|
|
|
import (
|
|
"io"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// progressCallback 在每次读取时被调用,报告已读字节数和估算速率。
|
|
type progressCallback func(bytesRead int64, speedBps float64)
|
|
|
|
// progressReader 包装 io.Reader,定期通过回调报告传输进度。
|
|
type progressReader struct {
|
|
reader io.Reader
|
|
total int64
|
|
read atomic.Int64
|
|
callback progressCallback
|
|
startTime time.Time
|
|
lastCall time.Time
|
|
interval time.Duration
|
|
}
|
|
|
|
func newProgressReader(reader io.Reader, total int64, callback progressCallback) *progressReader {
|
|
now := time.Now()
|
|
return &progressReader{
|
|
reader: reader,
|
|
total: total,
|
|
callback: callback,
|
|
startTime: now,
|
|
lastCall: now,
|
|
interval: 500 * time.Millisecond,
|
|
}
|
|
}
|
|
|
|
func (r *progressReader) Read(p []byte) (int, error) {
|
|
n, err := r.reader.Read(p)
|
|
if n > 0 {
|
|
current := r.read.Add(int64(n))
|
|
now := time.Now()
|
|
isFinal := err == io.EOF || (r.total > 0 && current >= r.total)
|
|
if isFinal || now.Sub(r.lastCall) >= r.interval {
|
|
r.lastCall = now
|
|
elapsed := now.Sub(r.startTime).Seconds()
|
|
speed := float64(0)
|
|
if elapsed > 0 {
|
|
speed = float64(current) / elapsed
|
|
}
|
|
r.callback(current, speed)
|
|
}
|
|
}
|
|
return n, err
|
|
}
|