package flow import ( "errors" "fmt" "git.sxidc.com/go-tools/utils/pipeline/component" "github.com/mitchellh/mapstructure" ) const ( TypeLoop = "loop" ) type LoopBuildParams struct { ConditionComponent *SubComponentBuildParams `mapstructure:"condition" structs:"condition"` SubComponent *SubComponentBuildParams `mapstructure:"sub" structs:"sub"` } func (params *LoopBuildParams) Check() error { if params.ConditionComponent == nil { return errors.New(TypeLoop + "流程的条件组件参数为空") } if params.SubComponent == nil { return errors.New(TypeLoop + "流程的子组件参数为空") } err := params.ConditionComponent.Check(TypeLoop) if err != nil { return err } err = params.SubComponent.Check(TypeLoop) if err != nil { return err } if params.ConditionComponent.Name == params.SubComponent.Name { return fmt.Errorf("流程中存在同名的组件: condition: %s flow: %s", params.ConditionComponent.Name, params.SubComponent.Name) } return nil } type Loop struct { component.BaseComponent ConditionComponent component.Component SubComponent component.Component } func (f *Loop) Run(globalRunParams *component.GlobalRunParams, dynamicParams map[string]any) (any, error) { return f.OnRun(globalRunParams, dynamicParams, func(globalRunParams *component.GlobalRunParams, dynamicParams map[string]any) (any, error) { lastResult := globalRunParams.GetLastResult() var conditionDynamicParamsMap map[string]any conditionDynamicParams, ok := dynamicParams[f.ConditionComponent.GetName()] if ok { innerConditionDynamicParamsMap, ok := conditionDynamicParams.(map[string]any) if !ok { return nil, errors.New(TypeLoop + "流程" + f.GetName() + "的条件组件" + f.ConditionComponent.GetName() + "动态参数类型错误") } conditionDynamicParamsMap = innerConditionDynamicParamsMap } var subDynamicParamsMap map[string]any subDynamicParams, ok := dynamicParams[f.SubComponent.GetName()] if ok { innerSubDynamicParamsMap, ok := subDynamicParams.(map[string]any) if !ok { return nil, errors.New(TypeLoop + "流程" + f.GetName() + "的子组件" + f.SubComponent.GetName() + "动态参数类型错误") } subDynamicParamsMap = innerSubDynamicParamsMap } condition, err := f.runConditionComponent(globalRunParams, conditionDynamicParamsMap) if err != nil { return nil, err } if !condition { return lastResult, nil } var result any for condition { innerResult, err := f.SubComponent.Run(globalRunParams, subDynamicParamsMap) if err != nil { return nil, err } innerCondition, err := f.runConditionComponent(globalRunParams, conditionDynamicParamsMap) if err != nil { return nil, err } condition = innerCondition result = innerResult } return result, nil }) } func (f *Loop) runConditionComponent(globalRunParams *component.GlobalRunParams, conditionDynamicParamsMap map[string]any) (bool, error) { conditionResult, err := f.ConditionComponent.Run(globalRunParams, conditionDynamicParamsMap) if err != nil { return false, err } condition, ok := conditionResult.(bool) if !ok { return false, errors.New(TypeLoop + "流程的条件子组件返回结果应当为bool") } return condition, nil } type LoopBuilder struct{} func (builder *LoopBuilder) ProductType() string { return TypeLoop } func (builder *LoopBuilder) Build(name string, buildParams map[string]any, runParams map[string]any) (component.Component, error) { if buildParams == nil || len(buildParams) == 0 { return nil, errors.New(TypeLoop + "流程没有传递构建参数") } flowBuildParams := new(LoopBuildParams) err := mapstructure.Decode(buildParams, flowBuildParams) if err != nil { return nil, errors.New(TypeLoop + "流程构建参数Decode失败: " + err.Error()) } err = flowBuildParams.Check() if err != nil { return nil, err } conditionFlow, err := flowBuildParams.ConditionComponent.BuildComponent() if err != nil { return nil, err } subFlow, err := flowBuildParams.SubComponent.BuildComponent() if err != nil { return nil, err } return &Loop{ BaseComponent: *component.NewBaseComponent(TypeLoop, name, runParams), ConditionComponent: conditionFlow, SubComponent: subFlow, }, nil }