|
|
@@ -0,0 +1,214 @@
|
|
|
+package mqtt_binding
|
|
|
+
|
|
|
+import (
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/domain"
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/infrastructure"
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/infrastructure/logger"
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/mqtt_api"
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/mqtt_api/request"
|
|
|
+ "git.sxidc.com/go-framework/baize/framework/core/mqtt_api/response"
|
|
|
+ "git.sxidc.com/go-tools/utils/reflectutils"
|
|
|
+ "git.sxidc.com/go-tools/utils/strutils"
|
|
|
+ "github.com/pkg/errors"
|
|
|
+ "reflect"
|
|
|
+ "strings"
|
|
|
+)
|
|
|
+
|
|
|
+// ResponseIdentifierFunc 获取响应标识符的函数
|
|
|
+// 参数:
|
|
|
+// - c: 上下文
|
|
|
+// - params: 请求参数
|
|
|
+// - objects: 基于请求参数构造出的领域对象
|
|
|
+// - i: 基础设施
|
|
|
+// 返回值:
|
|
|
+// - 响应标识符
|
|
|
+// - 错误
|
|
|
+type ResponseIdentifierFunc func(c *mqtt_api.Context, params any) (string, error)
|
|
|
+
|
|
|
+// FormDomainObjectsFunc 构造领域对象函数类型
|
|
|
+// 参数:
|
|
|
+// - c: 上下文
|
|
|
+// - params: 请求参数
|
|
|
+// 返回值:
|
|
|
+// - 基于请求参数构造的领域对象,回传到ServiceFunc的objects参数
|
|
|
+// - 错误
|
|
|
+type FormDomainObjectsFunc func(c *mqtt_api.Context, params any) ([]domain.Object, error)
|
|
|
+
|
|
|
+// ServiceFunc 服务函数(业务逻辑函数)
|
|
|
+// 类型参数:
|
|
|
+// - O: 响应数据类型,对应response.SendResponseFunc的data的类型
|
|
|
+// 参数:
|
|
|
+// - c: 上下文
|
|
|
+// - params: 请求参数
|
|
|
+// - objects: 基于请求参数构造出的领域对象
|
|
|
+// - i: 基础设施
|
|
|
+// 返回值:
|
|
|
+// - 响应数据
|
|
|
+// - 错误
|
|
|
+type ServiceFunc[O any] func(c *mqtt_api.Context, params any, objects []domain.Object, i *infrastructure.Infrastructure) (O, error)
|
|
|
+
|
|
|
+// Bind 通用绑定
|
|
|
+// 类型参数:
|
|
|
+// - O: 响应数据类型,对应response.SendResponseFunc的data的类型
|
|
|
+// 参数:
|
|
|
+// - binder: 用来执行绑定的binder
|
|
|
+// - item: 执行绑定的参数
|
|
|
+// - responseIdentifier: 全局响应标识符
|
|
|
+// - middlewares: 该绑定的中间件
|
|
|
+func Bind[O any](binder *Binder, item *BindItem[O], responseIdentifier string, middlewares ...Middleware) {
|
|
|
+ item.bind(binder, responseIdentifier, middlewares...)
|
|
|
+}
|
|
|
+
|
|
|
+// BindItem 通用BindItem
|
|
|
+type BindItem[O any] struct {
|
|
|
+ // 相对主题
|
|
|
+ Topic string
|
|
|
+
|
|
|
+ // 响应泛型函数,如果不响应,需要使用NoResponse零值占位
|
|
|
+ SendResponseFunc response.SendResponseFunc[O]
|
|
|
+
|
|
|
+ // 使用的请求参数,非必传,当请求参数为nil时,说明该接口没有参数
|
|
|
+ RequestParams any
|
|
|
+
|
|
|
+ // 获取响应标识符的函数
|
|
|
+ ResponseIdentifierFunc ResponseIdentifierFunc
|
|
|
+
|
|
|
+ // 通过请求参数构造使用的领域对象,之后在ServiceFunc中会按照构造实体的顺序进行回调
|
|
|
+ // 非必传,如果该字段为nil,则说明没有领域对象
|
|
|
+ // 与Objects字段二选一使用,如果都指定,会按照该字段处理
|
|
|
+ FormDomainObjectsFunc FormDomainObjectsFunc
|
|
|
+
|
|
|
+ // 使用的领域对象,当使用Tag对实体进行标注后,可以直接通过该字段给定实体,之后在ServiceFunc中会按照给定实体的顺序进行回调
|
|
|
+ // 非必传,如果为nil或长度为0,则说明没有领域对象
|
|
|
+ // 与FormObjectsFunc字段二选一使用,如果都指定,会按照FormObjectsFunc字段处理
|
|
|
+ Objects []domain.Object
|
|
|
+
|
|
|
+ // 应用服务泛型函数
|
|
|
+ ServiceFunc ServiceFunc[O]
|
|
|
+}
|
|
|
+
|
|
|
+func (item *BindItem[O]) bind(binder *Binder, responseIdentifier string, middlewares ...Middleware) {
|
|
|
+ if strutils.IsStringEmpty(item.Topic) {
|
|
|
+ panic("需要指定主题")
|
|
|
+ }
|
|
|
+
|
|
|
+ if item.SendResponseFunc == nil {
|
|
|
+ panic("需要指定响应函数")
|
|
|
+ }
|
|
|
+
|
|
|
+ if item.ServiceFunc == nil {
|
|
|
+ panic("需要指定应用服务函数")
|
|
|
+ }
|
|
|
+
|
|
|
+ var outputZero O
|
|
|
+ outputZeroValue := reflect.ValueOf(outputZero)
|
|
|
+ if outputZeroValue.IsValid() && outputZeroValue.Kind() == reflect.Pointer {
|
|
|
+ panic("bind的输出类型不能使用指针类型")
|
|
|
+ }
|
|
|
+
|
|
|
+ if outputZeroValue.IsValid() && strings.Contains(outputZeroValue.String(), "response.InfosData") {
|
|
|
+ infosField := outputZeroValue.FieldByName("Infos")
|
|
|
+ if infosField.IsValid() && infosField.Type().Elem().Kind() == reflect.Pointer {
|
|
|
+ panic("bind的输出类型不能使用指针类型")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ apiMiddlewares := make([]mqtt_api.Handler, len(middlewares))
|
|
|
+ for i, middleware := range middlewares {
|
|
|
+ innerMiddleware := middleware
|
|
|
+ apiMiddlewares[i] = func(c *mqtt_api.Context) {
|
|
|
+ innerMiddleware(c, binder.i)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ handlers := append(apiMiddlewares, func(c *mqtt_api.Context) {
|
|
|
+ var params any
|
|
|
+
|
|
|
+ // 有请求数据
|
|
|
+ if item.RequestParams != nil {
|
|
|
+ requestParamsType := reflect.TypeOf(item.RequestParams)
|
|
|
+ if !reflectutils.IsTypeStructOrStructPointer(requestParamsType) {
|
|
|
+ err := errors.New("请求参数不是结构或结构指针")
|
|
|
+ logger.GetInstance().Error(err)
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if requestParamsType.Kind() == reflect.Pointer {
|
|
|
+ params = reflect.New(requestParamsType.Elem()).Interface()
|
|
|
+ } else {
|
|
|
+ params = reflect.New(requestParamsType).Interface()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 将请求数据解析到请求参数中
|
|
|
+ err := request.BindingJson(c, params)
|
|
|
+ if err != nil {
|
|
|
+ logger.GetInstance().Error(err)
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if item.ResponseIdentifierFunc != nil {
|
|
|
+ newResponseIdentifier, err := item.ResponseIdentifierFunc(c, params)
|
|
|
+ if err != nil {
|
|
|
+ logger.GetInstance().Error(err)
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ responseIdentifier = newResponseIdentifier
|
|
|
+ }
|
|
|
+
|
|
|
+ // 进行领域对象转化
|
|
|
+ var domainObjects []domain.Object
|
|
|
+ if item.FormDomainObjectsFunc != nil {
|
|
|
+ innerDomainObjects, err := item.FormDomainObjectsFunc(c, params)
|
|
|
+ if err != nil {
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ domainObjects = innerDomainObjects
|
|
|
+ } else {
|
|
|
+ if item.Objects != nil && len(item.Objects) != 0 {
|
|
|
+ for _, object := range item.Objects {
|
|
|
+ if object == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ objectType := reflect.TypeOf(object)
|
|
|
+ if !reflectutils.IsTypeStructOrStructPointer(objectType) {
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, errors.New("领域对象不是结构或结构指针"))
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ obj := reflect.New(reflectutils.PointerTypeElem(objectType)).Interface().(domain.Object)
|
|
|
+
|
|
|
+ if params != nil {
|
|
|
+ err := request.AssignRequestParamsToDomainObject(params, obj)
|
|
|
+ if err != nil {
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputZero, err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ domainObjects = append(domainObjects, obj)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 执行业务函数
|
|
|
+ outputModel, err := item.ServiceFunc(c, params, domainObjects, binder.i)
|
|
|
+
|
|
|
+ // 发送响应
|
|
|
+ item.SendResponseFunc(c, responseIdentifier, outputModel, err)
|
|
|
+ return
|
|
|
+ })
|
|
|
+
|
|
|
+ // 所有的函数加入到执行链中
|
|
|
+ err := binder.router.AddTopic(item.Topic, handlers...)
|
|
|
+ if err != nil {
|
|
|
+ panic("添加主题" + item.Topic + "失败")
|
|
|
+ }
|
|
|
+}
|