|
|
@@ -0,0 +1,106 @@
|
|
|
+package handler
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "git.ikuban.com/server/kratos-utils/v2/http/middleware"
|
|
|
+ ku_annotations "git.ikuban.com/server/kubanapis/kuban/api/annotations"
|
|
|
+ "github.com/go-kratos/kratos/v2/transport/http"
|
|
|
+ openapi_v3 "github.com/google/gnostic/openapiv3"
|
|
|
+ "github.com/jhump/protoreflect/desc"
|
|
|
+ "github.com/jhump/protoreflect/grpcreflect"
|
|
|
+ "google.golang.org/genproto/googleapis/api/annotations"
|
|
|
+ "google.golang.org/grpc"
|
|
|
+ "google.golang.org/protobuf/proto"
|
|
|
+)
|
|
|
+
|
|
|
+func RegisterRoute(s *http.Server, srv any, svcDesc grpc.ServiceDesc) {
|
|
|
+ r := s.Route("/api/")
|
|
|
+
|
|
|
+ // 加载完整的服务描述符
|
|
|
+ fullSvcDesc, err := grpcreflect.LoadServiceDescriptor(&svcDesc)
|
|
|
+ if err != nil {
|
|
|
+ panic(fmt.Sprintf("加载服务描述符失败 err:%v", err))
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册一元方法handler
|
|
|
+ for _, md := range svcDesc.Methods {
|
|
|
+ // 获取方法option
|
|
|
+ option := GetOptionByServiceDescriptor(fullSvcDesc, svcDesc.ServiceName, md.MethodName)
|
|
|
+ // 跳过不需要生成http方法的
|
|
|
+ if !option.GenHttp {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册http接口
|
|
|
+ r.POST(option.Path, unaryHandler(srv, md, option))
|
|
|
+ }
|
|
|
+
|
|
|
+ // 注册流式方法handler
|
|
|
+ for _, std := range svcDesc.Streams {
|
|
|
+
|
|
|
+ // 获取方法option
|
|
|
+ option := GetOptionByServiceDescriptor(fullSvcDesc, svcDesc.ServiceName, std.StreamName)
|
|
|
+ // 跳过不需要生成http方法的
|
|
|
+ if !option.GenHttp {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ switch {
|
|
|
+ case std.ClientStreams && std.ServerStreams:
|
|
|
+ // 双向流
|
|
|
+
|
|
|
+ case std.ClientStreams && !std.ServerStreams:
|
|
|
+ // 客户端流
|
|
|
+
|
|
|
+ case !std.ClientStreams && std.ServerStreams:
|
|
|
+ // 服务端流
|
|
|
+ r.POST(option.Path, serverStreamHandler(srv, std, option))
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func GetOptionByServiceDescriptor(sd *desc.ServiceDescriptor, serviceName, methodName string) *middleware.Option {
|
|
|
+ // 获取方法描述符
|
|
|
+ md := sd.FindMethodByName(methodName)
|
|
|
+ if md == nil {
|
|
|
+ panic(fmt.Sprintf("未找到方法描述符 service:%v, method:%v", serviceName, methodName))
|
|
|
+ }
|
|
|
+
|
|
|
+ // option
|
|
|
+ option := &middleware.Option{}
|
|
|
+
|
|
|
+ // 获取方法option
|
|
|
+ methodOptions := md.GetMethodOptions()
|
|
|
+ operation := proto.GetExtension(methodOptions, openapi_v3.E_Operation).(*openapi_v3.Operation)
|
|
|
+ if operation == nil {
|
|
|
+ // 跳过不需要生成http方法的
|
|
|
+ option.GenHttp = false
|
|
|
+ return option
|
|
|
+ }
|
|
|
+ option.GenHttp = true
|
|
|
+
|
|
|
+ // 不需要认证的
|
|
|
+ if len(operation.Security) == 0 {
|
|
|
+ option.NotAuth = true
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析自定义option [操作记录]
|
|
|
+ customOptions := proto.GetExtension(methodOptions, ku_annotations.E_Options).(*ku_annotations.Options)
|
|
|
+ if customOptions.GetOperationRecord().GetEnabled() {
|
|
|
+ option.OperationRecord = true
|
|
|
+ }
|
|
|
+
|
|
|
+ // 路由
|
|
|
+ rule := proto.GetExtension(methodOptions, annotations.E_Http).(*annotations.HttpRule)
|
|
|
+ if rule != nil {
|
|
|
+ switch httpRule := rule.GetPattern().(type) {
|
|
|
+ case *annotations.HttpRule_Post:
|
|
|
+ option.Path = httpRule.Post
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if option.Path == "" {
|
|
|
+ option.Path = fmt.Sprintf("/%s/%s", serviceName, methodName)
|
|
|
+ }
|
|
|
+
|
|
|
+ return option
|
|
|
+}
|