111 lines
3.2 KiB
Go
111 lines
3.2 KiB
Go
package cmd
|
||
|
||
import (
|
||
"fmt"
|
||
"io"
|
||
"os"
|
||
"path/filepath"
|
||
|
||
cdssdk "gitlink.org.cn/cloudream/common/sdks/storage"
|
||
|
||
"gitlink.org.cn/cloudream/common/pkgs/distlock"
|
||
stgglb "gitlink.org.cn/cloudream/storage/common/globals"
|
||
"gitlink.org.cn/cloudream/storage/common/pkgs/iterator"
|
||
coormq "gitlink.org.cn/cloudream/storage/common/pkgs/mq/coordinator"
|
||
)
|
||
|
||
// 下载包结构体,存储用户ID、包ID和输出路径。
|
||
type DownloadPackage struct {
|
||
userID cdssdk.UserID
|
||
packageID cdssdk.PackageID
|
||
outputPath string
|
||
}
|
||
|
||
// 下载包执行上下文,包含分布式锁服务。
|
||
type DownloadPackageContext struct {
|
||
Distlock *distlock.Service
|
||
}
|
||
|
||
// 新建一个下载包实例。
|
||
// userID: 用户标识。
|
||
// packageID: 包标识。
|
||
// outputPath: 输出路径。
|
||
func NewDownloadPackage(userID cdssdk.UserID, packageID cdssdk.PackageID, outputPath string) *DownloadPackage {
|
||
return &DownloadPackage{
|
||
userID: userID,
|
||
packageID: packageID,
|
||
outputPath: outputPath,
|
||
}
|
||
}
|
||
|
||
// 执行下载包操作。
|
||
// ctx: 下载包执行上下文。
|
||
// 返回值: 执行过程中可能出现的错误。
|
||
func (t *DownloadPackage) Execute(ctx *DownloadPackageContext) error {
|
||
// 获取协调器MQ客户端
|
||
coorCli, err := stgglb.CoordinatorMQPool.Acquire()
|
||
if err != nil {
|
||
return fmt.Errorf("new coordinator client: %w", err)
|
||
}
|
||
defer stgglb.CoordinatorMQPool.Release(coorCli) // 确保释放客户端资源
|
||
|
||
// 获取包内对象详情
|
||
getObjectDetails, err := coorCli.GetPackageObjectDetails(coormq.NewGetPackageObjectDetails(t.packageID))
|
||
if err != nil {
|
||
return fmt.Errorf("getting package object details: %w", err)
|
||
}
|
||
|
||
// 创建下载对象迭代器
|
||
objIter := iterator.NewDownloadObjectIterator(getObjectDetails.Objects, &iterator.DownloadContext{
|
||
Distlock: ctx.Distlock,
|
||
})
|
||
defer objIter.Close() // 确保迭代器关闭
|
||
|
||
// 写入对象数据到本地
|
||
return t.writeObjects(objIter)
|
||
}
|
||
|
||
// 将下载的对象写入本地文件系统。
|
||
// objIter: 下载中的对象迭代器。
|
||
// 返回值: 写入过程中可能出现的错误。
|
||
func (t *DownloadPackage) writeObjects(objIter iterator.DownloadingObjectIterator) error {
|
||
for {
|
||
objInfo, err := objIter.MoveNext()
|
||
if err == iterator.ErrNoMoreItem {
|
||
break // 没有更多对象时结束循环
|
||
}
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
err = func() error {
|
||
defer objInfo.File.Close() // 确保文件资源被释放
|
||
|
||
fullPath := filepath.Join(t.outputPath, objInfo.Object.Path) // 计算文件完整路径
|
||
|
||
dirPath := filepath.Dir(fullPath) // 获取文件所在目录路径
|
||
if err := os.MkdirAll(dirPath, 0755); err != nil { // 创建目录,如果不存在
|
||
return fmt.Errorf("creating object dir: %w", err)
|
||
}
|
||
|
||
outputFile, err := os.Create(fullPath) // 创建本地文件
|
||
if err != nil {
|
||
return fmt.Errorf("creating object file: %w", err)
|
||
}
|
||
defer outputFile.Close() // 确保文件关闭
|
||
|
||
_, err = io.Copy(outputFile, objInfo.File) // 将对象数据写入本地文件
|
||
if err != nil {
|
||
return fmt.Errorf("copy object data to local file failed, err: %w", err)
|
||
}
|
||
|
||
return nil
|
||
}()
|
||
if err != nil {
|
||
return err // 如果写入过程中出现错误,返回该错误
|
||
}
|
||
}
|
||
|
||
return nil // 没有错误,返回nil
|
||
}
|