Compare commits

...

10 Commits

Author SHA1 Message Date
5d2355983f udpate 2025-12-27 21:07:54 +08:00
5e1559eab5 update 2025-09-27 16:28:42 +08:00
a74d1e42c0 update new mlfow 2025-09-27 16:22:07 +08:00
8a4b8e69bc update k8s 2025-08-29 22:08:50 +08:00
d37d099619 补充prometheus 2025-08-24 16:55:43 +08:00
e3a6e821d9 补充架构图 2025-08-24 16:29:20 +08:00
bf80400b7a 处理包之间的引用 2025-08-24 15:58:47 +08:00
4a0ed93617 补充grpc认证 2025-08-24 14:51:13 +08:00
afa7743e82 update stream req 2025-08-24 14:34:22 +08:00
a6725de634 完善grpc 2025-08-24 14:15:16 +08:00
24 changed files with 998 additions and 48 deletions

10
.vscode/settings.json vendored
View File

@ -4,5 +4,13 @@
"CONFIG_PATH": "${workspaceFolder}/application.yaml" "CONFIG_PATH": "${workspaceFolder}/application.yaml"
}, },
"go.testEnvFile": "${workspaceFolder}/etc/unit_test.env", "go.testEnvFile": "${workspaceFolder}/etc/unit_test.env",
"terminal.integrated.suggest.enabled": true "terminal.integrated.suggest.enabled": true,
"protoc": {
"path": "/usr/local/bin/protoc",
"compile_on_save": false,
"options": [
"--proto_path=.",
"--proto_path=/usr/local/include",
]
}
} }

View File

@ -58,7 +58,37 @@ go mod init "122.51.31.227/go-course/go18"
# go mod init go18 # go mod init go18
``` ```
本[项目代码](http://122.51.31.227:3000/go-course/go18)
## Gin + GORM 开发简单的Book API Server ## Gin + GORM 开发简单的Book API Server
从写脚本开始 与 学会合理使用包来组织你的项目工程 从写脚本开始 与 学会合理使用包来组织你的项目工程
## GO18期更新点
1. RPC部分 新增JSON RPC的封装
1. JSON RPC详情介绍
2. JSON RPC 封装
3. 基于JSON RPC的RPC服务端和客户端实现
2. 新增消息总线模块
1. 消息总线的整体设计与介绍
2. 消息总线 支持 Kafka, RabbitMQ, Nats
3. 基于Kafka和RabbitMQ的消息总线实现
3. DevOps平台全新UI设计与实现
1. 基于DevOps的平台UI框架介绍与实现
2. 多模块系统的重构与升级
3. 应用服务树的设计与实现
4. CMDB系统开发模块升级
1. 新增任务调度执行模块, 完成任务的调度与执行
2. 基于任务调度模块重构 资产同步的逻辑
5. 审计系统开发模块升级
1. 基于消息总线的 重构审计系统的 事件发生和订阅逻辑
6. k8s operator开发模块升级
1. 升级到最新版本默认支持v4
2. 支持指定namespace的资源同步
3. 支持指定wroker节点数量改善并发同步效率

View File

@ -11,3 +11,9 @@ devcloud: 研发云, 给产研团队(技术团队), 产品经理, 项目经理,
多业务模块组成, 渐进式微服务开发方式 多业务模块组成, 渐进式微服务开发方式
最新版本:
pipeline: https://github.com/infraboard/devops/tree/main/api/mflow
旧版本:
https://github.com/infraboard/mflow
整体最新代码: devops 项目里面

View File

@ -28,8 +28,10 @@ func (c *consumer) Run(ctx context.Context) error {
// 发送的数据时Json格式, 接收用的JSON, 发送也需要使用JSON // 发送的数据时Json格式, 接收用的JSON, 发送也需要使用JSON
err = e.Load(m.Value) err = e.Load(m.Value)
if err == nil { if err == nil {
// 保存日志, 保持失败的次数统计起来,披露给外部, 编写一个采集器,来采统计失败次数
if err := event.GetService().SaveEvent(ctx, types.NewSet[*event.Event]().Add(e)); err != nil { if err := event.GetService().SaveEvent(ctx, types.NewSet[*event.Event]().Add(e)); err != nil {
c.log.Error().Msgf("save event error, %s", err) c.log.Error().Msgf("save event error, %s", err)
c.collector.Inc()
} }
} }

View File

@ -6,6 +6,7 @@ import (
"122.51.31.227/go-course/go18/devcloud/audit/apps/event" "122.51.31.227/go-course/go18/devcloud/audit/apps/event"
"github.com/infraboard/mcube/v2/ioc" "github.com/infraboard/mcube/v2/ioc"
"github.com/infraboard/mcube/v2/ioc/config/log" "github.com/infraboard/mcube/v2/ioc/config/log"
"github.com/prometheus/client_golang/prometheus"
"github.com/rs/zerolog" "github.com/rs/zerolog"
ioc_kafka "github.com/infraboard/mcube/v2/ioc/config/kafka" ioc_kafka "github.com/infraboard/mcube/v2/ioc/config/kafka"
@ -37,6 +38,9 @@ type consumer struct {
GroupId string `toml:"group_id" json:"group_id" yaml:"group_id" env:"GROUP_ID"` GroupId string `toml:"group_id" json:"group_id" yaml:"group_id" env:"GROUP_ID"`
// 当前这个消费者 配置的topic // 当前这个消费者 配置的topic
Topics []string `toml:"topic" json:"topic" yaml:"topic" env:"TOPIC"` Topics []string `toml:"topic" json:"topic" yaml:"topic" env:"TOPIC"`
// 采集器
collector *EventCollector
} }
// 对象名称 // 对象名称
@ -48,6 +52,11 @@ func (i *consumer) Name() string {
func (i *consumer) Init() error { func (i *consumer) Init() error {
// 对象 // 对象
i.log = log.Sub(i.Name()) i.log = log.Sub(i.Name())
// 准备好采集器, 注册给Prometheus
i.collector = NewEventCollector()
prometheus.MustRegister(i.collector)
i.reader = ioc_kafka.ConsumerGroup(i.GroupId, i.Topics) i.reader = ioc_kafka.ConsumerGroup(i.GroupId, i.Topics)
go i.Run(i.ctx) go i.Run(i.ctx)

View File

@ -0,0 +1,38 @@
package consumer
import "github.com/prometheus/client_golang/prometheus"
// # HELP save_event_error_count 事件入库失败个数统计
// # TYPE save_event_error_count gauge
// save_event_error_count{service="devcloud"} 0
func NewEventCollector() *EventCollector {
return &EventCollector{
errCountDesc: prometheus.NewDesc(
"save_event_error_count",
"事件入库失败个数统计",
[]string{},
prometheus.Labels{"service": "devcloud"},
),
}
}
// 收集事件指标的采集器
type EventCollector struct {
errCountDesc *prometheus.Desc
// 需要自己根据实践情况来维护这个变量
errCount int
}
func (c *EventCollector) Inc() {
c.errCount++
}
// 指标元数据注册
func (c *EventCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- c.errCountDesc
}
// 指标的值的采集
func (c *EventCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(c.errCountDesc, prometheus.GaugeValue, float64(c.errCount))
}

View File

@ -0,0 +1,16 @@
# k8s 集群管理
https://kubernetes.io/
k8s UI工具: Rancher, KubeSphere, Dashbaord k8s 集群管理工具(运维人员)
+ Deployment,StatfulSet, DaesonSet, Pod, Service, ...
我们要做的系统: 是做个 k8s的集群管理工具吗 给软件研发人员使用的(应用的发布与部署)
依赖于K8s提供的能力来实现一套发布系统
## 概念的定义

View File

@ -0,0 +1,87 @@
<mxfile host="65bd71144e">
<diagram id="2lwm4o9OGl1Gjpf4ACLQ" name="第 1 页">
<mxGraphModel dx="1115" dy="631" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="4" value="查询制品" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="5" target="9">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="5" value="artifact&lt;div&gt;制品库&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="260" y="100" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="6" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="7" target="5">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="23" value="制品信息上报" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="6">
<mxGeometry x="-0.1818" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="7" value="CI工具" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="30" y="100" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="8" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="9" target="13">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="9" value="deploy&lt;div&gt;应用部署&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="260" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="10" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="12" target="9">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="11" value="选择适合的制品格式&lt;div&gt;&lt;br&gt;&lt;/div&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="10">
<mxGeometry x="0.2278" y="-3" relative="1" as="geometry">
<mxPoint x="29" y="-17" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="12" value="cluster&lt;div&gt;应用集群&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="590" y="250" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="13" value="k8s 集群" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="260" y="430" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="14" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="18" target="13">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="15" value="watch" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="14">
<mxGeometry x="0.2242" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="16" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="18" target="12">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="17" value="实时更新集群状态" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="16">
<mxGeometry x="0.0236" y="-4" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="18" value="sync&lt;div&gt;部署同步&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="590" y="430" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="19" value="首次部署使用模版渲染" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="20" target="12">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="20" value="temlate&lt;div&gt;部署模版&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="590" y="100" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="21" style="edgeStyle=none;html=1;exitX=0;exitY=0.3333333333333333;exitDx=0;exitDy=0;exitPerimeter=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="22" target="12">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="22" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1">
<mxGeometry x="770" y="260" width="30" height="60" as="geometry"/>
</mxCell>
<mxCell id="24" value="应用部署 (应用发布流中最核心)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="440" y="30" width="200" height="30" as="geometry"/>
</mxCell>
<mxCell id="25" value="承载应用运行的实例" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="485" y="330" width="110" height="30" as="geometry"/>
</mxCell>
<mxCell id="26" value="部署引擎" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="200" y="320" width="60" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

1
devops Submodule

@ -0,0 +1 @@
Subproject commit 78b4bd5dac73a7561abecfc0cbe587a4033cb49b

6
go.mod
View File

@ -11,6 +11,7 @@ require (
github.com/infraboard/devops v0.0.6 github.com/infraboard/devops v0.0.6
github.com/infraboard/mcube/v2 v2.0.63 github.com/infraboard/mcube/v2 v2.0.63
github.com/infraboard/modules v0.0.20 github.com/infraboard/modules v0.0.20
github.com/prometheus/client_golang v1.22.0
github.com/rs/xid v1.6.0 github.com/rs/xid v1.6.0
github.com/rs/zerolog v1.34.0 github.com/rs/zerolog v1.34.0
github.com/segmentio/kafka-go v0.4.47 github.com/segmentio/kafka-go v0.4.47
@ -19,6 +20,8 @@ require (
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lighthouse v1.0.1134 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/lighthouse v1.0.1134
go.mongodb.org/mongo-driver v1.17.3 go.mongodb.org/mongo-driver v1.17.3
golang.org/x/crypto v0.38.0 golang.org/x/crypto v0.38.0
google.golang.org/grpc v1.72.0
google.golang.org/protobuf v1.36.6
gopkg.in/yaml.v3 v3.0.1 gopkg.in/yaml.v3 v3.0.1
gorm.io/datatypes v1.2.5 gorm.io/datatypes v1.2.5
gorm.io/driver/mysql v1.5.7 gorm.io/driver/mysql v1.5.7
@ -77,7 +80,6 @@ require (
github.com/pierrec/lz4/v4 v4.1.15 // indirect github.com/pierrec/lz4/v4 v4.1.15 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.63.0 // indirect github.com/prometheus/common v0.63.0 // indirect
github.com/prometheus/procfs v0.16.0 // indirect github.com/prometheus/procfs v0.16.0 // indirect
@ -112,8 +114,6 @@ require (
golang.org/x/text v0.25.0 // indirect golang.org/x/text v0.25.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect
google.golang.org/grpc v1.72.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gorm.io/driver/postgres v1.5.11 // indirect gorm.io/driver/postgres v1.5.11 // indirect
modernc.org/libc v1.22.5 // indirect modernc.org/libc v1.22.5 // indirect

View File

@ -0,0 +1,2 @@
# 关于面试

3
skills/metric/README.md Normal file
View File

@ -0,0 +1,3 @@
# Metric
https://www.mcube.top/guide/config/metric.html

View File

@ -1,59 +1,108 @@
<mxfile host="65bd71144e"> <mxfile host="65bd71144e">
<diagram id="yflk6MuM42xHFq2jSyhu" name="第 1 页"> <diagram id="yflk6MuM42xHFq2jSyhu" name="第 1 页">
<mxGraphModel dx="1333" dy="710" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0"> <mxGraphModel dx="1115" dy="597" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root> <root>
<mxCell id="0"/> <mxCell id="0"/>
<mxCell id="1" parent="0"/> <mxCell id="1" parent="0"/>
<mxCell id="2" value="server a&lt;div&gt;fn&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="2" value="server a&lt;div&gt;fn&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="170" y="170" width="120" height="60" as="geometry"/> <mxGeometry x="170" y="170" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="6" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="5" target="2"> <mxCell id="6" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="5" target="2" edge="1">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="7" value="servier a: fn" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="6"> <mxCell id="7" value="servier a: fn" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="6" vertex="1" connectable="0">
<mxGeometry x="0.1941" y="-1" relative="1" as="geometry"> <mxGeometry x="0.1941" y="-1" relative="1" as="geometry">
<mxPoint as="offset"/> <mxPoint as="offset"/>
</mxGeometry> </mxGeometry>
</mxCell> </mxCell>
<mxCell id="5" value="server b" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="5" value="server b" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="630" y="170" width="120" height="60" as="geometry"/> <mxGeometry x="630" y="170" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="8" value="rpc" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> <mxCell id="8" value="rpc" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="400" y="100" width="60" height="30" as="geometry"/> <mxGeometry x="400" y="100" width="60" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="9" value="fn: (my_name) {hello, my_name}" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> <mxCell id="9" value="fn: (my_name) {hello, my_name}" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="350" y="250" width="230" height="30" as="geometry"/> <mxGeometry x="350" y="250" width="230" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="10" value="service c&lt;div&gt;python&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="10" value="service c&lt;div&gt;python&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="630" y="390" width="120" height="60" as="geometry"/> <mxGeometry x="630" y="390" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="11" value="service d&lt;div&gt;java&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="11" value="service d&lt;div&gt;java&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="390" y="390" width="120" height="60" as="geometry"/> <mxGeometry x="390" y="390" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="12" value="server b&lt;div&gt;go&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="12" value="server b&lt;div&gt;go&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="150" y="390" width="120" height="60" as="geometry"/> <mxGeometry x="150" y="390" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="19" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" edge="1" parent="1" source="13" target="16"> <mxCell id="19" style="edgeStyle=none;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;" parent="1" source="13" target="16" edge="1">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="20" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="13" target="17"> <mxCell id="20" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="13" target="17" edge="1">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="13" value="protofuf" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1"> <mxCell id="13" value="protofuf" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="390" y="570" width="120" height="60" as="geometry"/> <mxGeometry x="390" y="570" width="120" height="60" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="15" value="interface(struct)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> <mxCell id="15" value="interface(struct)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="160" y="480" width="100" height="30" as="geometry"/> <mxGeometry x="160" y="480" width="100" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="16" value="interface(class)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> <mxCell id="16" value="interface(class)" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="400" y="480" width="100" height="30" as="geometry"/> <mxGeometry x="400" y="480" width="100" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="17" value="class" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> <mxCell id="17" value="class" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="670" y="480" width="60" height="30" as="geometry"/> <mxGeometry x="670" y="480" width="60" height="30" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="18" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.43;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="13" target="15"> <mxCell id="18" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.43;entryY=1;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="13" target="15" edge="1">
<mxGeometry relative="1" as="geometry"/> <mxGeometry relative="1" as="geometry"/>
</mxCell> </mxCell>
<mxCell id="30" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="21" target="22">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="31" value="GRPC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="30">
<mxGeometry x="-0.2941" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="32" style="edgeStyle=orthogonalEdgeStyle;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="21" target="25">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="21" value="业务网关(Restful API grpc-rest)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="190" y="920" width="530" height="60" as="geometry"/>
</mxCell>
<mxCell id="22" value="grpc service&lt;div&gt;app1&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="190" y="1050" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="23" value="&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;grpc service&lt;/span&gt;&lt;div&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;app2&lt;/span&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="340" y="1050" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="24" value="&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;grpc service&lt;/span&gt;&lt;div&gt;&lt;span style=&quot;color: rgb(0, 0, 0);&quot;&gt;app3&lt;/span&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="480" y="1050" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="25" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(251, 251, 251); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;&quot;&gt;grpc service&lt;/span&gt;&lt;div&gt;&lt;span style=&quot;color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(251, 251, 251); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;&quot;&gt;app3&lt;/span&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="630" y="1050" width="120" height="60" as="geometry"/>
</mxCell>
<mxCell id="28" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;" edge="1" parent="1" source="27" target="21">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="29" value="Restful API" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="28">
<mxGeometry x="-0.15" y="-4" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="27" value="Browser" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="190" y="800" width="530" height="60" as="geometry"/>
</mxCell>
<mxCell id="33" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.425;entryY=1.033;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="23" target="22">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="330" y="1150"/>
</Array>
</mxGeometry>
</mxCell>
<mxCell id="34" value="GRPC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="33">
<mxGeometry x="-0.2337" y="-2" relative="1" as="geometry">
<mxPoint as="offset"/>
</mxGeometry>
</mxCell>
</root> </root>
</mxGraphModel> </mxGraphModel>
</diagram> </diagram>

View File

@ -10,6 +10,8 @@ type HelloService interface {
+ RPC方法的定义 + RPC方法的定义
+ PRC数据结构的定义 + PRC数据结构的定义
安装vsocde的 proto语法高亮插件: vscode-proto3
## 插件安装 ## 插件安装
```sh ```sh
@ -155,3 +157,10 @@ func (c *helloServiceClient) Hello(ctx context.Context, in *Request, opts ...grp
## 其他服务 使用生成的client调用grpc服务的方法 ## 其他服务 使用生成的client调用grpc服务的方法
## 包
```sh
protoc -I=. --go_out=. --go_opt=module="122.51.31.227/go-course/go18" skills/rpc/protobuf/app_service/interface.proto
```

View File

@ -0,0 +1,165 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.8
// protoc v6.32.0
// source: skills/rpc/protobuf/app_service/interface.proto
package app_service
import (
reflect "reflect"
sync "sync"
unsafe "unsafe"
hello_service "122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type App struct {
state protoimpl.MessageState `protogen:"open.v1"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"`
// 通过包名引用其他包里面定义
Request *hello_service.Request `protobuf:"bytes,4,opt,name=request,proto3" json:"request,omitempty"`
Response *hello_service.Response `protobuf:"bytes,5,opt,name=response,proto3" json:"response,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *App) Reset() {
*x = App{}
mi := &file_skills_rpc_protobuf_app_service_interface_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *App) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*App) ProtoMessage() {}
func (x *App) ProtoReflect() protoreflect.Message {
mi := &file_skills_rpc_protobuf_app_service_interface_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use App.ProtoReflect.Descriptor instead.
func (*App) Descriptor() ([]byte, []int) {
return file_skills_rpc_protobuf_app_service_interface_proto_rawDescGZIP(), []int{0}
}
func (x *App) GetId() string {
if x != nil {
return x.Id
}
return ""
}
func (x *App) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *App) GetDescription() string {
if x != nil {
return x.Description
}
return ""
}
func (x *App) GetRequest() *hello_service.Request {
if x != nil {
return x.Request
}
return nil
}
func (x *App) GetResponse() *hello_service.Response {
if x != nil {
return x.Response
}
return nil
}
var File_skills_rpc_protobuf_app_service_interface_proto protoreflect.FileDescriptor
const file_skills_rpc_protobuf_app_service_interface_proto_rawDesc = "" +
"\n" +
"/skills/rpc/protobuf/app_service/interface.proto\x12\x03app\x1a1skills/rpc/protobuf/hello_service/interface.proto\"\xa2\x01\n" +
"\x03App\x12\x0e\n" +
"\x02id\x18\x01 \x01(\tR\x02id\x12\x12\n" +
"\x04name\x18\x02 \x01(\tR\x04name\x12 \n" +
"\vdescription\x18\x03 \x01(\tR\vdescription\x12(\n" +
"\arequest\x18\x04 \x01(\v2\x0e.hello.RequestR\arequest\x12+\n" +
"\bresponse\x18\x05 \x01(\v2\x0f.hello.ResponseR\bresponseB>Z<122.51.31.227/go-course/go18/skills/rpc/protobuf/app_serviceb\x06proto3"
var (
file_skills_rpc_protobuf_app_service_interface_proto_rawDescOnce sync.Once
file_skills_rpc_protobuf_app_service_interface_proto_rawDescData []byte
)
func file_skills_rpc_protobuf_app_service_interface_proto_rawDescGZIP() []byte {
file_skills_rpc_protobuf_app_service_interface_proto_rawDescOnce.Do(func() {
file_skills_rpc_protobuf_app_service_interface_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_skills_rpc_protobuf_app_service_interface_proto_rawDesc), len(file_skills_rpc_protobuf_app_service_interface_proto_rawDesc)))
})
return file_skills_rpc_protobuf_app_service_interface_proto_rawDescData
}
var file_skills_rpc_protobuf_app_service_interface_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_skills_rpc_protobuf_app_service_interface_proto_goTypes = []any{
(*App)(nil), // 0: app.App
(*hello_service.Request)(nil), // 1: hello.Request
(*hello_service.Response)(nil), // 2: hello.Response
}
var file_skills_rpc_protobuf_app_service_interface_proto_depIdxs = []int32{
1, // 0: app.App.request:type_name -> hello.Request
2, // 1: app.App.response:type_name -> hello.Response
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
}
func init() { file_skills_rpc_protobuf_app_service_interface_proto_init() }
func file_skills_rpc_protobuf_app_service_interface_proto_init() {
if File_skills_rpc_protobuf_app_service_interface_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_skills_rpc_protobuf_app_service_interface_proto_rawDesc), len(file_skills_rpc_protobuf_app_service_interface_proto_rawDesc)),
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_skills_rpc_protobuf_app_service_interface_proto_goTypes,
DependencyIndexes: file_skills_rpc_protobuf_app_service_interface_proto_depIdxs,
MessageInfos: file_skills_rpc_protobuf_app_service_interface_proto_msgTypes,
}.Build()
File_skills_rpc_protobuf_app_service_interface_proto = out.File
file_skills_rpc_protobuf_app_service_interface_proto_goTypes = nil
file_skills_rpc_protobuf_app_service_interface_proto_depIdxs = nil
}

View File

@ -0,0 +1,16 @@
syntax = "proto3";
package app;
option go_package="122.51.31.227/go-course/go18/skills/rpc/protobuf/app_service";
//
import "skills/rpc/protobuf/hello_service/interface.proto";
message App {
string id = 1;
string name = 2;
string description = 3;
//
hello.Request request = 4;
hello.Response response = 5;
}

View File

@ -0,0 +1,56 @@
package hello_service
import context "context"
// PerRPCCredentials defines the common interface for the credentials which need to
// attach security information to every RPC (e.g., oauth2).
// type PerRPCCredentials interface {
// // GetRequestMetadata gets the current request metadata, refreshing tokens
// // if required. This should be called by the transport layer on each
// // request, and the data should be populated in headers or other
// // context. If a status code is returned, it will be used as the status for
// // the RPC (restricted to an allowable set of codes as defined by gRFC
// // A54). uri is the URI of the entry point for the request. When supported
// // by the underlying implementation, ctx can be used for timeout and
// // cancellation. Additionally, RequestInfo data will be available via ctx
// // to this call. TODO(zhaoq): Define the set of the qualified keys instead
// // of leaving it as an arbitrary string.
// GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
// // RequireTransportSecurity indicates whether the credentials requires
// // transport security.
// RequireTransportSecurity() bool
// }
func NewClientAuthentication(clientId, clientSecret string) *Authentication {
return &Authentication{
clientID: clientId,
clientSecret: clientSecret,
}
}
// Authentication todo
type Authentication struct {
clientID string
clientSecret string
}
// WithClientCredentials todo
func (a *Authentication) WithClientCredentials(clientID, clientSecret string) {
a.clientID = clientID
a.clientSecret = clientSecret
}
// GetRequestMetadata todo
func (a *Authentication) GetRequestMetadata(context.Context, ...string) (
map[string]string, error,
) {
return map[string]string{
ClientHeaderKey: a.clientID,
ClientSecretKey: a.clientSecret,
}, nil
}
// RequireTransportSecurity todo
func (a *Authentication) RequireTransportSecurity() bool {
return false
}

View File

@ -9,6 +9,7 @@ package hello_service
import ( import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl" protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
reflect "reflect" reflect "reflect"
sync "sync" sync "sync"
unsafe "unsafe" unsafe "unsafe"
@ -21,9 +22,72 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
) )
type Corpus int32
const (
Corpus_UNIVERSAL Corpus = 0
Corpus_WEB Corpus = 1
Corpus_IMAGES Corpus = 2
Corpus_LOCAL Corpus = 3
Corpus_NEWS Corpus = 4
Corpus_PRODUCTS Corpus = 5
Corpus_VIDEO Corpus = 6
)
// Enum value maps for Corpus.
var (
Corpus_name = map[int32]string{
0: "UNIVERSAL",
1: "WEB",
2: "IMAGES",
3: "LOCAL",
4: "NEWS",
5: "PRODUCTS",
6: "VIDEO",
}
Corpus_value = map[string]int32{
"UNIVERSAL": 0,
"WEB": 1,
"IMAGES": 2,
"LOCAL": 3,
"NEWS": 4,
"PRODUCTS": 5,
"VIDEO": 6,
}
)
func (x Corpus) Enum() *Corpus {
p := new(Corpus)
*p = x
return p
}
func (x Corpus) String() string {
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
}
func (Corpus) Descriptor() protoreflect.EnumDescriptor {
return file_skills_rpc_protobuf_hello_service_interface_proto_enumTypes[0].Descriptor()
}
func (Corpus) Type() protoreflect.EnumType {
return &file_skills_rpc_protobuf_hello_service_interface_proto_enumTypes[0]
}
func (x Corpus) Number() protoreflect.EnumNumber {
return protoreflect.EnumNumber(x)
}
// Deprecated: Use Corpus.Descriptor instead.
func (Corpus) EnumDescriptor() ([]byte, []int) {
return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP(), []int{0}
}
type Request struct { type Request struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
// map
Extras map[string]string `protobuf:"bytes,2,rep,name=extras,proto3" json:"extras,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
} }
@ -65,6 +129,66 @@ func (x *Request) GetValue() string {
return "" return ""
} }
func (x *Request) GetExtras() map[string]string {
if x != nil {
return x.Extras
}
return nil
}
type RequestSet struct {
state protoimpl.MessageState `protogen:"open.v1"`
Total int64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
// repeated 来描述一个数组
Items []*Request `protobuf:"bytes,2,rep,name=items,proto3" json:"items,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *RequestSet) Reset() {
*x = RequestSet{}
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *RequestSet) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*RequestSet) ProtoMessage() {}
func (x *RequestSet) ProtoReflect() protoreflect.Message {
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use RequestSet.ProtoReflect.Descriptor instead.
func (*RequestSet) Descriptor() ([]byte, []int) {
return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP(), []int{1}
}
func (x *RequestSet) GetTotal() int64 {
if x != nil {
return x.Total
}
return 0
}
func (x *RequestSet) GetItems() []*Request {
if x != nil {
return x.Items
}
return nil
}
type Response struct { type Response struct {
state protoimpl.MessageState `protogen:"open.v1"` state protoimpl.MessageState `protogen:"open.v1"`
Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"`
@ -74,7 +198,7 @@ type Response struct {
func (x *Response) Reset() { func (x *Response) Reset() {
*x = Response{} *x = Response{}
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[1] mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -86,7 +210,7 @@ func (x *Response) String() string {
func (*Response) ProtoMessage() {} func (*Response) ProtoMessage() {}
func (x *Response) ProtoReflect() protoreflect.Message { func (x *Response) ProtoReflect() protoreflect.Message {
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[1] mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[2]
if x != nil { if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -99,7 +223,7 @@ func (x *Response) ProtoReflect() protoreflect.Message {
// Deprecated: Use Response.ProtoReflect.Descriptor instead. // Deprecated: Use Response.ProtoReflect.Descriptor instead.
func (*Response) Descriptor() ([]byte, []int) { func (*Response) Descriptor() ([]byte, []int) {
return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP(), []int{1} return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP(), []int{2}
} }
func (x *Response) GetValue() string { func (x *Response) GetValue() string {
@ -109,17 +233,90 @@ func (x *Response) GetValue() string {
return "" return ""
} }
type ErrorStatus struct {
state protoimpl.MessageState `protogen:"open.v1"`
Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"`
Details []*anypb.Any `protobuf:"bytes,2,rep,name=details,proto3" json:"details,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ErrorStatus) Reset() {
*x = ErrorStatus{}
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ErrorStatus) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ErrorStatus) ProtoMessage() {}
func (x *ErrorStatus) ProtoReflect() protoreflect.Message {
mi := &file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes[3]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ErrorStatus.ProtoReflect.Descriptor instead.
func (*ErrorStatus) Descriptor() ([]byte, []int) {
return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP(), []int{3}
}
func (x *ErrorStatus) GetMessage() string {
if x != nil {
return x.Message
}
return ""
}
func (x *ErrorStatus) GetDetails() []*anypb.Any {
if x != nil {
return x.Details
}
return nil
}
var File_skills_rpc_protobuf_hello_service_interface_proto protoreflect.FileDescriptor var File_skills_rpc_protobuf_hello_service_interface_proto protoreflect.FileDescriptor
const file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc = "" + const file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc = "" +
"\n" + "\n" +
"1skills/rpc/protobuf/hello_service/interface.proto\x12\x05hello\"\x1f\n" + "1skills/rpc/protobuf/hello_service/interface.proto\x12\x05hello\x1a\x19google/protobuf/any.proto\"\x8e\x01\n" +
"\aRequest\x12\x14\n" + "\aRequest\x12\x14\n" +
"\x05value\x18\x01 \x01(\tR\x05value\" \n" + "\x05value\x18\x01 \x01(\tR\x05value\x122\n" +
"\x06extras\x18\x02 \x03(\v2\x1a.hello.Request.ExtrasEntryR\x06extras\x1a9\n" +
"\vExtrasEntry\x12\x10\n" +
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"H\n" +
"\n" +
"RequestSet\x12\x14\n" +
"\x05total\x18\x01 \x01(\x03R\x05total\x12$\n" +
"\x05items\x18\x02 \x03(\v2\x0e.hello.RequestR\x05items\" \n" +
"\bResponse\x12\x14\n" + "\bResponse\x12\x14\n" +
"\x05value\x18\x01 \x01(\tR\x05value28\n" + "\x05value\x18\x01 \x01(\tR\x05value\"W\n" +
"\vErrorStatus\x12\x18\n" +
"\amessage\x18\x01 \x01(\tR\amessage\x12.\n" +
"\adetails\x18\x02 \x03(\v2\x14.google.protobuf.AnyR\adetails*Z\n" +
"\x06Corpus\x12\r\n" +
"\tUNIVERSAL\x10\x00\x12\a\n" +
"\x03WEB\x10\x01\x12\n" +
"\n" +
"\x06IMAGES\x10\x02\x12\t\n" +
"\x05LOCAL\x10\x03\x12\b\n" +
"\x04NEWS\x10\x04\x12\f\n" +
"\bPRODUCTS\x10\x05\x12\t\n" +
"\x05VIDEO\x10\x062j\n" +
"\fHelloService\x12(\n" + "\fHelloService\x12(\n" +
"\x05Hello\x12\x0e.hello.Request\x1a\x0f.hello.ResponseB@Z>122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_serviceb\x06proto3" "\x05Hello\x12\x0e.hello.Request\x1a\x0f.hello.Response\x120\n" +
"\aChannel\x12\x0e.hello.Request\x1a\x0f.hello.Response\"\x00(\x010\x01B@Z>122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_serviceb\x06proto3"
var ( var (
file_skills_rpc_protobuf_hello_service_interface_proto_rawDescOnce sync.Once file_skills_rpc_protobuf_hello_service_interface_proto_rawDescOnce sync.Once
@ -133,19 +330,30 @@ func file_skills_rpc_protobuf_hello_service_interface_proto_rawDescGZIP() []byte
return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescData return file_skills_rpc_protobuf_hello_service_interface_proto_rawDescData
} }
var file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_skills_rpc_protobuf_hello_service_interface_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
var file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_skills_rpc_protobuf_hello_service_interface_proto_goTypes = []any{ var file_skills_rpc_protobuf_hello_service_interface_proto_goTypes = []any{
(*Request)(nil), // 0: hello.Request (Corpus)(0), // 0: hello.Corpus
(*Response)(nil), // 1: hello.Response (*Request)(nil), // 1: hello.Request
(*RequestSet)(nil), // 2: hello.RequestSet
(*Response)(nil), // 3: hello.Response
(*ErrorStatus)(nil), // 4: hello.ErrorStatus
nil, // 5: hello.Request.ExtrasEntry
(*anypb.Any)(nil), // 6: google.protobuf.Any
} }
var file_skills_rpc_protobuf_hello_service_interface_proto_depIdxs = []int32{ var file_skills_rpc_protobuf_hello_service_interface_proto_depIdxs = []int32{
0, // 0: hello.HelloService.Hello:input_type -> hello.Request 5, // 0: hello.Request.extras:type_name -> hello.Request.ExtrasEntry
1, // 1: hello.HelloService.Hello:output_type -> hello.Response 1, // 1: hello.RequestSet.items:type_name -> hello.Request
1, // [1:2] is the sub-list for method output_type 6, // 2: hello.ErrorStatus.details:type_name -> google.protobuf.Any
0, // [0:1] is the sub-list for method input_type 1, // 3: hello.HelloService.Hello:input_type -> hello.Request
0, // [0:0] is the sub-list for extension type_name 1, // 4: hello.HelloService.Channel:input_type -> hello.Request
0, // [0:0] is the sub-list for extension extendee 3, // 5: hello.HelloService.Hello:output_type -> hello.Response
0, // [0:0] is the sub-list for field type_name 3, // 6: hello.HelloService.Channel:output_type -> hello.Response
5, // [5:7] is the sub-list for method output_type
3, // [3:5] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
} }
func init() { file_skills_rpc_protobuf_hello_service_interface_proto_init() } func init() { file_skills_rpc_protobuf_hello_service_interface_proto_init() }
@ -158,13 +366,14 @@ func file_skills_rpc_protobuf_hello_service_interface_proto_init() {
File: protoimpl.DescBuilder{ File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc), len(file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc)), RawDescriptor: unsafe.Slice(unsafe.StringData(file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc), len(file_skills_rpc_protobuf_hello_service_interface_proto_rawDesc)),
NumEnums: 0, NumEnums: 1,
NumMessages: 2, NumMessages: 5,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },
GoTypes: file_skills_rpc_protobuf_hello_service_interface_proto_goTypes, GoTypes: file_skills_rpc_protobuf_hello_service_interface_proto_goTypes,
DependencyIndexes: file_skills_rpc_protobuf_hello_service_interface_proto_depIdxs, DependencyIndexes: file_skills_rpc_protobuf_hello_service_interface_proto_depIdxs,
EnumInfos: file_skills_rpc_protobuf_hello_service_interface_proto_enumTypes,
MessageInfos: file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes, MessageInfos: file_skills_rpc_protobuf_hello_service_interface_proto_msgTypes,
}.Build() }.Build()
File_skills_rpc_protobuf_hello_service_interface_proto = out.File File_skills_rpc_protobuf_hello_service_interface_proto = out.File

View File

@ -3,16 +3,44 @@ syntax = "proto3";
package hello; package hello;
option go_package="122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service"; option go_package="122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service";
// proto文件, ipmort用法
import "google/protobuf/any.proto";
// The HelloService service definition. // The HelloService service definition.
service HelloService { service HelloService {
// rpc // rpc
rpc Hello (Request) returns (Response); rpc Hello (Request) returns (Response);
rpc Channel (stream Request) returns (stream Response) {}
} }
message Request { message Request {
string value = 1; string value = 1;
// map
map<string, string> extras = 2;
}
message RequestSet {
int64 total = 1;
// repeated
repeated Request items = 2;
} }
message Response { message Response {
string value = 1; string value = 1;
} }
enum Corpus {
UNIVERSAL = 0;
WEB = 1;
IMAGES = 2;
LOCAL = 3;
NEWS = 4;
PRODUCTS = 5;
VIDEO = 6;
}
message ErrorStatus {
string message = 1;
repeated google.protobuf.Any details = 2;
}

View File

@ -8,7 +8,6 @@ package hello_service
import ( import (
context "context" context "context"
grpc "google.golang.org/grpc" grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes" codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status" status "google.golang.org/grpc/status"
@ -20,7 +19,8 @@ import (
const _ = grpc.SupportPackageIsVersion9 const _ = grpc.SupportPackageIsVersion9
const ( const (
HelloService_Hello_FullMethodName = "/hello.HelloService/Hello" HelloService_Hello_FullMethodName = "/hello.HelloService/Hello"
HelloService_Channel_FullMethodName = "/hello.HelloService/Channel"
) )
// HelloServiceClient is the client API for HelloService service. // HelloServiceClient is the client API for HelloService service.
@ -31,6 +31,7 @@ const (
type HelloServiceClient interface { type HelloServiceClient interface {
// rpc 声明接口 // rpc 声明接口
Hello(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) Hello(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error)
Channel(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Request, Response], error)
} }
type helloServiceClient struct { type helloServiceClient struct {
@ -51,6 +52,19 @@ func (c *helloServiceClient) Hello(ctx context.Context, in *Request, opts ...grp
return out, nil return out, nil
} }
func (c *helloServiceClient) Channel(ctx context.Context, opts ...grpc.CallOption) (grpc.BidiStreamingClient[Request, Response], error) {
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
stream, err := c.cc.NewStream(ctx, &HelloService_ServiceDesc.Streams[0], HelloService_Channel_FullMethodName, cOpts...)
if err != nil {
return nil, err
}
x := &grpc.GenericClientStream[Request, Response]{ClientStream: stream}
return x, nil
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type HelloService_ChannelClient = grpc.BidiStreamingClient[Request, Response]
// HelloServiceServer is the server API for HelloService service. // HelloServiceServer is the server API for HelloService service.
// All implementations must embed UnimplementedHelloServiceServer // All implementations must embed UnimplementedHelloServiceServer
// for forward compatibility. // for forward compatibility.
@ -59,6 +73,7 @@ func (c *helloServiceClient) Hello(ctx context.Context, in *Request, opts ...grp
type HelloServiceServer interface { type HelloServiceServer interface {
// rpc 声明接口 // rpc 声明接口
Hello(context.Context, *Request) (*Response, error) Hello(context.Context, *Request) (*Response, error)
Channel(grpc.BidiStreamingServer[Request, Response]) error
mustEmbedUnimplementedHelloServiceServer() mustEmbedUnimplementedHelloServiceServer()
} }
@ -72,6 +87,9 @@ type UnimplementedHelloServiceServer struct{}
func (UnimplementedHelloServiceServer) Hello(context.Context, *Request) (*Response, error) { func (UnimplementedHelloServiceServer) Hello(context.Context, *Request) (*Response, error) {
return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented") return nil, status.Errorf(codes.Unimplemented, "method Hello not implemented")
} }
func (UnimplementedHelloServiceServer) Channel(grpc.BidiStreamingServer[Request, Response]) error {
return status.Errorf(codes.Unimplemented, "method Channel not implemented")
}
func (UnimplementedHelloServiceServer) mustEmbedUnimplementedHelloServiceServer() {} func (UnimplementedHelloServiceServer) mustEmbedUnimplementedHelloServiceServer() {}
func (UnimplementedHelloServiceServer) testEmbeddedByValue() {} func (UnimplementedHelloServiceServer) testEmbeddedByValue() {}
@ -111,6 +129,13 @@ func _HelloService_Hello_Handler(srv interface{}, ctx context.Context, dec func(
return interceptor(ctx, in, info, handler) return interceptor(ctx, in, info, handler)
} }
func _HelloService_Channel_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(HelloServiceServer).Channel(&grpc.GenericServerStream[Request, Response]{ServerStream: stream})
}
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
type HelloService_ChannelServer = grpc.BidiStreamingServer[Request, Response]
// HelloService_ServiceDesc is the grpc.ServiceDesc for HelloService service. // HelloService_ServiceDesc is the grpc.ServiceDesc for HelloService service.
// It's only intended for direct use with grpc.RegisterService, // It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy) // and not to be introspected or modified (even as a copy)
@ -123,6 +148,13 @@ var HelloService_ServiceDesc = grpc.ServiceDesc{
Handler: _HelloService_Hello_Handler, Handler: _HelloService_Hello_Handler,
}, },
}, },
Streams: []grpc.StreamDesc{}, Streams: []grpc.StreamDesc{
{
StreamName: "Channel",
Handler: _HelloService_Channel_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "skills/rpc/protobuf/hello_service/interface.proto", Metadata: "skills/rpc/protobuf/hello_service/interface.proto",
} }

View File

@ -0,0 +1,35 @@
package hello_service_test
import (
"testing"
"122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service"
"google.golang.org/protobuf/types/known/anypb"
)
func TestAny(t *testing.T) {
status := hello_service.ErrorStatus{
Details: []*anypb.Any{},
}
d1 := hello_service.Request{Value: "test"}
any1, err := anypb.New(&d1)
if err != nil {
t.Fatal(err)
}
d2 := hello_service.Response{Value: "test"}
any2, err := anypb.New(&d2)
if err != nil {
t.Fatal(err)
}
status.Details = append(status.Details, any1, any2)
t.Log(status)
target := hello_service.Request{}
if err := status.Details[0].UnmarshalTo(&target); err != nil {
t.Fatal(err)
}
t.Log(target.Value)
}

View File

@ -0,0 +1,90 @@
package hello_service
import (
context "context"
"fmt"
"github.com/infraboard/mcube/v2/ioc/config/log"
"github.com/rs/zerolog"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
status "google.golang.org/grpc/status"
)
const (
ClientHeaderKey = "client-id"
ClientSecretKey = "client-secret"
)
// GrpcAuthUnaryServerInterceptor returns a new unary server interceptor for auth.
func GrpcAuthUnaryServerInterceptor() grpc.UnaryServerInterceptor {
return newGrpcAuther().Auth
}
func newGrpcAuther() *grpcAuther {
return &grpcAuther{
log: log.Sub("Grpc Auther"),
}
}
// UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info
// contains all the information of this RPC the interceptor can operate on. And handler is the wrapper
// of the service method implementation. It is the responsibility of the interceptor to invoke handler
// to complete the RPC.
// type UnaryServerInterceptor func(ctx context.Context, req any, info *UnaryServerInfo, handler UnaryHandler) (resp any, err error)
// internal todo
type grpcAuther struct {
log *zerolog.Logger
}
func (a *grpcAuther) Auth(
ctx context.Context, req any,
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp any, err error) {
// http2 header -> metadata
// 重上下文中获取认证信息
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("ctx is not an grpc incoming context")
}
fmt.Println("gprc header info: ", md)
clientId, clientSecret := a.GetClientCredentialsFromMeta(md)
// 校验调用的客户端凭证是否有效
if err := a.validateServiceCredential(clientId, clientSecret); err != nil {
return nil, err
}
// 把请求交给后续的Handler处理
resp, err = handler(ctx, req)
return resp, err
}
func (a *grpcAuther) GetClientCredentialsFromMeta(md metadata.MD) (
clientId, clientSecret string) {
cids := md.Get(ClientHeaderKey)
sids := md.Get(ClientSecretKey)
if len(cids) > 0 {
clientId = cids[0]
}
if len(sids) > 0 {
clientSecret = sids[0]
}
return
}
func (a *grpcAuther) validateServiceCredential(clientId, clientSecret string) error {
if clientId == "" && clientSecret == "" {
return status.Errorf(codes.Unauthenticated, "client_id or client_secret is \"\"")
}
if !(clientId == "admin" && clientSecret == "123456") {
return status.Errorf(codes.Unauthenticated, "client_id or client_secret invalidate")
}
return nil
}

View File

@ -2,6 +2,7 @@ package main
import ( import (
"context" "context"
"io"
"log" "log"
"net" "net"
@ -11,7 +12,8 @@ import (
func main() { func main() {
// 首先是通过grpc.NewServer()构造一个gRPC服务对象 // 首先是通过grpc.NewServer()构造一个gRPC服务对象
grpcServer := grpc.NewServer() // 补充了全局的认证中间件
grpcServer := grpc.NewServer(grpc.ChainUnaryInterceptor(hello_service.GrpcAuthUnaryServerInterceptor()))
// SDK 提供 服务实现对象的注册 // SDK 提供 服务实现对象的注册
hello_service.RegisterHelloServiceServer(grpcServer, &HelloService{}) hello_service.RegisterHelloServiceServer(grpcServer, &HelloService{})
@ -38,3 +40,24 @@ func (h *HelloService) Hello(ctx context.Context, req *hello_service.Request) (*
Value: "Hello " + req.Value, Value: "Hello " + req.Value,
}, nil }, nil
} }
// 接收来自客户端的流式请求,然后不断返回
func (h *HelloService) Channel(stream grpc.BidiStreamingServer[hello_service.Request, hello_service.Response]) error {
for {
// 读取客户端发送过来的数据
msg, err := stream.Recv()
if err != nil {
// 如果遇到io.EOF表示客户端流被关闭
if err == io.EOF {
return nil
}
return err
}
// 处理消息并返回响应
if err := stream.Send(&hello_service.Response{
Value: "Hello " + msg.Value,
}); err != nil {
return err
}
}
}

View File

@ -3,7 +3,9 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"io"
"log" "log"
"time"
"122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service" "122.51.31.227/go-course/go18/skills/rpc/protobuf/hello_service"
"google.golang.org/grpc" "google.golang.org/grpc"
@ -12,7 +14,12 @@ import (
func main() { func main() {
// grpc.Dial负责和gRPC服务建立链接 // grpc.Dial负责和gRPC服务建立链接
conn, err := grpc.NewClient("localhost:1234", grpc.WithTransportCredentials(insecure.NewCredentials())) conn, err := grpc.NewClient("localhost:1234",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithPerRPCCredentials(hello_service.NewClientAuthentication(
"admin",
"123456",
)))
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -27,4 +34,33 @@ func main() {
panic(err) panic(err)
} }
fmt.Println(resp.Value) fmt.Println(resp.Value)
stream, err := helloServiceClient.Channel(context.Background())
if err != nil {
panic(err)
}
// 首先是向服务端发送数据
go func() {
count := 1
for {
if err := stream.Send(&hello_service.Request{Value: fmt.Sprintf("[%d] hi", count)}); err != nil {
log.Fatal(err)
}
count++
time.Sleep(time.Second)
}
}()
// 然后在循环中接收服务端返回的数据
for {
reply, err := stream.Recv()
if err != nil {
if err == io.EOF {
break
}
log.Fatal(err)
}
fmt.Println(reply.GetValue())
}
} }