kis-flow/kis/faas.go

155 lines
4.7 KiB
Go
Raw Normal View History

2024-03-19 19:16:03 +08:00
package kis
import (
"errors"
"fmt"
"reflect"
"runtime"
"strings"
2024-03-19 19:16:03 +08:00
)
// FaaS Function as a Service
// 将
// type FaaS func(context.Context, Flow) error
// 改为
// type FaaS func(context.Context, Flow, ...interface{}) error
// 可以通过可变参数的任意输入类型进行数据传递
2024-03-19 19:16:03 +08:00
type FaaS interface{}
// FaaSDesc FaaS 回调计算业务函数 描述
2024-03-19 19:16:03 +08:00
type FaaSDesc struct {
Serialize // 当前Function的数据输入输出序列化实现
FnName string // Function名称
f interface{} // FaaS 函数
fName string // 函数名称
ArgsType []reflect.Type // 函数参数类型(集合)
ArgNum int // 函数参数个数
FuncType reflect.Type // 函数类型
FuncValue reflect.Value // 函数值(函数地址)
2024-03-19 19:16:03 +08:00
}
// NewFaaSDesc 根据用户注册的FnName 和FaaS 回调函数,创建 FaaSDesc 描述实例
2024-03-19 19:16:03 +08:00
func NewFaaSDesc(fnName string, f FaaS) (*FaaSDesc, error) {
// 输入输出序列化实例
var serializeImpl Serialize
// 传入的回调函数FaaS,函数值(函数地址)
2024-03-19 19:16:03 +08:00
funcValue := reflect.ValueOf(f)
// 传入的回调函数FaaS 类型
2024-03-19 19:16:03 +08:00
funcType := funcValue.Type()
// 判断传递的FaaS指针是否是函数类型
if !isFuncType(funcType) {
return nil, fmt.Errorf("provided FaaS type is %s, not a function", funcType.Name())
2024-03-19 19:16:03 +08:00
}
// 判断传递的FaaS函数是否有返回值类型是只包括(error)
if funcType.NumOut() != 1 || funcType.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
return nil, errors.New("function must have exactly one return value of type error")
}
// FaaS函数的参数类型集合
2024-03-19 19:16:03 +08:00
argsType := make([]reflect.Type, funcType.NumIn())
// 获取FaaS的函数名称
2024-03-19 19:16:03 +08:00
fullName := runtime.FuncForPC(funcValue.Pointer()).Name()
// 确保 FaaS func(context.Context, Flow, ...interface{}) error 形参列表存在context.Context 和 kis.Flow
// 是否包含kis.Flow类型的形参
containsKisFlow := false
// 是否包含context.Context类型的形参
containsCtx := false
2024-03-19 19:16:03 +08:00
// 遍历FaaS的形参类型
2024-03-19 19:16:03 +08:00
for i := 0; i < funcType.NumIn(); i++ {
// 取出第i个形式参数类型
2024-03-19 19:16:03 +08:00
paramType := funcType.In(i)
2024-03-19 19:16:03 +08:00
if isFlowType(paramType) {
// 判断是否包含kis.Flow类型的形参
containsKisFlow = true
} else if isContextType(paramType) {
// 判断是否包含context.Context类型的形参
containsCtx = true
} else if isSliceType(paramType) {
// 获取当前参数Slice的元素类型
itemType := paramType.Elem()
// 如果当前参数是一个指针类型,则获取指针指向的结构体类型
if itemType.Kind() == reflect.Ptr {
itemType = itemType.Elem() // 获取指针指向的结构体类型
}
// Check if f implements Serialize interface
// (检测传递的FaaS函数是否实现了Serialize接口)
if isSerialize(itemType) {
// 如果当前形参实现了Serialize接口则使用当前形参的序列化实现
serializeImpl = reflect.New(itemType).Interface().(Serialize)
} else {
// 如果当前形参没有实现Serialize接口则使用默认的序列化实现
serializeImpl = defaultSerialize // Use global default implementation
}
} else {
// Other types are not supported
2024-03-19 19:16:03 +08:00
}
// 将当前形参类型追加到argsType集合中
2024-03-19 19:16:03 +08:00
argsType[i] = paramType
}
if !containsKisFlow {
// 不包含kis.Flow类型的形参返回错误
return nil, errors.New("function parameters must have kis.Flow param, please use FaaS type like: [type FaaS func(context.Context, Flow, ...interface{}) error]")
}
2024-03-19 19:16:03 +08:00
if !containsCtx {
// 不包含context.Context类型的形参返回错误
return nil, errors.New("function parameters must have context, please use FaaS type like: [type FaaS func(context.Context, Flow, ...interface{}) error]")
2024-03-19 19:16:03 +08:00
}
// 返回FaaSDesc描述实例
2024-03-19 19:16:03 +08:00
return &FaaSDesc{
Serialize: serializeImpl,
FnName: fnName,
f: f,
fName: fullName,
ArgsType: argsType,
ArgNum: len(argsType),
FuncType: funcType,
FuncValue: funcValue,
2024-03-19 19:16:03 +08:00
}, nil
}
// isFuncType 判断传递进来的 paramType 是否是函数类型
func isFuncType(paramType reflect.Type) bool {
return paramType.Kind() == reflect.Func
}
// isFlowType 判断传递进来的 paramType 是否是 kis.Flow 类型
func isFlowType(paramType reflect.Type) bool {
var flowInterfaceType = reflect.TypeOf((*Flow)(nil)).Elem()
return paramType.Implements(flowInterfaceType)
}
// isContextType 判断传递进来的 paramType 是否是 context.Context 类型
func isContextType(paramType reflect.Type) bool {
typeName := paramType.Name()
return strings.Contains(typeName, "Context")
}
// isSliceType 判断传递进来的 paramType 是否是切片类型
func isSliceType(paramType reflect.Type) bool {
return paramType.Kind() == reflect.Slice
2024-03-19 19:16:03 +08:00
}