前言

上篇文章《Go - 如何编写 ProtoBuf 插件 (一) 》,分享了应用 proto3自定义选项 能够实现插件的编写,说到基于 MethodOptionsServiceOptions 选项去实现 methodservice 自定义设置拦截器。

接上篇文章,持续分享。

定义插件

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

接下来依据 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.UnaryInterceptorgrpc.StreamInterceptor 中应用。

举荐浏览

  • Go - 如何编写 ProtoBuf 插件 (一) ?
  • Go - 对于 protoc 工具的小纳闷
  • Go - 对于 .proto 文件的小思考
  • Go - 基于逃逸剖析来晋升程序性能
  • Go - 应用 sync.Map 解决 map 并发平安问题