前言
上篇文章《Go - 如何编写 ProtoBuf 插件 (一) 》,分享了使用 proto3 的 自定义选项 可以实现插件的编写,说到基于 MethodOptions 和 ServiceOptions 选项去实现 method 和 service 自定义设置拦截器。
接上篇文章,继续分享。
定义插件
// plugin/interceptor/options/interceptor.protosyntax = "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 tokenoptional string whitelist = 2; // ip whitelistoptional bool logger = 3; // logger}message ServiceHandler {optional string authorization = 1; // login tokenoptional string whitelist = 2; // ip whitelistoptional bool logger = 3; // logger}
接下来根据 interceptor.proto 生成 interceptor.pb.go
// 生成 interceptor.pb.go// 使用的 protoc --version 为 libprotoc 3.18.1// 使用的 protoc-gen-go --version 为 protoc-gen-go v1.27.1// 在 plugin/interceptor/options 目录下执行 protoc 命令protoc --go_out=. interceptor.proto
使用插件
// helloworld/helloworld.protosyntax = "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;}
接下来根据 helloworld.proto 生成 helloworld.pb.go
// 生成 helloworld.pb.go// 使用的 protoc --version 为 libprotoc 3.18.1// 使用的 protoc-gen-go --version 为 protoc-gen-go v1.27.1// 在根目录下执行 protoc 命令protoc --go_out=helloworld/gen helloworld/helloworld.proto
获取自定义选项
// main.go// 演示代码package mainimport ("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})}
输出:
--- service ---service name: helloworld.Greeteruse interceptor authorization: login_token--- service ------ method ---method name: helloworld.Greeter.SayHello1use interceptor whitelist: ip_whitelistuse interceptor logger: true--- method ------ method ---method name: helloworld.Greeter.SayHello2use interceptor logger: false--- method ---
小结
本文主要内容是基于 自定义选项 定义了 interceptor 插件,然后在 helloworld.proto 中使用了插件,最后在 golang 代码中获取到使用的插件信息。
接下来,要对获取到的插件信息进行使用,主要用在 grpc.ServerOption 中,例如在 grpc.UnaryInterceptor 和 grpc.StreamInterceptor 中使用。
