You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

service.go 4.4 kB

4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package proxy
  2. import (
  3. "context"
  4. "reflect"
  5. "sync"
  6. "unicode"
  7. "unicode/utf8"
  8. ctx "github.com/opentrx/seata-golang/v2/pkg/client/base/context"
  9. "github.com/opentrx/seata-golang/v2/pkg/util/log"
  10. )
  11. var (
  12. // serviceDescriptorMap, string -> *ServiceDescriptor
  13. serviceDescriptorMap = sync.Map{}
  14. )
  15. // MethodDescriptor
  16. type MethodDescriptor struct {
  17. Method reflect.Method
  18. CallerValue reflect.Value
  19. CtxType reflect.Type
  20. ArgsType []reflect.Type
  21. ArgsNum int
  22. ReturnValuesType []reflect.Type
  23. ReturnValuesNum int
  24. }
  25. // ServiceDescriptor
  26. type ServiceDescriptor struct {
  27. Name string
  28. ReflectType reflect.Type
  29. ReflectValue reflect.Value
  30. Methods sync.Map // string -> *MethodDescriptor
  31. }
  32. // Register
  33. func Register(service interface{}, methodName string) *MethodDescriptor {
  34. serviceType := reflect.TypeOf(service)
  35. serviceValue := reflect.ValueOf(service)
  36. svcName := reflect.Indirect(serviceValue).Type().Name()
  37. svcDesc, _ := serviceDescriptorMap.LoadOrStore(svcName, &ServiceDescriptor{
  38. Name: svcName,
  39. ReflectType: serviceType,
  40. ReflectValue: serviceValue,
  41. Methods: sync.Map{},
  42. })
  43. svcDescriptor := svcDesc.(*ServiceDescriptor)
  44. methodDesc, methodExist := svcDescriptor.Methods.Load(methodName)
  45. if methodExist {
  46. methodDescriptor := methodDesc.(*MethodDescriptor)
  47. return methodDescriptor
  48. }
  49. method, methodFounded := serviceType.MethodByName(methodName)
  50. if methodFounded {
  51. methodDescriptor := describeMethod(method)
  52. if methodDescriptor != nil {
  53. methodDescriptor.CallerValue = serviceValue
  54. svcDescriptor.Methods.Store(methodName, methodDescriptor)
  55. return methodDescriptor
  56. }
  57. }
  58. return nil
  59. }
  60. // describeMethod
  61. // might return nil when method is not exported or some other error
  62. func describeMethod(method reflect.Method) *MethodDescriptor {
  63. methodType := method.Type
  64. methodName := method.Name
  65. inNum := methodType.NumIn()
  66. outNum := methodType.NumOut()
  67. // Method must be exported.
  68. if method.PkgPath != "" {
  69. return nil
  70. }
  71. var (
  72. ctxType reflect.Type
  73. argsType, returnValuesType []reflect.Type
  74. )
  75. for index := 1; index < inNum; index++ {
  76. if methodType.In(index).String() == "context.Context" {
  77. ctxType = methodType.In(index)
  78. }
  79. argsType = append(argsType, methodType.In(index))
  80. // need not be a pointer.
  81. if !isExportedOrBuiltinType(methodType.In(index)) {
  82. log.Errorf("argument type of method %q is not exported %v", methodName, methodType.In(index))
  83. return nil
  84. }
  85. }
  86. // returnValuesType
  87. for num := 0; num < outNum; num++ {
  88. returnValuesType = append(returnValuesType, methodType.Out(num))
  89. }
  90. return &MethodDescriptor{
  91. Method: method,
  92. CtxType: ctxType,
  93. ArgsType: argsType,
  94. ArgsNum: inNum,
  95. ReturnValuesType: returnValuesType,
  96. ReturnValuesNum: outNum,
  97. }
  98. }
  99. // Is this an exported - upper case - name
  100. func isExported(name string) bool {
  101. s, _ := utf8.DecodeRuneInString(name)
  102. return unicode.IsUpper(s)
  103. }
  104. // Is this type exported or a builtin?
  105. func isExportedOrBuiltinType(t reflect.Type) bool {
  106. for t.Kind() == reflect.Ptr {
  107. t = t.Elem()
  108. }
  109. // PkgPath will be non-empty even for an exported type,
  110. // so we need to check the type name as well.
  111. return isExported(t.Name()) || t.PkgPath() == ""
  112. }
  113. // Invoke
  114. func Invoke(methodDesc *MethodDescriptor, ctx *ctx.RootContext, args []interface{}) []reflect.Value {
  115. in := []reflect.Value{methodDesc.CallerValue}
  116. for i := 0; i < len(args); i++ {
  117. t := reflect.ValueOf(args[i])
  118. if methodDesc.ArgsType[i].String() == "context.Context" {
  119. t = SuiteContext(ctx, methodDesc)
  120. }
  121. if !t.IsValid() {
  122. at := methodDesc.ArgsType[i]
  123. if at.Kind() == reflect.Ptr {
  124. at = at.Elem()
  125. }
  126. t = reflect.New(at)
  127. }
  128. in = append(in, t)
  129. }
  130. returnValues := methodDesc.Method.Func.Call(in)
  131. return returnValues
  132. }
  133. func SuiteContext(ctx context.Context, methodDesc *MethodDescriptor) reflect.Value {
  134. if contextValue := reflect.ValueOf(ctx); contextValue.IsValid() {
  135. return contextValue
  136. }
  137. return reflect.Zero(methodDesc.CtxType)
  138. }
  139. func ReturnWithError(methodDesc *MethodDescriptor, err error) []reflect.Value {
  140. var result = make([]reflect.Value, 0)
  141. for i := 0; i < methodDesc.ReturnValuesNum-1; i++ {
  142. result = append(result, reflect.Zero(methodDesc.ReturnValuesType[i]))
  143. }
  144. result = append(result, reflect.ValueOf(err))
  145. return result
  146. }