kis-flow/kis/faas.go

82 lines
1.9 KiB
Go
Raw Normal View History

2024-03-19 19:16:03 +08:00
package kis
import (
"errors"
"fmt"
"reflect"
"runtime"
)
// FaaS Function as a Service
// type FaaS func(context.Context, *kisflow, ...interface{}) error
// 这是一个方法类型,会在注入时在方法内判断
type FaaS interface{}
type FaaSDesc struct {
FnName string
f interface{}
fName string
ArgsType []reflect.Type
ArgNum int
FuncType reflect.Type
FuncValue reflect.Value
FaasSerialize
}
var globalFaaSSerialize = &DefaultFaasSerialize{}
func NewFaaSDesc(fnName string, f FaaS) (*FaaSDesc, error) {
funcValue := reflect.ValueOf(f)
funcType := funcValue.Type()
if err := validateFuncType(funcType, funcValue); err != nil {
return nil, err
}
argsType := make([]reflect.Type, funcType.NumIn())
fullName := runtime.FuncForPC(funcValue.Pointer()).Name()
containsKisflowCtx := false
for i := 0; i < funcType.NumIn(); i++ {
paramType := funcType.In(i)
if isFlowType(paramType) {
containsKisflowCtx = true
}
argsType[i] = paramType
}
if !containsKisflowCtx {
return nil, errors.New("function parameters must have Kisflow context")
}
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")
}
// Check if f implements FaasSerialize interface
var serializeImpl FaasSerialize
if ser, ok := f.(FaasSerialize); ok {
serializeImpl = ser
} else {
serializeImpl = globalFaaSSerialize // Use global default implementation
}
return &FaaSDesc{
FnName: fnName,
f: f,
fName: fullName,
ArgsType: argsType,
ArgNum: len(argsType),
FuncType: funcType,
FuncValue: funcValue,
FaasSerialize: serializeImpl,
}, nil
}
func validateFuncType(funcType reflect.Type, funcValue reflect.Value) error {
if funcType.Kind() != reflect.Func {
return fmt.Errorf("provided FaaS type is %s, not a function", funcType.Name())
}
return nil
}