kis-flow/kis/faas.go

155 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package kis
import (
"errors"
"fmt"
"reflect"
"runtime"
"strings"
)
// FaaS Function as a Service
// 将
// type FaaS func(context.Context, Flow) error
// 改为
// type FaaS func(context.Context, Flow, ...interface{}) error
// 可以通过可变参数的任意输入类型进行数据传递
type FaaS interface{}
// FaaSDesc FaaS 回调计算业务函数 描述
type FaaSDesc struct {
Serialize // 当前Function的数据输入输出序列化实现
FnName string // Function名称
f interface{} // FaaS 函数
fName string // 函数名称
ArgsType []reflect.Type // 函数参数类型(集合)
ArgNum int // 函数参数个数
FuncType reflect.Type // 函数类型
FuncValue reflect.Value // 函数值(函数地址)
}
// NewFaaSDesc 根据用户注册的FnName 和FaaS 回调函数,创建 FaaSDesc 描述实例
func NewFaaSDesc(fnName string, f FaaS) (*FaaSDesc, error) {
// 输入输出序列化实例
var serializeImpl Serialize
// 传入的回调函数FaaS,函数值(函数地址)
funcValue := reflect.ValueOf(f)
// 传入的回调函数FaaS 类型
funcType := funcValue.Type()
// 判断传递的FaaS指针是否是函数类型
if !isFuncType(funcType) {
return nil, fmt.Errorf("provided FaaS type is %s, not a function", funcType.Name())
}
// 判断传递的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函数的参数类型集合
argsType := make([]reflect.Type, funcType.NumIn())
// 获取FaaS的函数名称
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
// 遍历FaaS的形参类型
for i := 0; i < funcType.NumIn(); i++ {
// 取出第i个形式参数类型
paramType := funcType.In(i)
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
}
// 将当前形参类型追加到argsType集合中
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]")
}
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]")
}
// 返回FaaSDesc描述实例
return &FaaSDesc{
Serialize: serializeImpl,
FnName: fnName,
f: f,
fName: fullName,
ArgsType: argsType,
ArgNum: len(argsType),
FuncType: funcType,
FuncValue: funcValue,
}, 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
}