route.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  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. }
  76. // 解析自定义option [操作记录]
  77. customOptions := proto.GetExtension(methodOptions, ku_annotations.E_Options).(*ku_annotations.Options)
  78. if customOptions.GetOperationRecord().GetEnabled() {
  79. option.OperationRecord = true
  80. }
  81. // 路由
  82. rule := proto.GetExtension(methodOptions, annotations.E_Http).(*annotations.HttpRule)
  83. if rule != nil {
  84. switch httpRule := rule.GetPattern().(type) {
  85. case *annotations.HttpRule_Post:
  86. option.Path = httpRule.Post
  87. option.Method = http2.MethodPost
  88. case *annotations.HttpRule_Get:
  89. option.Path = httpRule.Get
  90. option.Method = http2.MethodGet
  91. case *annotations.HttpRule_Delete:
  92. option.Path = httpRule.Delete
  93. option.Method = http2.MethodDelete
  94. case *annotations.HttpRule_Put:
  95. option.Path = httpRule.Put
  96. option.Method = http2.MethodPut
  97. }
  98. }
  99. if option.Path == "" {
  100. option.Path = fmt.Sprintf("/%s/%s", serviceName, methodName)
  101. }
  102. if option.Method == "" {
  103. option.Method = http2.MethodPost
  104. }
  105. return option
  106. }