mirror of
https://github.com/Awuqing/BackupX.git
synced 2026-07-23 05:28:14 +08:00
功能: 集成 rclone 高级传输特性 + 全 70+ 后端支持
1. 失败自动重试:rclone Pacer 指数退避,默认 10 次底层 HTTP 重试 2. 带宽限制:配置 bandwidth_limit + Settings 运行时可调 3. 上传实时进度:progressReader + LogHub SSE 推送字节级进度/速率 4. 存储空间查询:StorageAbout 可选接口,GetUsage 返回远端真实空间 5. 全 rclone 后端:backend/all 引入 70+ 后端,新增 rclone 存储类型, API 驱动的可搜索后端选择器 + 动态配置表单
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package backup
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
@@ -99,6 +100,41 @@ func (h *LogHub) Complete(recordID uint, status string) {
|
||||
}
|
||||
}
|
||||
|
||||
// AppendProgress 推送上传进度事件(节流:每个 recordID 每 500ms 最多一次,最终值始终推送)。
|
||||
func (h *LogHub) AppendProgress(recordID uint, progress ProgressInfo) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
state := h.ensureState(recordID)
|
||||
|
||||
// 节流:距上次 progress 事件不足 500ms 且未完成则跳过(100% 始终推送)
|
||||
now := time.Now().UTC()
|
||||
isFinal := progress.Percent >= 100
|
||||
if !isFinal && len(state.events) > 0 {
|
||||
last := state.events[len(state.events)-1]
|
||||
if last.Progress != nil && now.Sub(last.Timestamp) < 500*time.Millisecond {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
state.nextSequence++
|
||||
event := LogEvent{
|
||||
RecordID: recordID,
|
||||
Sequence: state.nextSequence,
|
||||
Level: "progress",
|
||||
Message: fmt.Sprintf("上传进度: %.1f%%", progress.Percent),
|
||||
Timestamp: now,
|
||||
Status: state.status,
|
||||
Progress: &progress,
|
||||
}
|
||||
state.events = append(state.events, event)
|
||||
for _, subscriber := range state.subscribers {
|
||||
select {
|
||||
case subscriber <- event:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *LogHub) ensureState(recordID uint) *logStreamState {
|
||||
state, ok := h.streams[recordID]
|
||||
if ok {
|
||||
|
||||
@@ -41,13 +41,23 @@ type RunResult struct {
|
||||
}
|
||||
|
||||
type LogEvent struct {
|
||||
RecordID uint `json:"recordId"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Completed bool `json:"completed"`
|
||||
Status string `json:"status"`
|
||||
RecordID uint `json:"recordId"`
|
||||
Sequence int64 `json:"sequence"`
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Completed bool `json:"completed"`
|
||||
Status string `json:"status"`
|
||||
Progress *ProgressInfo `json:"progress,omitempty"`
|
||||
}
|
||||
|
||||
// ProgressInfo 描述上传进度,通过 SSE 实时推送给前端。
|
||||
type ProgressInfo struct {
|
||||
BytesSent int64 `json:"bytesSent"`
|
||||
TotalBytes int64 `json:"totalBytes"`
|
||||
Percent float64 `json:"percent"`
|
||||
SpeedBps float64 `json:"speedBps"` // bytes/sec
|
||||
TargetName string `json:"targetName"`
|
||||
}
|
||||
|
||||
type LogWriter interface {
|
||||
|
||||
Reference in New Issue
Block a user