route.go 2.9 KB

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