route.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package handler
  2. import (
  3. "fmt"
  4. http2 "net/http"
  5. "git.ikuban.com/server/kratos-utils/v2/transport/middleware"
  6. ku_annotations "git.ikuban.com/server/kubanapis/kuban/api/annotations"
  7. "github.com/go-kratos/kratos/v2/transport/http"
  8. openapi_v3 "github.com/google/gnostic/openapiv3"
  9. "github.com/jhump/protoreflect/desc"
  10. "github.com/jhump/protoreflect/grpcreflect"
  11. "google.golang.org/genproto/googleapis/api/annotations"
  12. "google.golang.org/grpc"
  13. "google.golang.org/protobuf/proto"
  14. )
  15. func RegisterRoute(s *http.Server, srv any, svcDesc grpc.ServiceDesc, baseUrl string) {
  16. r := s.Route("/api/")
  17. if baseUrl != "" {
  18. r = s.Route(baseUrl)
  19. }
  20. // 加载完整的服务描述符
  21. fullSvcDesc, err := grpcreflect.LoadServiceDescriptor(&svcDesc)
  22. if err != nil {
  23. panic(fmt.Sprintf("加载服务描述符失败 err:%v", err))
  24. }
  25. // 注册一元方法handler
  26. for _, md := range svcDesc.Methods {
  27. // 获取方法option
  28. option := GetOptionByServiceDescriptor(fullSvcDesc, svcDesc.ServiceName, md.MethodName)
  29. // 跳过不需要生成http方法的
  30. if !option.GenHttp {
  31. continue
  32. }
  33. // 注册http接口
  34. r.Handle(option.Method, option.Path, unaryHandler(srv, md, option))
  35. }
  36. // 注册流式方法handler
  37. for _, std := range svcDesc.Streams {
  38. // 获取方法option
  39. option := GetOptionByServiceDescriptor(fullSvcDesc, svcDesc.ServiceName, std.StreamName)
  40. // 跳过不需要生成http方法的
  41. if !option.GenHttp {
  42. continue
  43. }
  44. switch {
  45. case std.ClientStreams && std.ServerStreams:
  46. // 双向流
  47. case std.ClientStreams && !std.ServerStreams:
  48. // 客户端流
  49. case !std.ClientStreams && std.ServerStreams:
  50. // 服务端流
  51. r.POST(option.Path, serverStreamHandler(srv, std, option))
  52. }
  53. }
  54. }
  55. func GetOptionByServiceDescriptor(sd *desc.ServiceDescriptor, serviceName, methodName string) *middleware.Option {
  56. // 获取方法描述符
  57. md := sd.FindMethodByName(methodName)
  58. if md == nil {
  59. panic(fmt.Sprintf("未找到方法描述符 service:%v, method:%v", serviceName, methodName))
  60. }
  61. // option
  62. option := &middleware.Option{}
  63. // 获取方法option
  64. methodOptions := md.GetMethodOptions()
  65. operation := proto.GetExtension(methodOptions, openapi_v3.E_Operation).(*openapi_v3.Operation)
  66. if operation == nil {
  67. // 跳过不需要生成http方法的
  68. option.GenHttp = false
  69. return option
  70. }
  71. option.GenHttp = true
  72. // 不需要认证的
  73. if len(operation.Security) == 0 {
  74. option.NotAuth = true
  75. } else {
  76. if len(operation.Security[0].AdditionalProperties) != 0 {
  77. option.AuthorizationsName = operation.Security[0].AdditionalProperties[0].Name
  78. }
  79. }
  80. // 解析自定义option [操作记录]
  81. customOptions := proto.GetExtension(methodOptions, ku_annotations.E_Options).(*ku_annotations.Options)
  82. if customOptions.GetOperationRecord().GetEnabled() {
  83. option.OperationRecord = true
  84. }
  85. // 路由
  86. rule := proto.GetExtension(methodOptions, annotations.E_Http).(*annotations.HttpRule)
  87. if rule != nil {
  88. switch httpRule := rule.GetPattern().(type) {
  89. case *annotations.HttpRule_Post:
  90. option.Path = httpRule.Post
  91. option.Method = http2.MethodPost
  92. case *annotations.HttpRule_Get:
  93. option.Path = httpRule.Get
  94. option.Method = http2.MethodGet
  95. case *annotations.HttpRule_Delete:
  96. option.Path = httpRule.Delete
  97. option.Method = http2.MethodDelete
  98. case *annotations.HttpRule_Put:
  99. option.Path = httpRule.Put
  100. option.Method = http2.MethodPut
  101. }
  102. }
  103. if option.Path == "" {
  104. option.Path = fmt.Sprintf("/%s/%s", serviceName, methodName)
  105. }
  106. if option.Method == "" {
  107. option.Method = http2.MethodPost
  108. }
  109. return option
  110. }