Go - 如何编写 ProtoBuf 插件(二)?

简介: Go - 如何编写 ProtoBuf 插件(二)?

文章目录:

  • 前言
  • 定义插件
  • 使用插件
  • 获取自定义选项
  • 小结
  • 推荐阅读


前言

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

接上篇文章,继续分享。

定义插件

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

接下来根据 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.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;
}

接下来根据 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 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
 })
}

输出:

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

小结

本文主要内容是基于 自定义选项 定义了 interceptor 插件,然后在 helloworld.proto 中使用了插件,最后在 golang 代码中获取到使用的插件信息。

接下来,要对获取到的插件信息进行使用,主要用在 grpc.ServerOption 中,例如在 grpc.UnaryInterceptorgrpc.StreamInterceptor 中使用。

推荐阅读

目录
相关文章
|
9月前
|
开发框架 Go 计算机视觉
纯Go语言开发人脸检测、瞳孔/眼睛定位与面部特征检测插件-助力GoFly快速开发框架
开发纯go插件的原因是因为目前 Go 生态系统中几乎所有现有的人脸检测解决方案都是纯粹绑定到一些 C/C++ 库,如 OpenCV 或 dlib,但通过 cgo 调用 C 程序会引入巨大的延迟,并在性能方面产生显著的权衡。此外,在许多情况下,在各种平台上安装 OpenCV 是很麻烦的。使用纯Go开发的插件不仅在开发时方便,在项目部署和项目维护也能省很多时间精力。
238 5
Go - 如何编写 ProtoBuf 插件 (一) ?
Go - 如何编写 ProtoBuf 插件 (一) ?
116 2
Go - 如何编写 ProtoBuf 插件 (三) ?
Go - 如何编写 ProtoBuf 插件 (三) ?
81 1
|
运维 监控 测试技术
Golang质量生态建设问题之接入并使用Go单元测试插件的问题如何解决
Golang质量生态建设问题之接入并使用Go单元测试插件的问题如何解决
123 1
|
JSON Linux 测试技术
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
go语言处理数据、基本通信以及环境配置 -- json,protobuf,grpc
165 1
|
网络架构
flutter推荐路由器插件:go_router
flutter推荐路由器插件:go_router
511 0
|
Go 开发者
Go语言插件开发:Pingo库实践
Go语言插件开发:Pingo库实践
205 0
|
JSON 人工智能 API
用 Go 编写 ChatGPT 插件
用 Go 编写 ChatGPT 插件
167 0
|
7月前
|
编译器 Go
揭秘 Go 语言中空结构体的强大用法
Go 语言中的空结构体 `struct{}` 不包含任何字段,不占用内存空间。它在实际编程中有多种典型用法:1) 结合 map 实现集合(set)类型;2) 与 channel 搭配用于信号通知;3) 申请超大容量的 Slice 和 Array 以节省内存;4) 作为接口实现时明确表示不关注值。此外,需要注意的是,空结构体作为字段时可能会因内存对齐原因占用额外空间。建议将空结构体放在外层结构体的第一个字段以优化内存使用。
|
7月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。