Could we add some examples for each module?
Hi, I am glad to find this powerful pkg. However, their is no tutorial or example to show how to use it. Could we add some tutorials or examples for each module?
BTW, my usecase is as follows, we deploy client's gRPC servers in our cluster. client will send request to our proxy saying" I want ADD 1, 2 ", our proxy will parse the request and act like the real gRPC client, sending request to multiple gRPC server, return the fastest response to client.
ClientA ----> Proxy -- --> Server A & B
+1 for examples
I can suggest some example:
- Parse .proto file
- Create dynamic message
- Send message to GRPC
- marshal and unmarshal binary data
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoparse"
"github.com/jhump/protoreflect/dynamic"
"github.com/jhump/protoreflect/dynamic/grpcdynamic"
"google.golang.org/grpc"
)
const GRPC_SERVER = "127.0.0.1:10000"
// proto file https://github.com/grpc/grpc-go/blob/master/examples/route_guide/routeguide/route_guide.proto
func loadProto() *desc.FileDescriptor {
parser := protoparse.Parser{}
parser.ImportPaths = []string{
os.Getenv("HOME") + "/go/src/google.golang.org/grpc/examples/route_guide/routeguide",
}
descs, err := parser.ParseFiles("route_guide.proto")
if err != nil {
panic(err)
}
log.Printf("Loaded descriptor content:")
for _, desc := range descs {
for _, service := range desc.GetServices() {
log.Printf("> service %s", service.GetFullyQualifiedName())
for _, method := range service.GetMethods() {
log.Printf(" * method %s (%s) %s",
method.GetFullyQualifiedName(),
method.GetInputType().GetFullyQualifiedName(),
method.GetOutputType().GetFullyQualifiedName(),
)
}
}
for _, msg := range desc.GetMessageTypes() {
log.Printf("- message %s", msg.GetFullyQualifiedName())
}
}
return descs[0]
}
// Dynamically create message using parsed proto descriptor
func composeMessage(descriptor *desc.FileDescriptor) *dynamic.Message {
messageDesc := descriptor.FindMessage("routeguide.Point")
if messageDesc == nil {
panic(fmt.Errorf("Can't find message"))
}
message := dynamic.NewMessage(messageDesc)
/*
message Point {
int32 latitude = 1;
int32 longitude = 2;
}
*/
message.SetFieldByName("latitude", int32(12345678))
message.SetFieldByName("longitude", int32(87654321))
return message
}
// Require GRPC server running
// cd ~/go/src/google.golang.org/grpc/examples/route_guide
// go run server/server.go
//
func callGrpc(descriptor *desc.FileDescriptor) {
serviceName := "routeguide.RouteGuide"
methodName := "GetFeature"
log.Printf("Looking for serviceName %s methodName %s", serviceName, methodName)
// FIND DYNAMIC DESCRIPTORS FOR SERVICE AND METHOD
serviceDesc := descriptor.FindService(serviceName)
if serviceDesc == nil {
panic(fmt.Errorf("Can't find service %s", serviceName))
}
methodDesc := serviceDesc.FindMethodByName(methodName)
if methodDesc == nil {
panic(fmt.Errorf("Can't find method %s in service %s", methodName, serviceName))
}
// CREATE GRPC CLIENT
log.Printf("Creating GRPC client for %s", GRPC_SERVER)
conn, err := grpc.Dial(GRPC_SERVER, grpc.WithInsecure())
if err != nil {
panic(err)
}
defer conn.Close()
grpcClient := grpcdynamic.NewStub(conn)
// SENDING MESSAGE
message := composeMessage(descriptor)
response, err := grpcClient.InvokeRpc(context.TODO(), methodDesc, message)
if err != nil {
panic(err)
}
log.Printf("response %#v", response)
json, err := response.(*dynamic.Message).MarshalJSON()
log.Printf("response json %s %v", json, err)
}
// Convert dynamic.Message to binary string (proto encoded) and parse proto string to dynamic.Message
func toAndFromBin(descriptor *desc.FileDescriptor) {
message := composeMessage(descriptor)
data, err := message.Marshal()
log.Printf("Binary data %v %v", data, err)
parsedDessage := dynamic.NewMessage(descriptor.FindMessage("routeguide.Point"))
err = parsedDessage.Unmarshal(data)
log.Printf("Parsed from binary %v %v", message, err)
}
func main() {
descriptor := loadProto()
fmt.Println("")
log.Printf("Creating message dynamicly of type routeguide.Point")
fmt.Println("")
point := composeMessage(descriptor)
json, err := point.MarshalJSON()
log.Printf("message routeguide.Point as json: %s %v", json, err)
fmt.Println("")
log.Printf("Calling grpc endpoint routeguide.Point")
fmt.Println("")
callGrpc(descriptor)
fmt.Println("")
log.Printf("Work with binary strings")
fmt.Println("")
toAndFromBin(descriptor)
}
@Paxa Thanks a lot. Your example explains pretty well.
@Paxa How do I read the incoming metadata after invokeRPC call i.e., response, err := grpcClient.InvokeRpc(context.TODO(), methodDesc, message)
@LSTPro, that's really a grpc-go question, not specific to this repo. https://github.com/grpc/grpc-go/blob/master/Documentation/grpc-metadata.md#receiving-metadata
@jhump The link provided was helpful, Thank you!