From ad4583fe85ac28bcf659c71e8a63820a908946e9 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Wed, 9 Mar 2022 13:35:52 +0300 Subject: [PATCH] [#1185] neofs-cli: Add progress bar to object put/get Signed-off-by: Evgenii Stratonikov --- cmd/neofs-cli/internal/client/client.go | 10 ++++++ cmd/neofs-cli/modules/object.go | 46 ++++++++++++++++++++++-- go.mod | 1 + go.sum | Bin 95725 -> 96596 bytes 4 files changed, 55 insertions(+), 2 deletions(-) diff --git a/cmd/neofs-cli/internal/client/client.go b/cmd/neofs-cli/internal/client/client.go index ffeb7a033..949074560 100644 --- a/cmd/neofs-cli/internal/client/client.go +++ b/cmd/neofs-cli/internal/client/client.go @@ -464,6 +464,13 @@ type GetObjectPrm struct { objectAddressPrm rawPrm payloadWriterPrm + headerCallback func(*object.Object) +} + +// SetHeaderCallback sets callback which is called on the object after the header is received, +// but before the payload is written. +func (p *GetObjectPrm) SetHeaderCallback(f func(*object.Object)) { + p.headerCallback = f } // GetObjectRes groups resulting values of GetObject operation. @@ -527,6 +534,9 @@ func GetObject(prm GetObjectPrm) (*GetObjectRes, error) { _, err = rdr.Close() return nil, fmt.Errorf("read object header: %w", err) } + if prm.headerCallback != nil { + prm.headerCallback(&hdr) + } sz := hdr.PayloadSize() if sz > maxPayloadBufferSize { diff --git a/cmd/neofs-cli/modules/object.go b/cmd/neofs-cli/modules/object.go index 31e86c6d4..de8121bce 100644 --- a/cmd/neofs-cli/modules/object.go +++ b/cmd/neofs-cli/modules/object.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/cheggaaa/pb" objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object" internalclient "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/client" "github.com/nspcc-dev/neofs-sdk-go/checksum" @@ -123,6 +124,8 @@ const ( const putExpiresOnFlag = "expires-on" +const noProgressFlag = "no-progress" + var putExpiredOn uint64 func initObjectPutCmd() { @@ -141,6 +144,7 @@ func initObjectPutCmd() { flags.Bool("disable-filename", false, "Do not set well-known filename attribute") flags.Bool("disable-timestamp", false, "Do not set well-known timestamp attribute") flags.Uint64VarP(&putExpiredOn, putExpiresOnFlag, "e", 0, "Last epoch in the life of the object") + flags.Bool(noProgressFlag, false, "Do not show progress bar") } func initObjectDeleteCmd() { @@ -169,6 +173,7 @@ func initObjectGetCmd() { flags.String("file", "", "File to write object payload to. Default: stdout.") flags.String("header", "", "File to write header to. Default: stdout.") flags.Bool(rawFlag, false, rawFlagDesc) + flags.Bool(noProgressFlag, false, "Do not show progress bar") } func initObjectSearchCmd() { @@ -446,11 +451,31 @@ func putObject(cmd *cobra.Command, _ []string) { prepareSessionPrmWithOwner(cmd, sessionObjectCtxAddress, key, ownerID, &prm) prepareObjectPrm(cmd, &prm) prm.SetHeader(obj) - prm.SetPayloadReader(f) + + var p *pb.ProgressBar + + noProgress, _ := cmd.Flags().GetBool(noProgressFlag) + if noProgress { + prm.SetPayloadReader(f) + } else { + fi, err := f.Stat() + if err != nil { + cmd.PrintErrf("Failed to get file size, progress bar is disabled: %v\n", err) + prm.SetPayloadReader(f) + } else { + p = pb.New64(fi.Size()) + p.Output = cmd.OutOrStdout() + prm.SetPayloadReader(p.NewProxyReader(f)) + p.Start() + } + } res, err := internalclient.PutObject(prm) exitOnErr(cmd, errf("rpc error: %w", err)) + if p != nil { + p.Finish() + } cmd.Printf("[%s] Object successfully stored\n", filename) cmd.Printf(" ID: %s\n CID: %s\n", res.ID(), cid) } @@ -498,7 +523,21 @@ func getObject(cmd *cobra.Command, _ []string) { prepareSessionPrm(cmd, objAddr, &prm) prepareObjectPrmRaw(cmd, &prm) prm.SetAddress(objAddr) - prm.SetPayloadWriter(out) + + var p *pb.ProgressBar + noProgress, _ := cmd.Flags().GetBool(noProgressFlag) + + if filename == "" || noProgress { + prm.SetPayloadWriter(out) + } else { + p = pb.New64(0) + p.Output = cmd.OutOrStdout() + prm.SetPayloadWriter(p.NewProxyWriter(out)) + prm.SetHeaderCallback(func(o *object.Object) { + p.SetTotal64(int64(o.PayloadSize())) + p.Start() + }) + } res, err := internalclient.GetObject(prm) if err != nil { @@ -510,6 +549,9 @@ func getObject(cmd *cobra.Command, _ []string) { } if filename != "" { + if p != nil { + p.Finish() + } cmd.Printf("[%s] Object successfully saved\n", filename) } diff --git a/go.mod b/go.mod index 4663fa772..0ea2d1e1f 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/nspcc-dev/neofs-node go 1.16 require ( + github.com/cheggaaa/pb v1.0.29 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e github.com/flynn-archive/go-shlex v0.0.0-20150515145356-3f9db97f8568 github.com/golang/snappy v0.0.3 // indirect diff --git a/go.sum b/go.sum index df3745faef431947d4684ea57e4c07a33e4e3a12..4e0e849260b944094ae0ab415fdb0536c7c1ad48 100644 GIT binary patch delta 641 zcmZXR%Z`&^0EIJ)Zj8~5mu-{Ag%aWCR@zC-q)_MuN(&tXy5mxy7cK>Upls$Lnz%Ia z4NSUlY32dk`4+~FTQ|0ii-|tK_nmWce*S2D|JC^Xx^=hoeao`2#BLTi3Q(fk4Df5g z*=RBy`TT~Ek^&BZSKxrjI8caQv49zYv);t+F!|8$riqhaix ztvUrrl9Cuc2V%au~Zx$ z-{ne`IqzxJS`>+qrgo>FZX6Qpy9xp|latpHQfr4hqKTbzLp88Ox$Mb1)z{d87)B#{ zQSlo_F~YU7nY7(9vLCAYuXcPoWn$#R?4)us}v3rI)4(p zILwMCm*5iaGc^$U^}h1?aN^O`x)>9auDgi!o*~OAEzQ|E1BZtBm(vb6uyK>ZXj!h@ zJZKi+bR>0NPOyb1hIMSW+0doTOak@ZpYA+Yh(u