package cmdline import ( "fmt" "io" "os" "path/filepath" "strings" "time" "github.com/jedib0t/go-pretty/v6/table" "github.com/juju/ratelimit" "gitlink.org.cn/cloudream/client/internal/task" myio "gitlink.org.cn/cloudream/common/utils/io" ) func ObjectListBucketObjects(ctx CommandContext, bucketID int) error { userID := 0 objects, err := ctx.Cmdline.Svc.BucketSvc().GetBucketObjects(userID, bucketID) if err != nil { return err } fmt.Printf("Find %d objects in bucket %d for user %d:\n", len(objects), bucketID, userID) tb := table.NewWriter() tb.AppendHeader(table.Row{"ID", "Name", "Size", "BucketID", "State", "Redundancy"}) for _, obj := range objects { tb.AppendRow(table.Row{obj.ObjectID, obj.Name, obj.BucketID, obj.State, obj.FileSize, obj.Redundancy}) } fmt.Print(tb.Render()) return nil } func ObjectDownloadObject(ctx CommandContext, localFilePath string, objectID int) error { // 创建本地文件 curExecPath, err := os.Executable() if err != nil { return fmt.Errorf("get executable directory failed, err: %w", err) } outputFilePath := filepath.Join(filepath.Dir(curExecPath), localFilePath) outputFileDir := filepath.Dir(outputFilePath) err = os.MkdirAll(outputFileDir, os.ModePerm) if err != nil { return fmt.Errorf("create output file directory %s failed, err: %w", outputFileDir, err) } outputFile, err := os.Create(outputFilePath) if err != nil { return fmt.Errorf("create output file %s failed, err: %w", outputFilePath, err) } defer outputFile.Close() // 下载文件 reader, err := ctx.Cmdline.Svc.ObjectSvc().DownloadObject(0, objectID) if err != nil { return fmt.Errorf("download object failed, err: %w", err) } defer reader.Close() bkt := ratelimit.NewBucketWithRate(10*1024, 10*1024) _, err = io.Copy(outputFile, ratelimit.Reader(reader, bkt)) if err != nil { // TODO 写入到文件失败,是否要考虑删除这个不完整的文件? return fmt.Errorf("copy object data to local file failed, err: %w", err) } return nil } func ObjectUploadRepObject(ctx CommandContext, localFilePath string, bucketID int, objectName string, repCount int) error { file, err := os.Open(localFilePath) if err != nil { return fmt.Errorf("open file %s failed, err: %w", localFilePath, err) } defer file.Close() fileInfo, err := file.Stat() if err != nil { return fmt.Errorf("get file %s state failed, err: %w", localFilePath, err) } fileSize := fileInfo.Size() // TODO 测试用 bkt := ratelimit.NewBucketWithRate(10*1024, 10*1024) uploadObject := task.UploadObject{ ObjectName: objectName, File: myio.WithCloser(ratelimit.Reader(file, bkt), func(reader io.Reader) error { return file.Close() }), FileSize: fileSize, } uploadObjects := []task.UploadObject{uploadObject} taskID, err := ctx.Cmdline.Svc.ObjectSvc().StartUploadingRepObjects(0, bucketID, uploadObjects, repCount) if err != nil { return fmt.Errorf("upload file data failed, err: %w", err) } for { complete, UploadRepResults, err := ctx.Cmdline.Svc.ObjectSvc().WaitUploadingRepObjects(taskID, time.Second*5) if complete { if err != nil { return fmt.Errorf("uploading rep object: %w", err) } fmt.Print(UploadRepResults[0].ResultFileHash) return nil } if err != nil { return fmt.Errorf("wait uploading: %w", err) } } } func ObjectUploadRepObjectDir(ctx CommandContext, localDirPath string, bucketID int, repCount int) error { var uploadFiles []task.UploadObject var uploadFile task.UploadObject err := filepath.Walk(localDirPath, func(fname string, fi os.FileInfo, err error) error { if !fi.IsDir() { file, err := os.Open(fname) if err != nil { return fmt.Errorf("open file %s failed, err: %w", fname, err) } // TODO 测试用 bkt := ratelimit.NewBucketWithRate(10*1024, 10*1024) uploadFile = task.UploadObject{ ObjectName: strings.Replace(fname, "\\", "/", -1), File: myio.WithCloser(ratelimit.Reader(file, bkt), func(reader io.Reader) error { return file.Close() }), FileSize: fi.Size(), } uploadFiles = append(uploadFiles, uploadFile) } return nil }) if err != nil { return fmt.Errorf("open directory %s failed, err: %w", localDirPath, err) } // 遍历 关闭文件流 for _, uploadFile := range uploadFiles { defer uploadFile.File.Close() } taskID, err := ctx.Cmdline.Svc.ObjectSvc().StartUploadingRepObjects(0, bucketID, uploadFiles, repCount) if err != nil { return fmt.Errorf("upload file data failed, err: %w", err) } for { complete, UploadRepResults, err := ctx.Cmdline.Svc.ObjectSvc().WaitUploadingRepObjects(taskID, time.Second*5) if complete { tb := table.NewWriter() tb.AppendHeader(table.Row{"ObjectID", "FileHash"}) for _, uploadRepResult := range UploadRepResults { tb.AppendRow(table.Row{uploadRepResult.ObjectID, uploadRepResult.ResultFileHash}) } fmt.Print(tb.Render()) if err != nil { return fmt.Errorf("uploading rep object: %w", err) } return nil } if err != nil { return fmt.Errorf("wait uploading: %w", err) } } } func ObjectEcWrite(ctx CommandContext, localFilePath string, bucketID int, objectName string, ecName string) error { // TODO panic("not implement yet") } func ObjectUpdateRepObject(ctx CommandContext, objectID int, filePath string) error { userID := 0 file, err := os.Open(filePath) if err != nil { return fmt.Errorf("open file %s failed, err: %w", filePath, err) } defer file.Close() fileInfo, err := file.Stat() if err != nil { return fmt.Errorf("get file %s state failed, err: %w", filePath, err) } fileSize := fileInfo.Size() // TODO 测试用 bkt := ratelimit.NewBucketWithRate(10*1024, 10*1024) taskID, err := ctx.Cmdline.Svc.ObjectSvc().StartUpdatingRepObject(userID, objectID, myio.WithCloser(ratelimit.Reader(file, bkt), func(reader io.Reader) error { return file.Close() }), fileSize) if err != nil { return fmt.Errorf("update object %d failed, err: %w", objectID, err) } for { complete, err := ctx.Cmdline.Svc.ObjectSvc().WaitUpdatingRepObject(taskID, time.Second*5) if complete { if err != nil { return fmt.Errorf("updating rep object: %w", err) } return nil } if err != nil { return fmt.Errorf("wait updating: %w", err) } } } func ObjectDeleteObject(ctx CommandContext, objectID int) error { userID := 0 err := ctx.Cmdline.Svc.ObjectSvc().DeleteObject(userID, objectID) if err != nil { return fmt.Errorf("delete object %d failed, err: %w", objectID, err) } return nil } func init() { commands.MustAdd(ObjectListBucketObjects, "object", "ls") commands.MustAdd(ObjectUploadRepObject, "object", "new", "rep") commands.MustAdd(ObjectUploadRepObjectDir, "object", "new", "dir") commands.MustAdd(ObjectDownloadObject, "object", "get") commands.MustAdd(ObjectUpdateRepObject, "object", "update", "rep") commands.MustAdd(ObjectDeleteObject, "object", "delete") }