preface

The previous article, Go – How to write a ProtoBuf plugin (Part 1), shared how you can write a plugin using proto3’s custom options, Speaking of implementing custom method and Service Settings interceptors based on the MethodOptions and ServiceOptions options.

Pick up the post and continue sharing.

Define the plugin

// plugin/interceptor/options/interceptor.proto syntax = "proto3"; package interceptor; option go_package = "./; interceptor/options"; import "google/protobuf/descriptor.proto"; extend google.protobuf.MethodOptions { optional MethodHandler method_handler = 63500; } extend google.protobuf.ServiceOptions { optional ServiceHandler service_handler = 63501; } message MethodHandler { optional string authorization = 1; // login token optional string whitelist = 2; // ip whitelist optional bool logger = 3; // logger } message ServiceHandler { optional string authorization = 1; // login token optional string whitelist = 2; // ip whitelist optional bool logger = 3; // logger }Copy the code

Next, generate interceptor.pb.go from interceptor.proto

// Generate interceptor.pb.go // Use protoc --version is libprotoc 3.18.1 // use protoc-gen-go --version is protoc-gen-go V1.27.1 / / in the plugin/interceptor/options directory protoc command protoc -- go_out =. Interceptor. The protoCopy the code

The use of plug-in

// helloworld/helloworld.proto syntax = "proto3"; package helloworld; option go_package = "./; helloworld"; import "plugin/interceptor/options/interceptor.proto"; service Greeter { option (interceptor.service_handler) = { authorization : "login_token", }; rpc SayHello1 (HelloRequest) returns (HelloReply) { option (interceptor.method_handler) = { whitelist : "ip_whitelist", logger: true, }; } rpc SayHello2 (HelloRequest) returns (HelloReply) { option (interceptor.method_handler) = { logger: false, }; } } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }Copy the code

Next, generate HelloWorld.pb. go from helloWorld.proto

// Protoc --version is libprotoc 3.18.1 // protoc-gen-go --version is protoc-gen-go v1.27.1 / / in the root directory protoc command protoc - go_out = helloworld/gen helloworld/helloworld protoCopy the code

Gets custom options

/ / main. Go / / demo code package main import (" FMT "strconv" _ "github.com/xinliangnote/protobuf/helloworld/gen" " "github.com/xinliangnote/protobuf/plugin/interceptor/options" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" ) func main() { protoregistry.GlobalFiles.RangeFiles(func(fd protoreflect.FileDescriptor) bool { services := fd.Services() for i := 0; i < services.Len(); i++ { service := services.Get(i) if serviceHandler, _ := proto.GetExtension(service.Options(), options.E_ServiceHandler).(*options.ServiceHandler); serviceHandler ! = nil { fmt.Println() fmt.Println("--- service ---") fmt.Println("service name: " + string(service.FullName())) if serviceHandler.Authorization ! = nil && *serviceHandler.Authorization ! = "" { fmt.Println("use interceptor authorization: " + *serviceHandler.Authorization) } fmt.Println("--- service ---") } methods := service.Methods() for k := 0; k < methods.Len(); k++ { method := methods.Get(k) if methodHandler, _ := proto.GetExtension(method.Options(), options.E_MethodHandler).(*options.MethodHandler); methodHandler ! = nil { fmt.Println() fmt.Println("--- method ---") fmt.Println("method name: " + string(method.FullName())) if methodHandler.Whitelist ! = nil && *methodHandler.Whitelist ! = "" { fmt.Println("use interceptor whitelist: " + *methodHandler.Whitelist) } if methodHandler.Logger ! = nil { fmt.Println("use interceptor logger: " + strconv.FormatBool(*methodHandler.Logger)) } fmt.Println("--- method ---") } } } return true }) }Copy the code

Output:

--- service ---
service name: helloworld.Greeter
use interceptor authorization: login_token
--- service ---

--- method ---
method name: helloworld.Greeter.SayHello1
use interceptor whitelist: ip_whitelist
use interceptor logger: true
--- method ---

--- method ---
method name: helloworld.Greeter.SayHello2
use interceptor logger: false
--- method ---
Copy the code

summary

The main content of this article is to define the interceptor plug-in based on the custom options, then use the plug-in in helloWorld.proto, and finally get the information of the plug-in used in golang code.

Next, use the obtained plug-in information, mainly in grpc.ServerOption, such as grpc.UnaryInterceptor and grpc.StreamInterceptor.

Recommended reading

  • Go – How to write a ProtoBuf plugin (I)?
  • Go – a little confusion about the Protoc tool
  • Go – A little thought about.proto files
  • Go – Improves application performance based on escape analysis
  • Go – Use sync.Map to solve the problem of Map concurrency security