Go - 如何编写 ProtoBuf 插件(二)?
前言
上篇文章《Go - 如何编写 ProtoBuf 插件 (一) 》,分享了使用 proto3 的 自定义选项 可以实现插件的编写,说到基于 MethodOptions 和 ServiceOptions 选项去实现 method 和 service 自定义设置拦截器。
接上篇文章,继续分享。
定义插件
// 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.UnaryInterceptor 和 grpc.StreamInterceptor 中使用。
推荐阅读
- Go - 如何编写 ProtoBuf 插件 (一) ?
- Go - 关于 protoc 工具的小疑惑
- Go - 关于 .proto 文件的小思考
- Go - 基于逃逸分析来提升程序性能
- Go - 使用 sync.Map 解决 map 并发安全问题
Go - 如何编写 ProtoBuf 插件(二)?的更多相关文章
- Go - 如何编写 ProtoBuf 插件 (三) ?
目录 前言 演示代码 小结 推荐阅读 前言 上篇文章<Go - 如何编写 ProtoBuf 插件 (二) >,分享了基于 自定义选项 定义了 interceptor 插件,然后在 hell ...
- [翻译]如何编写GIMP插件(二)
写在前面: 本人翻译并不专业,甚至英语不好,翻译内容仅供参考.由于博主是边学边翻译,所以不能保证翻译的准确性和正确性,如果可以,请查看原版学习,本文仅作学习记录之用. <How to write ...
- 编写jQuery插件--实现返回顶部插件
国庆过去一周多了,作为IT界的具有严重’工作狂‘性质的宅人,居然还没走出玩耍的心情,拖了程序猿的脚后跟了.最近工作不顺,心情不佳,想吐槽下公司,想了还是厚道点,以彼之道还施彼身,觉得自己也和他们同流合 ...
- 使用Qt编写模块化插件式应用程序
动态链接库技术使软件工程师们兽血沸腾,它使得应用系统(程序)可以以二进制模块的形式灵活地组建起来.比起源码级别的模块化,二进制级别的模块划分使得各模块更加独立,各模块可以分别编译和链接,模块的升级不会 ...
- [翻译]如何编写GIMP插件(一)
近期想尝试编写gimp插件,在gimp官网看到了三篇简明教程,顺便翻译了下,由于本人英文,计算机知识有限,文中难免有warning,error出现,欢迎指正. <How to write a G ...
- Lua编写wireshark插件初探——解析Websocket上的MQTT协议
一.背景 最近在做物联网流量分析时发现, App在使用MQTT协议时往往通过SSL+WebSocket+MQTT这种方式与服务器通信,在使用SSL中间人截获数据后,Wireshark不能自动解析出MQ ...
- 金蝶K3 wise 插件二次开发与配置
金蝶K3 wise 插件二次开发与配置 开发环境:K/3 Wise 13.0.K/3 Bos开发平台.Visual Basic 6.0 目录 一.二次开发插件编程二.代码演示三.配置插件四.测试插件五 ...
- 前端html、CSS快速编写代码插件-Emmet使用方法技巧详解
前端html.CSS快速编写代码插件-Emmet使用方法技巧详解 Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来 ...
- Qt 显示透明flash和编写QtWebkit插件
Qt 有两种方法可以显示flash. 1. 通过QAxWidget 调用com形式显示flash, 需要本机安装IE flash插件 2. 直接通过qwebview显示flash, 需要下载webki ...
随机推荐
- 一个非常好用的IDEA插件,用于填充set
对于对接三方接口总有一堆字段参数,如在入参时需要赋值,将请求参数封装成一个pojo实体类,然后需要为其set,调用许多setter方法,如果一行行去编写很麻烦,...能不能节省一下我仅存的生产力呀.. ...
- Vulnhub-DarkHole_1 题解
Vulnhub-DarkHole_1-Writeup 靶机地址:DARKHOLE: 1 Difficulty: Easy 扫描与发现 使用arp-scan发现目标IP arp-scan -l 使用nm ...
- ElasticJob分布式任务调度应用v2.5.2
为何要使用分布式任务调度 **本人博客网站 **IT小神 www.itxiaoshen.com 演示项目源码地址** https://gitee.com/yongzhebuju/spring-task ...
- namp相关命令大全
常用功能: -探测主机存活- 扫描端口- 探测主机操作系统信息- 检测漏洞 nmap 常用的几个参数 nmap -v ip 显示详细的扫描过程 nmap -p ip 扫描指定端口 nmap -A ...
- 模数不超过 long long 范围时的快速乘
笔者的话:使用前请确保评测系统的long double严格为16B ! 模数不在 int 范围内的乘法在 OI 中运用广泛,例如Millar-Rabin,Pollard-Rho等等.这样的乘法,直接乘 ...
- 洛谷 P2481 [SDOI2010]代码拍卖会(背包+隔板法)
题面传送门 题意: 给出 \(n,p\),求有多少 \(n\) 位数 \(X=a_1a_2a_3\dots a_n\) 满足: 该 \(n\) 位数不含前导零 \(a_i \leq a_{i+1}\) ...
- 洛谷 P4621 - [COCI2012-2013#6] BAKTERIJE(exCRT)
洛谷题面传送门 发篇正常点的题解. 首先对于这样的题暴力枚举肯定是不行的,因为最小时间显然可能达到 \((4nm)^5\approx 10^{20}\),就算数据很难卡到这个上界,构造出一些使你暴力超 ...
- Codeforces Round #683 (Div. 1) Solution
A. Knapsack 猜个结论--先把所有的东西加起来,如果小于 \(\frac{1}{2}m\) 就输出不合法:如果在 \([\frac{1}{2}m, m]\)之间直接全部输出:若大于 \(m\ ...
- Synteny和collinear的区别
在比较基因组学的时候,经常会听到"共线性"这个词,但是与其对应的有两个不同的概念,即 (1) synteny (2) collinear 二者的区别如下图所示: 可以看到,synt ...
- Docker Alpine Dockerfile 安装nginx,最小镜像
Docker Alpine Dockerfile 安装nginx,最小镜像 FROM alpine MAINTAINER will ## 将alpine-linux:apk的安装源改为国内镜像 RUN ...