This commit is contained in:
irsl 2026-02-20 07:30:12 -08:00 committed by GitHub
commit 22e9a5a991
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 32 deletions

View File

@ -174,6 +174,13 @@ var (
permitted if they are both set to the same value, to increase backwards permitted if they are both set to the same value, to increase backwards
compatibility with earlier releases that allowed both to be set).`)) compatibility with earlier releases that allowed both to be set).`))
reflection = optionalBoolFlag{val: true} reflection = optionalBoolFlag{val: true}
convertMessage = flags.String("convert-message", "", prettify(`
Turns the tool into an offline converter; the proto representation of
the JSON input will be printed to the standard output.
This parameter should specify the fully qualified name of the protobuf
message definition (e.g. some.service/ReadRequest).
`))
) )
func init() { func init() {
@ -370,27 +377,34 @@ func main() {
args := flags.Args() args := flags.Args()
if len(args) == 0 { convertJson := *convertMessage != ""
fail(nil, "Too few arguments.")
}
var target string
if args[0] != "list" && args[0] != "describe" {
target = args[0]
args = args[1:]
}
if len(args) == 0 { var target string
fail(nil, "Too few arguments.")
}
var list, describe, invoke bool var list, describe, invoke bool
if args[0] == "list" { if len(args) != 0 {
list = true if convertJson {
args = args[1:] fail(nil, "Target service should be omitted for offline conversions.")
} else if args[0] == "describe" { }
describe = true
args = args[1:] if args[0] != "list" && args[0] != "describe" {
target = args[0]
args = args[1:]
}
if args[0] == "list" {
list = true
args = args[1:]
} else if args[0] == "describe" {
describe = true
args = args[1:]
} else {
invoke = true
}
} else { } else {
invoke = true if !convertJson {
fail(nil, "Too few arguments.")
}
} }
verbosityLevel := 0 verbosityLevel := 0
@ -417,7 +431,7 @@ func main() {
symbol = args[0] symbol = args[0]
args = args[1:] args = args[1:]
} else { } else {
if *data != "" { if *data != "" && !convertJson {
warn("The -d argument is not used with 'list' or 'describe' verb.") warn("The -d argument is not used with 'list' or 'describe' verb.")
} }
if len(rpcHeaders) > 0 { if len(rpcHeaders) > 0 {
@ -785,9 +799,10 @@ func main() {
} else { } else {
// Invoke an RPC // Invoke an RPC
if cc == nil { if cc == nil && !convertJson {
cc = dial() cc = dial()
} }
var in io.Reader var in io.Reader
if *data == "@" { if *data == "@" {
in = os.Stdin in = os.Stdin
@ -808,6 +823,16 @@ func main() {
if err != nil { if err != nil {
fail(err, "Failed to construct request parser and formatter for %q", *format) fail(err, "Failed to construct request parser and formatter for %q", *format)
} }
if convertJson {
proto, err:= grpcurl.ConvertMessage(descSource, *convertMessage, rf.Next)
if err != nil {
fail(err, "Error converting message %q", *convertMessage)
}
os.Stdout.Write(proto)
os.Exit(0)
}
h := &grpcurl.DefaultEventHandler{ h := &grpcurl.DefaultEventHandler{
Out: os.Stdout, Out: os.Stdout,
Formatter: formatter, Formatter: formatter,

View File

@ -119,18 +119,7 @@ func InvokeRPC(ctx context.Context, source DescriptorSource, ch grpcdynamic.Chan
handler.OnResolveMethod(mtd) handler.OnResolveMethod(mtd)
// we also download any applicable extensions so we can provide full support for parsing user-provided data req, msgFactory, err:= getExtensions(source, mtd.GetInputType())
var ext dynamic.ExtensionRegistry
alreadyFetched := map[string]bool{}
if err = fetchAllExtensions(source, &ext, mtd.GetInputType(), alreadyFetched); err != nil {
return fmt.Errorf("error resolving server extensions for message %s: %v", mtd.GetInputType().GetFullyQualifiedName(), err)
}
if err = fetchAllExtensions(source, &ext, mtd.GetOutputType(), alreadyFetched); err != nil {
return fmt.Errorf("error resolving server extensions for message %s: %v", mtd.GetOutputType().GetFullyQualifiedName(), err)
}
msgFactory := dynamic.NewMessageFactoryWithExtensionRegistry(&ext)
req := msgFactory.NewMessage(mtd.GetInputType())
handler.OnSendHeaders(md) handler.OnSendHeaders(md)
ctx = metadata.NewOutgoingContext(ctx, md) ctx = metadata.NewOutgoingContext(ctx, md)
@ -407,3 +396,48 @@ func parseSymbol(svcAndMethod string) (string, string) {
} }
return svcAndMethod[:pos], svcAndMethod[pos+1:] return svcAndMethod[:pos], svcAndMethod[pos+1:]
} }
func ConvertMessage(source DescriptorSource, messageFullName string, requestData RequestSupplier) ([]byte, error) {
dsc, err := source.FindSymbol(messageFullName)
if err != nil {
return nil, err
}
md, ok := dsc.(*desc.MessageDescriptor)
if ! ok {
return nil, fmt.Errorf("%q should point to a message descriptor instead of %d:", messageFullName, md)
}
req, _, err:= getExtensions(source, md)
if err != nil {
return nil, err
}
err = requestData(req)
if err != nil {
return nil, err
}
re, err:= proto.Marshal(req)
if err != nil {
return nil, err
}
return re, nil
}
func getExtensions(source DescriptorSource, md *desc.MessageDescriptor) (req proto.Message, msgFactory *dynamic.MessageFactory, err error) {
// we also download any applicable extensions so we can provide full support for parsing user-provided data
var ext dynamic.ExtensionRegistry
alreadyFetched := map[string]bool{}
if err = fetchAllExtensions(source, &ext, md, alreadyFetched); err != nil {
return nil, nil, fmt.Errorf("error resolving server extensions for message %s: %v", md.GetFullyQualifiedName(), err)
}
if err = fetchAllExtensions(source, &ext, md, alreadyFetched); err != nil {
return nil, nil, fmt.Errorf("error resolving server extensions for message %s: %v", md.GetFullyQualifiedName(), err)
}
msgFactory = dynamic.NewMessageFactoryWithExtensionRegistry(&ext)
req = msgFactory.NewMessage(md)
return req, msgFactory, nil
}