bind_item.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package mqtt_binding
  2. import (
  3. "git.sxidc.com/go-framework/baize/framework/core/domain"
  4. "git.sxidc.com/go-framework/baize/framework/core/infrastructure"
  5. "git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger"
  6. "git.sxidc.com/go-framework/baize/framework/core/mqtt_api"
  7. "git.sxidc.com/go-framework/baize/framework/core/mqtt_api/mqtt_request"
  8. "git.sxidc.com/go-framework/baize/framework/core/mqtt_api/mqtt_response"
  9. "git.sxidc.com/go-tools/utils/reflectutils"
  10. "git.sxidc.com/go-tools/utils/strutils"
  11. "github.com/pkg/errors"
  12. "reflect"
  13. "strings"
  14. )
  15. // ResponseIdentifierFunc 获取响应标识符的函数
  16. // 参数:
  17. // - c: 上下文
  18. // - params: 请求参数
  19. // - objects: 基于请求参数构造出的领域对象
  20. // - i: 基础设施
  21. // 返回值:
  22. // - 响应标识符
  23. // - 错误
  24. type ResponseIdentifierFunc func(c *mqtt_api.Context, params any) (string, error)
  25. // FormDomainObjectsFunc 构造领域对象函数类型
  26. // 参数:
  27. // - c: 上下文
  28. // - params: 请求参数
  29. // 返回值:
  30. // - 基于请求参数构造的领域对象,回传到ServiceFunc的objects参数
  31. // - 错误
  32. type FormDomainObjectsFunc func(c *mqtt_api.Context, params any) ([]domain.Object, error)
  33. // ServiceFunc 服务函数(业务逻辑函数)
  34. // 类型参数:
  35. // - O: 响应数据类型,对应response.SendResponseFunc的data的类型
  36. // 参数:
  37. // - c: 上下文
  38. // - params: 请求参数
  39. // - objects: 基于请求参数构造出的领域对象
  40. // - i: 基础设施
  41. // 返回值:
  42. // - 响应数据
  43. // - 错误
  44. type ServiceFunc[O any] func(c *mqtt_api.Context, params any, objects []domain.Object, i *infrastructure.Infrastructure) (O, error)
  45. // Bind 通用绑定
  46. // 类型参数:
  47. // - O: 响应数据类型,对应response.SendResponseFunc的data的类型
  48. // 参数:
  49. // - binder: 用来执行绑定的binder
  50. // - item: 执行绑定的参数
  51. // - responseIdentifier: 全局响应标识符
  52. // - middlewares: 该绑定的中间件
  53. func Bind[O any](binder *Binder, item *BindItem[O], middlewares ...Middleware) {
  54. item.bind(binder, middlewares...)
  55. }
  56. // BindItem 通用BindItem
  57. type BindItem[O any] struct {
  58. // 相对主题
  59. Topic string
  60. // 响应泛型函数,如果不响应,需要使用NoResponse零值占位
  61. SendResponseFunc mqtt_response.SendResponseFunc[O]
  62. // 使用的请求参数,非必传,当请求参数为nil时,说明该接口没有参数
  63. RequestParams any
  64. // 获取响应标识符的函数
  65. ResponseIdentifierFunc ResponseIdentifierFunc
  66. // 通过请求参数构造使用的领域对象,之后在ServiceFunc中会按照构造实体的顺序进行回调
  67. // 非必传,如果该字段为nil,则说明没有领域对象
  68. // 与Objects字段二选一使用,如果都指定,会按照该字段处理
  69. FormDomainObjectsFunc FormDomainObjectsFunc
  70. // 使用的领域对象,当使用Tag对实体进行标注后,可以直接通过该字段给定实体,之后在ServiceFunc中会按照给定实体的顺序进行回调
  71. // 非必传,如果为nil或长度为0,则说明没有领域对象
  72. // 与FormObjectsFunc字段二选一使用,如果都指定,会按照FormObjectsFunc字段处理
  73. Objects []domain.Object
  74. // 应用服务泛型函数
  75. ServiceFunc ServiceFunc[O]
  76. }
  77. func (item *BindItem[O]) bind(binder *Binder, middlewares ...Middleware) {
  78. if strutils.IsStringEmpty(item.Topic) {
  79. panic("需要指定主题")
  80. }
  81. if item.SendResponseFunc == nil {
  82. panic("需要指定响应函数")
  83. }
  84. if item.ServiceFunc == nil {
  85. panic("需要指定应用服务函数")
  86. }
  87. var outputZero O
  88. outputZeroValue := reflect.ValueOf(outputZero)
  89. if outputZeroValue.IsValid() && outputZeroValue.Kind() == reflect.Pointer {
  90. panic("bind的输出类型不能使用指针类型")
  91. }
  92. if outputZeroValue.IsValid() && strings.Contains(outputZeroValue.String(), "mqtt_response.InfosData") {
  93. infosField := outputZeroValue.FieldByName("Infos")
  94. if infosField.IsValid() && infosField.Type().Elem().Kind() == reflect.Pointer {
  95. panic("bind的输出类型不能使用指针类型")
  96. }
  97. }
  98. apiMiddlewares := make([]mqtt_api.Handler, len(middlewares))
  99. for i, middleware := range middlewares {
  100. innerMiddleware := middleware
  101. apiMiddlewares[i] = func(c *mqtt_api.Context) {
  102. innerMiddleware(c, binder.i)
  103. }
  104. }
  105. handlers := append(apiMiddlewares, func(c *mqtt_api.Context) {
  106. var params any
  107. var responseIdentifier string
  108. // 有请求数据
  109. if item.RequestParams != nil {
  110. requestParamsType := reflect.TypeOf(item.RequestParams)
  111. if !reflectutils.IsTypeStructOrStructPointer(requestParamsType) {
  112. err := errors.New("请求参数不是结构或结构指针")
  113. logger.GetInstance().Error(err)
  114. item.SendResponseFunc(c, responseIdentifier, outputZero, err)
  115. return
  116. }
  117. if requestParamsType.Kind() == reflect.Pointer {
  118. params = reflect.New(requestParamsType.Elem()).Interface()
  119. } else {
  120. params = reflect.New(requestParamsType).Interface()
  121. }
  122. // 将请求数据解析到请求参数中
  123. err := mqtt_request.BindingJson(c, params)
  124. if err != nil {
  125. logger.GetInstance().Error(err)
  126. item.SendResponseFunc(c, responseIdentifier, outputZero, err)
  127. return
  128. }
  129. }
  130. if item.ResponseIdentifierFunc != nil {
  131. newResponseIdentifier, err := item.ResponseIdentifierFunc(c, params)
  132. if err != nil {
  133. logger.GetInstance().Error(err)
  134. item.SendResponseFunc(c, responseIdentifier, outputZero, err)
  135. return
  136. }
  137. responseIdentifier = newResponseIdentifier
  138. }
  139. // 进行领域对象转化
  140. var domainObjects []domain.Object
  141. if item.FormDomainObjectsFunc != nil {
  142. innerDomainObjects, err := item.FormDomainObjectsFunc(c, params)
  143. if err != nil {
  144. item.SendResponseFunc(c, responseIdentifier, outputZero, err)
  145. return
  146. }
  147. domainObjects = innerDomainObjects
  148. } else {
  149. if item.Objects != nil && len(item.Objects) != 0 {
  150. for _, object := range item.Objects {
  151. if object == nil {
  152. continue
  153. }
  154. objectType := reflect.TypeOf(object)
  155. if !reflectutils.IsTypeStructOrStructPointer(objectType) {
  156. item.SendResponseFunc(c, responseIdentifier, outputZero, errors.New("领域对象不是结构或结构指针"))
  157. return
  158. }
  159. obj := reflect.New(reflectutils.PointerTypeElem(objectType)).Interface().(domain.Object)
  160. if params != nil {
  161. err := mqtt_request.AssignRequestParamsToDomainObject(params, obj)
  162. if err != nil {
  163. item.SendResponseFunc(c, responseIdentifier, outputZero, err)
  164. return
  165. }
  166. }
  167. domainObjects = append(domainObjects, obj)
  168. }
  169. }
  170. }
  171. // 执行业务函数
  172. outputModel, err := item.ServiceFunc(c, params, domainObjects, binder.i)
  173. // 发送响应
  174. item.SendResponseFunc(c, responseIdentifier, outputModel, err)
  175. return
  176. })
  177. // 所有的函数加入到执行链中
  178. err := binder.router.AddTopic(item.Topic, handlers...)
  179. if err != nil {
  180. panic("添加主题" + item.Topic + "失败")
  181. }
  182. }