Skip to content

Commit

Permalink
Add support for --bytes-as-base64 (#611)
Browse files Browse the repository at this point in the history
This allows entering bytes as a base64-encoded string, using the standard
encoding.

Co-authored-by: ktr <ktr@syfm.me>
  • Loading branch information
flokli and ktr0731 committed Feb 5, 2023
1 parent f75862c commit 2856945
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 8 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ data (TYPE_BYTES) => \u65e5\u672c\u8a9e
}
```

Or add the flag `--bytes-as-base64` to pass bytes as a base64-encoded string
```
> call UnaryBytes --bytes-as-base64
data (TYPE_BYTES) => SGVsbG8gV29ybGQh
```

Or add the flag `--bytes-from-file` to read bytes from the provided relative path
```
> call UnaryBytes --bytes-from-file
Expand Down
3 changes: 2 additions & 1 deletion e2e/testdata/fixtures/teste2e_repl-call_--help.golden
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ usage: call <method name>

Options:
--add-repeated-manually prompt asks whether to add a value if it encountered to a repeated field
--bytes-from-file interpret TYPE_BYTES input as a relative path to a file
--bytes-as-base64 interpret TYPE_BYTES input as base64-encoded string (mutually exclusive with --bytes-from-file)
--bytes-from-file interpret TYPE_BYTES input as a relative path to a file (mutually exclusive with --bytes-as-base64)
--dig-manually prompt asks whether to dig down if it encountered to a message field
--emit-defaults render fields with default values
--enrich enrich response output includes header, message, trailer and status
Expand Down
2 changes: 2 additions & 0 deletions fill/filler.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ type Filler interface {
type InteractiveFillerOpts struct {
// DigManually is true, Fill asks whether to dig down if it encountered to a message field.
DigManually,
// BytesAsBase64 is true, Fill will interpret input as base64-encoded string
BytesAsBase64,
// BytesFromFile is true, Fill will read the contents of the file from the provided relative path.
BytesFromFile,
// AddRepeatedManually is true, Fill asks whether to add a repeated field value
Expand Down
8 changes: 7 additions & 1 deletion fill/proto/interactive_filler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package proto

import (
"encoding/base64"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -201,7 +202,12 @@ func (r *resolver) resolveField(f *desc.FieldDescriptor) error {
// So, we need to call strconv.Unquote to interpret backslashes as an escape sequence.
case descriptorpb.FieldDescriptorProto_TYPE_BYTES:
converter = func(v string) (interface{}, error) {
if r.opts.BytesFromFile {
if r.opts.BytesAsBase64 {
b, err := base64.StdEncoding.DecodeString(v)
if err == nil {
return b, nil
}
} else if r.opts.BytesFromFile {
b, err := ioutil.ReadFile(v)
if err == nil {
return b, nil
Expand Down
13 changes: 10 additions & 3 deletions repl/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,16 @@ func (c *showCommand) Run(w io.Writer, args []string) error {
}

type callCommand struct {
enrich, digManually, bytesFromFile, emitDefaults, repeatCall, addRepeatedManually bool
enrich, digManually, bytesAsBase64, bytesFromFile, emitDefaults, repeatCall, addRepeatedManually bool
}

func (c *callCommand) FlagSet() (*pflag.FlagSet, bool) {
fs := pflag.NewFlagSet("call", pflag.ContinueOnError)
fs.Usage = func() {} // Disable help output when an error occurred.
fs.BoolVar(&c.enrich, "enrich", false, "enrich response output includes header, message, trailer and status")
fs.BoolVar(&c.digManually, "dig-manually", false, "prompt asks whether to dig down if it encountered to a message field")
fs.BoolVar(&c.bytesFromFile, "bytes-from-file", false, "interpret TYPE_BYTES input as a relative path to a file")
fs.BoolVar(&c.bytesAsBase64, "bytes-as-base64", false, "interpret TYPE_BYTES input as base64-encoded string (mutually exclusive with --bytes-from-file)")
fs.BoolVar(&c.bytesFromFile, "bytes-from-file", false, "interpret TYPE_BYTES input as a relative path to a file (mutually exclusive with --bytes-as-base64)")
fs.BoolVar(&c.emitDefaults, "emit-defaults", false, "render fields with default values")
fs.BoolVarP(&c.repeatCall, "repeat", "r", false, "repeat previous unary or server streaming request (if exists)")
fs.BoolVar(&c.addRepeatedManually, "add-repeated-manually", false, "prompt asks whether to add a value if it encountered to a repeated field")
Expand Down Expand Up @@ -199,9 +200,15 @@ func (c *callCommand) Run(w io.Writer, args []string) error {
},
)

// Ensure bytesAsBase64 and bytesFromFile are not both set
// pflag doesn't suppport mutually exclusive flags (https://github.com/spf13/pflag/issues/270)
if c.bytesAsBase64 && c.bytesFromFile {
return errors.New("only one of --bytes-as-base64 or --bytes-from-file can be specified")
}

// here we create the request context
// we also add the call command flags here
err := usecase.CallRPCInteractively(context.Background(), w, args[0], c.digManually, c.bytesFromFile, c.repeatCall, c.addRepeatedManually)
err := usecase.CallRPCInteractively(context.Background(), w, args[0], c.digManually, c.bytesAsBase64, c.bytesFromFile, c.repeatCall, c.addRepeatedManually)
if errors.Is(err, io.EOF) {
return errors.New("inputting canceled")
}
Expand Down
7 changes: 4 additions & 3 deletions usecase/call_rpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,15 +478,16 @@ func (f *interactiveFiller) Fill(v interface{}) error {
return f.fillFunc(v)
}

func CallRPCInteractively(ctx context.Context, w io.Writer, rpcName string, digManually, bytesFromFile, rerunPrevious, addRepeatedManually bool) error {
return dm.CallRPCInteractively(ctx, w, rpcName, digManually, bytesFromFile, rerunPrevious, addRepeatedManually)
func CallRPCInteractively(ctx context.Context, w io.Writer, rpcName string, digManually, bytesAsBase64, bytesFromFile, rerunPrevious, addRepeatedManually bool) error {
return dm.CallRPCInteractively(ctx, w, rpcName, digManually, bytesAsBase64, bytesFromFile, rerunPrevious, addRepeatedManually)
}

func (m *dependencyManager) CallRPCInteractively(ctx context.Context, w io.Writer, rpcName string, digManually, bytesFromFile, rerunPrevious, addRepeatedManually bool) error {
func (m *dependencyManager) CallRPCInteractively(ctx context.Context, w io.Writer, rpcName string, digManually, bytesAsBase64, bytesFromFile, rerunPrevious, addRepeatedManually bool) error {
return m.CallRPC(ctx, w, rpcName, rerunPrevious, &interactiveFiller{
fillFunc: func(v interface{}) error {
return m.interactiveFiller.Fill(v, fill.InteractiveFillerOpts{
DigManually: digManually,
BytesAsBase64: bytesAsBase64,
BytesFromFile: bytesFromFile,
AddRepeatedManually: addRepeatedManually,
})
Expand Down

0 comments on commit 2856945

Please sign in to comment.