mirror of
https://github.com/aceld/kis-flow.git
synced 2025-01-22 23:20:24 +08:00
151 lines
5.0 KiB
Go
151 lines
5.0 KiB
Go
package kis
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// FaaS Function as a Service
|
|
|
|
// Change the type definition from:
|
|
// type FaaS func(context.Context, Flow) error
|
|
// to:
|
|
// type FaaS func(context.Context, Flow, ...interface{}) error
|
|
// This allows passing data through variadic parameters of any type.
|
|
type FaaS interface{}
|
|
|
|
// FaaSDesc describes the FaaS callback computation function.
|
|
type FaaSDesc struct {
|
|
Serialize // Serialization implementation for the current Function's data input and output
|
|
FnName string // Function name
|
|
f interface{} // FaaS function
|
|
fName string // Function name
|
|
ArgsType []reflect.Type // Function parameter types (collection)
|
|
ArgNum int // Number of function parameters
|
|
FuncType reflect.Type // Function type
|
|
FuncValue reflect.Value // Function value (function address)
|
|
}
|
|
|
|
// NewFaaSDesc creates an instance of FaaSDesc description based on the registered FnName and FaaS callback function.
|
|
func NewFaaSDesc(fnName string, f FaaS) (*FaaSDesc, error) {
|
|
|
|
// Serialization instance
|
|
var serializeImpl Serialize
|
|
|
|
// Callback function value (function address)
|
|
funcValue := reflect.ValueOf(f)
|
|
|
|
// Callback function type
|
|
funcType := funcValue.Type()
|
|
|
|
// Check if the provided FaaS pointer is a function type
|
|
if !isFuncType(funcType) {
|
|
return nil, fmt.Errorf("provided FaaS type is %s, not a function", funcType.Name())
|
|
}
|
|
|
|
// Check if the FaaS function has a return value that only includes (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 function parameter types
|
|
argsType := make([]reflect.Type, funcType.NumIn())
|
|
|
|
// Get the FaaS function name
|
|
fullName := runtime.FuncForPC(funcValue.Pointer()).Name()
|
|
|
|
// Ensure that the FaaS function parameter list contains context.Context and kis.Flow
|
|
// Check if the function contains a parameter of type kis.Flow
|
|
containsKisFlow := false
|
|
// Check if the function contains a parameter of type context.Context
|
|
containsCtx := false
|
|
|
|
// Iterate over the FaaS function parameter types
|
|
for i := 0; i < funcType.NumIn(); i++ {
|
|
|
|
// Get the i-th formal parameter type
|
|
paramType := funcType.In(i)
|
|
|
|
if isFlowType(paramType) {
|
|
// Check if the function contains a parameter of type kis.Flow
|
|
containsKisFlow = true
|
|
|
|
} else if isContextType(paramType) {
|
|
// Check if the function contains a parameter of type context.Context
|
|
containsCtx = true
|
|
|
|
} else if isSliceType(paramType) {
|
|
|
|
// Get the element type of the current parameter Slice
|
|
itemType := paramType.Elem()
|
|
|
|
// If the current parameter is a pointer type, get the struct type that the pointer points to
|
|
if itemType.Kind() == reflect.Ptr {
|
|
itemType = itemType.Elem() // Get the struct type that the pointer points to
|
|
}
|
|
|
|
// Check if f implements Serialize interface
|
|
if isSerialize(itemType) {
|
|
// If the current parameter implements the Serialize interface, use the serialization implementation of the current parameter
|
|
serializeImpl = reflect.New(itemType).Interface().(Serialize)
|
|
|
|
} else {
|
|
// If the current parameter does not implement the Serialize interface, use the default serialization implementation
|
|
serializeImpl = defaultSerialize // Use global default implementation
|
|
}
|
|
}
|
|
|
|
// Append the current parameter type to the argsType collection
|
|
argsType[i] = paramType
|
|
}
|
|
|
|
if !containsKisFlow {
|
|
// If the function parameter list does not contain a parameter of type kis.Flow, return an error
|
|
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 {
|
|
// If the function parameter list does not contain a parameter of type context.Context, return an error
|
|
return nil, errors.New("function parameters must have context, please use FaaS type like: [type FaaS func(context.Context, Flow, ...interface{}) error]")
|
|
}
|
|
|
|
// Return the FaaSDesc description instance
|
|
return &FaaSDesc{
|
|
Serialize: serializeImpl,
|
|
FnName: fnName,
|
|
f: f,
|
|
fName: fullName,
|
|
ArgsType: argsType,
|
|
ArgNum: len(argsType),
|
|
FuncType: funcType,
|
|
FuncValue: funcValue,
|
|
}, nil
|
|
}
|
|
|
|
// isFuncType checks whether the provided paramType is a function type
|
|
func isFuncType(paramType reflect.Type) bool {
|
|
return paramType.Kind() == reflect.Func
|
|
}
|
|
|
|
// isFlowType checks whether the provided paramType is of type kis.Flow
|
|
func isFlowType(paramType reflect.Type) bool {
|
|
var flowInterfaceType = reflect.TypeOf((*Flow)(nil)).Elem()
|
|
|
|
return paramType.Implements(flowInterfaceType)
|
|
}
|
|
|
|
// isContextType checks whether the provided paramType is of type context.Context
|
|
func isContextType(paramType reflect.Type) bool {
|
|
typeName := paramType.Name()
|
|
|
|
return strings.Contains(typeName, "Context")
|
|
}
|
|
|
|
// isSliceType checks whether the provided paramType is a slice type
|
|
func isSliceType(paramType reflect.Type) bool {
|
|
return paramType.Kind() == reflect.Slice
|
|
}
|