Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could we add some examples for each module? #332

Open
umialpha opened this issue Jul 2, 2020 · 8 comments
Open

Could we add some examples for each module? #332

umialpha opened this issue Jul 2, 2020 · 8 comments

Comments

@umialpha
Copy link

umialpha commented Jul 2, 2020

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?

@umialpha
Copy link
Author

umialpha commented Jul 2, 2020

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

@Paxa
Copy link

Paxa commented Jul 12, 2020

+1 for examples

@Paxa
Copy link

Paxa commented Jul 12, 2020

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)
}

@umialpha
Copy link
Author

@Paxa Thanks a lot. Your example explains pretty well.

@LSTPro
Copy link

LSTPro commented Apr 4, 2024

@Paxa How do I read the incoming metadata after invokeRPC call
i.e., response, err := grpcClient.InvokeRpc(context.TODO(), methodDesc, message)

@jhump
Copy link
Owner

jhump commented Apr 4, 2024

@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

@LSTPro
Copy link

LSTPro commented Apr 4, 2024

@jhump The link provided was helpful, Thank you!

@alwaysastudent
Copy link

Wondering if we can get similar usage examples for v2 as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants