共引入 21个commits,主要涉及以下模块:
Commits:
4c33ffa4feat(link): add link refresh capability for expired download linksf38fe180fix(stream): 修复链接过期检测逻辑,避免将上下文取消视为链接过期7cf362c6fix(stream): 更新过期链接检查逻辑,支持所有4xx客户端错误03fbaf1crefactor(stream): 移除过时的链接刷新逻辑,添加自愈读取器以处理0字节读取
核心代码:
// 新增常量
MAX_LINK_REFRESH_COUNT = 50 // 链接最大刷新次数
MAX_RANGE_READ_RETRY_COUNT = 5 // RangeRead重试次数(从3提升到5)
// 新增函数
IsLinkExpiredError(err error) bool // 判断是否为链接过期错误
// 新增结构
RefreshableRangeReader struct {
link *model.Link
size int64
innerReader model.RangeReaderIF
mu sync.Mutex
refreshCount int // 防止无限循环
}
selfHealingReadCloser struct {
// 检测0字节读取,自动刷新链接
}功能说明:
- 链接过期检测: 识别多种云盘的过期错误(expired, token expired, access denied, 4xx状态码等)
- 自动刷新: 检测到过期时自动调用Refresher获取新链接,最多刷新50次
- 自愈机制: 处理某些云盘返回200但内容为空的情况(0字节读取检测)
- 并发安全: 使用sync.Mutex保护共享状态
- Context隔离: 刷新时使用WithoutCancel避免用户取消操作影响刷新
潜在风险:
- ✅ Context.WithoutCancel需要Go 1.21+
- ✅ 并发场景下的锁竞争
- ✅ refreshCount可能在某些场景下不递增导致无限循环
Commit: ce0da112 fix(copy_move): 将预创建子目录的深度从2级调整为1级
核心代码:
func (t *FileTransferTask) preCreateDirectoryTree(objs []model.Obj, dstBasePath string, maxDepth int) error {
// 第一轮:创建直接子目录
for _, obj := range objs {
if obj.IsDir() {
subdirPath := stdpath.Join(dstBasePath, obj.GetName())
op.MakeDir(t.Ctx(), t.DstStorage, subdirPath)
subdirs = append(subdirs, obj)
}
}
// 停止递归条件
if maxDepth <= 0 {
return nil
}
// 第二轮:递归创建嵌套目录
for _, subdir := range subdirs {
subObjs := op.List(...)
preCreateDirectoryTree(subObjs, subdirDstPath, maxDepth-1)
}
}功能说明:
- 深度控制: 默认maxDepth=1,只预创建2级目录(当前+子级)
- 防止深度递归: 避免在大型项目中递归过深导致栈溢出或性能问题
- 错误容忍: MakeDir失败时继续处理其他目录
- Context感知: 每次循环检查ctx.Err()支持取消操作
潜在风险:
- ✅ op.MakeDir和op.List调用需要存储初始化
- ✅ 大量目录时的性能问题
- ✅ Context取消时的资源清理
Commits:
b9dafa65feat(network): 增加对慢速网络的支持,调整超时和重试机制bce47884fix(driver): 增加夸克分片大小调整逻辑,支持重试机制0b8471f6feat(quark_open): 添加速率限制和重试逻辑
功能说明:
- 提升RangeRead重试次数: 3 → 5
- 调整网络超时参数
- 添加分片上传重试逻辑
Commits:
da2812c0fix(google_drive): 更新Put方法以支持可重复读取流和不可重复读取流的MD5校验5a6bad90feat(google_drive): 添加文件夹创建的锁机制和重试逻辑a54b2388feat(google_drive): 添加处理重复文件名的功能9ef22ec9fix(driver): fix file copy failure to 123pan due to incorrect etag0ead87effix(alias): update storage retrieval method in listRoot function311f6246fix: 修复500 panic和NaN问题
- 构建成功,无语法错误
- 依赖版本无冲突
- 新增函数不破坏现有接口
- RefreshableRangeReader实现model.RangeReaderIF接口
- 向后兼容旧代码
需要验证的场景:
- 并发安全: RefreshableRangeReader的并发读取
- 资源泄漏: Context取消时goroutine是否正确退出
- 边界条件:
- refreshCount达到50次的行为
- 0字节读取检测的准确性
- maxDepth=0时的目录创建
- 错误处理:
- nil Refresher时的处理
- 链接刷新失败时的回退机制
- 性能:
- 大文件下载时的刷新开销
- 深层目录结构的预创建性能
-
IsLinkExpiredError准确性
- 各种云盘的过期错误格式
- Context取消不应判断为过期
- HTTP 4xx/5xx的区分
-
RefreshableRangeReader可靠性
- 正常读取流程
- 自动刷新触发和成功
- 达到最大刷新次数
- 并发读取安全性
- Context取消的正确处理
-
selfHealingReadCloser
- 0字节读取检测
- 刷新重试机制
- 资源正确关闭
- preCreateDirectoryTree
- 深度控制正确性(0, 1, 2级)
- 大量目录的性能
- Context取消的响应
- 错误容忍性
原因:
- ✅ 新功能设计合理,有明确的边界和错误处理
⚠️ 并发场景需要充分测试⚠️ 链接刷新逻辑复杂,需要验证各种边界情况⚠️ 依赖op包的函数需要正确的初始化
前置条件:
- 完成全面的单元测试(见下方测试代码)
- 验证并发安全性
- 确认Context取消不会导致资源泄漏
- 性能测试通过(大文件、深层目录)
建议测试命令:
# 单元测试
go test ./internal/stream ./internal/fs -v -count=1 -race
# 压力测试
go test ./internal/stream -run Stress -v -count=10
# 完整测试套件
go test ./... -short -count=1