2024-03-19 19:16:03 +08:00
package kis
import (
"errors"
"fmt"
"reflect"
"runtime"
2024-03-25 16:35:20 +08:00
"strings"
2024-03-19 19:16:03 +08:00
)
// FaaS Function as a Service
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Change the type definition from:
2024-03-25 16:35:20 +08:00
// type FaaS func(context.Context, Flow) error
2024-04-15 17:50:02 +08:00
// to:
2024-03-25 16:35:20 +08:00
// type FaaS func(context.Context, Flow, ...interface{}) error
2024-04-15 17:50:02 +08:00
// This allows passing data through variadic parameters of any type.
2024-03-19 19:16:03 +08:00
type FaaS interface { }
2024-04-15 17:50:02 +08:00
// FaaSDesc describes the FaaS callback computation function.
2024-03-19 19:16:03 +08:00
type FaaSDesc struct {
2024-04-15 17:50:02 +08:00
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)
2024-03-19 19:16:03 +08:00
}
2024-04-15 17:50:02 +08:00
// NewFaaSDesc creates an instance of FaaSDesc description based on the registered FnName and FaaS callback function.
2024-03-19 19:16:03 +08:00
func NewFaaSDesc ( fnName string , f FaaS ) ( * FaaSDesc , error ) {
2024-03-21 10:13:32 +08:00
2024-04-15 17:50:02 +08:00
// Serialization instance
2024-03-25 16:35:20 +08:00
var serializeImpl Serialize
2024-03-21 10:13:32 +08:00
2024-04-15 17:50:02 +08:00
// Callback function value (function address)
2024-03-19 19:16:03 +08:00
funcValue := reflect . ValueOf ( f )
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Callback function type
2024-03-19 19:16:03 +08:00
funcType := funcValue . Type ( )
2024-04-15 17:50:02 +08:00
// Check if the provided FaaS pointer is a function type
2024-03-25 16:35:20 +08:00
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
}
2024-04-15 17:50:02 +08:00
// Check if the FaaS function has a return value that only includes (error)
2024-03-25 16:35:20 +08:00
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" )
}
2024-04-15 17:50:02 +08:00
// FaaS function parameter types
2024-03-19 19:16:03 +08:00
argsType := make ( [ ] reflect . Type , funcType . NumIn ( ) )
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Get the FaaS function name
2024-03-19 19:16:03 +08:00
fullName := runtime . FuncForPC ( funcValue . Pointer ( ) ) . Name ( )
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Ensure that the FaaS function parameter list contains context.Context and kis.Flow
// Check if the function contains a parameter of type kis.Flow
2024-03-21 10:13:32 +08:00
containsKisFlow := false
2024-04-15 17:50:02 +08:00
// Check if the function contains a parameter of type context.Context
2024-03-21 10:13:32 +08:00
containsCtx := false
2024-03-19 19:16:03 +08:00
2024-04-15 17:50:02 +08:00
// Iterate over the FaaS function parameter types
2024-03-19 19:16:03 +08:00
for i := 0 ; i < funcType . NumIn ( ) ; i ++ {
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Get the i-th formal parameter type
2024-03-19 19:16:03 +08:00
paramType := funcType . In ( i )
2024-03-25 16:35:20 +08:00
2024-03-19 19:16:03 +08:00
if isFlowType ( paramType ) {
2024-04-15 17:50:02 +08:00
// Check if the function contains a parameter of type kis.Flow
2024-03-21 10:13:32 +08:00
containsKisFlow = true
2024-03-25 16:35:20 +08:00
2024-03-21 10:13:32 +08:00
} else if isContextType ( paramType ) {
2024-04-15 17:50:02 +08:00
// Check if the function contains a parameter of type context.Context
2024-03-21 10:13:32 +08:00
containsCtx = true
2024-03-25 16:35:20 +08:00
} else if isSliceType ( paramType ) {
2024-04-15 17:50:02 +08:00
// Get the element type of the current parameter Slice
2024-03-21 10:13:32 +08:00
itemType := paramType . Elem ( )
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// If the current parameter is a pointer type, get the struct type that the pointer points to
2024-03-21 10:13:32 +08:00
if itemType . Kind ( ) == reflect . Ptr {
2024-04-15 17:50:02 +08:00
itemType = itemType . Elem ( ) // Get the struct type that the pointer points to
2024-03-21 10:13:32 +08:00
}
2024-03-25 16:35:20 +08:00
// Check if f implements Serialize interface
if isSerialize ( itemType ) {
2024-04-15 17:50:02 +08:00
// If the current parameter implements the Serialize interface, use the serialization implementation of the current parameter
2024-03-25 16:35:20 +08:00
serializeImpl = reflect . New ( itemType ) . Interface ( ) . ( Serialize )
2024-03-21 10:13:32 +08:00
} else {
2024-04-15 17:50:02 +08:00
// If the current parameter does not implement the Serialize interface, use the default serialization implementation
2024-03-25 16:35:20 +08:00
serializeImpl = defaultSerialize // Use global default implementation
2024-03-21 10:13:32 +08:00
}
2024-03-19 19:16:03 +08:00
}
2024-03-25 16:35:20 +08:00
2024-04-15 17:50:02 +08:00
// Append the current parameter type to the argsType collection
2024-03-19 19:16:03 +08:00
argsType [ i ] = paramType
}
2024-03-21 10:13:32 +08:00
if ! containsKisFlow {
2024-04-15 17:50:02 +08:00
// If the function parameter list does not contain a parameter of type kis.Flow, return an error
2024-03-25 16:35:20 +08:00
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-21 10:13:32 +08:00
}
2024-03-19 19:16:03 +08:00
2024-03-25 16:35:20 +08:00
if ! containsCtx {
2024-04-15 17:50:02 +08:00
// If the function parameter list does not contain a parameter of type context.Context, return an error
2024-03-25 16:35:20 +08:00
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
}
2024-04-15 17:50:02 +08:00
// Return the FaaSDesc description instance
2024-03-19 19:16:03 +08:00
return & FaaSDesc {
2024-03-25 16:35:20 +08:00
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
}
2024-04-15 17:50:02 +08:00
// isFuncType checks whether the provided paramType is a function type
2024-03-25 16:35:20 +08:00
func isFuncType ( paramType reflect . Type ) bool {
return paramType . Kind ( ) == reflect . Func
}
2024-04-15 17:50:02 +08:00
// isFlowType checks whether the provided paramType is of type kis.Flow
2024-03-25 16:35:20 +08:00
func isFlowType ( paramType reflect . Type ) bool {
var flowInterfaceType = reflect . TypeOf ( ( * Flow ) ( nil ) ) . Elem ( )
return paramType . Implements ( flowInterfaceType )
}
2024-04-15 17:50:02 +08:00
// isContextType checks whether the provided paramType is of type context.Context
2024-03-25 16:35:20 +08:00
func isContextType ( paramType reflect . Type ) bool {
typeName := paramType . Name ( )
return strings . Contains ( typeName , "Context" )
}
2024-04-15 17:50:02 +08:00
// isSliceType checks whether the provided paramType is a slice type
2024-03-25 16:35:20 +08:00
func isSliceType ( paramType reflect . Type ) bool {
return paramType . Kind ( ) == reflect . Slice
2024-03-19 19:16:03 +08:00
}