package geto import ( "fmt" "io" "os" "path/filepath" "strconv" "time" "github.com/inhies/go-bytesize" "github.com/spf13/cobra" cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" ) func init() { var opt option c := &cobra.Command{ Use: "geto /: ", Short: "download object to local disk", Args: cobra.ExactArgs(2), RunE: func(c *cobra.Command, args []string) error { ctx := cmd.GetCmdCtx(c) return geto(c, ctx, opt, args) }, } c.Flags().BoolVar(&opt.UseID, "id", false, "treat first argument as object id") c.Flags().Int64Var(&opt.Offset, "offset", 0, "offset of object to download") c.Flags().Int64Var(&opt.Length, "length", 0, "length of object to download") c.Flags().Int64Var(&opt.Seek, "seek", 0, "seek position when save to local file, if set, will not truncate local file") c.Flags().StringVarP(&opt.Output, "output", "o", "", "output file name") cmd.RootCmd.AddCommand(c) } type option struct { UseID bool Offset int64 Length int64 Seek int64 Output string } func geto(c *cobra.Command, ctx *cmd.CommandContext, opt option, args []string) error { var obj clitypes.Object if opt.UseID { id, err := strconv.ParseInt(args[0], 10, 64) if err != nil { return fmt.Errorf("invalid object id: %v", err) } resp, err := ctx.Client.Object().ListByIDs(cliapi.ObjectListByIDs{ ObjectIDs: []clitypes.ObjectID{clitypes.ObjectID(id)}, }) if err != nil { return fmt.Errorf("list objects by ids: %v", err) } if resp.Objects[0] == nil { return fmt.Errorf("object not found") } obj = *resp.Objects[0] } else { bkt, pkg, objPath, ok := cmd.SplitObjectPath(args[0]) if !ok { return fmt.Errorf("invalid object path") } pkgResp, err := ctx.Client.Package().GetByFullName(cliapi.PackageGetByFullName{ BucketName: bkt, PackageName: pkg, }) if err != nil { return fmt.Errorf("get package by name: %v", err) } objResp, err := ctx.Client.Object().ListByPath(cliapi.ObjectListByPath{ PackageID: pkgResp.Package.PackageID, Path: objPath, }) if err != nil { return fmt.Errorf("list objects by path: %v", err) } if len(objResp.Objects) != 1 { return fmt.Errorf("object not found") } obj = objResp.Objects[0] } filePath := args[1] if opt.Output != "" { filePath = filepath.Join(filePath, opt.Output) } else { filePath = filepath.Join(filePath, clitypes.BaseName(obj.Path)) } flag := os.O_CREATE | os.O_WRONLY if !c.Flags().Changed("seek") { flag |= os.O_TRUNC } file, err := os.OpenFile(filePath, flag, 0644) if err != nil { return fmt.Errorf("open file: %v", err) } defer file.Close() if opt.Seek != 0 { if _, err := file.Seek(opt.Seek, 0); err != nil { return fmt.Errorf("seek file: %v", err) } } fmt.Printf("%v\n", filePath) var len *int64 if c.Flags().Changed("length") { len = &opt.Length } resp, err := ctx.Client.Object().Download(cliapi.ObjectDownload{ ObjectID: obj.ObjectID, Offset: opt.Offset, Length: len, }) if err != nil { return fmt.Errorf("download object: %v", err) } startTime := time.Now() n, err := io.Copy(file, resp.File) if err != nil { return fmt.Errorf("copy object to file: %v", err) } dt := time.Since(startTime) fmt.Printf("size: %v, time: %v, speed: %v/s\n", bytesize.ByteSize(n), dt, bytesize.ByteSize(int64(float64(n)/dt.Seconds()))) return nil }