Files
mayfly-go/server/internal/flow/application/node.go
2025-05-20 21:04:47 +08:00

160 lines
3.9 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 application
import (
"context"
"fmt"
"mayfly-go/internal/flow/domain/entity"
"sync"
"time"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/utils/collx"
)
/******************* 执行流上下文 *******************/
type ExecutionCtx struct {
parent context.Context
Procinst *entity.Procinst // 流程实例
Execution *entity.Execution // 当前执行流
ProcinsVars collx.M // 流程实例变量
ExecutionVars collx.M // 执行流变量
OpExtra collx.M // 操作额外信息,记录用户任务审批状态等
HisProcinstOp *entity.HisProcinstOp // 当前节点操作记录用于start这种立即完成的避免在开始节点时重复查询节点信息
flowDef *entity.FlowDef
}
// GetProcinst 获取流程实例,若上下文不存在则从库中获取
func (e *ExecutionCtx) GetProcinst() *entity.Procinst {
if e.Procinst == nil {
pi, err := GetProcinstApp().GetById(e.Execution.ProcinstId)
if err != nil {
panic(err)
}
e.Procinst = pi
}
return e.Procinst
}
// GetFlowDef 获取流程定义
func (ec *ExecutionCtx) GetFlowDef() *entity.FlowDef {
if ec.flowDef == nil {
ec.flowDef = ec.Procinst.GetFlowDef()
}
return ec.flowDef
}
// GetNode 获取当前节点信息
func (ec *ExecutionCtx) GetFlowNode() *entity.FlowNode {
nodes := ec.GetFlowDef().GetNodes(ec.Execution.NodeKey)
if len(nodes) == 0 {
return nil
}
return nodes[0]
}
// GetNextNodes 获取该执行流的下一个节点
func (e *ExecutionCtx) GetNextNode(vars collx.M) (*entity.FlowNode, error) {
nextNodes := e.GetProcinst().GetFlowDef().GetNextNodes(e.Execution.NodeKey, vars)
if len(nextNodes) == 0 {
return nil, nil
}
if len(nextNodes) > 1 {
return nil, errorx.NewBiz("执行流的下一节点只允许单个节点")
}
return nextNodes[0], nil
}
/* context.Context 实现方法 */
// 实现Deadline方法继承父上下文
func (ec *ExecutionCtx) Deadline() (deadline time.Time, ok bool) {
return ec.parent.Deadline()
}
// 实现Done方法继承父上下文
func (ec *ExecutionCtx) Done() <-chan struct{} {
return ec.parent.Done()
}
// 实现Err方法继承父上下文
func (ec *ExecutionCtx) Err() error {
return ec.parent.Err()
}
// 实现Value方法
func (ec *ExecutionCtx) Value(key interface{}) interface{} {
return ec.parent.Value(key)
}
func NewExecutionCtx(ctx context.Context, procinst *entity.Procinst, execution *entity.Execution) *ExecutionCtx {
return &ExecutionCtx{
parent: ctx,
Procinst: procinst,
Execution: execution,
ExecutionVars: collx.M(execution.Vars),
ProcinsVars: collx.M(procinst.Vars),
}
}
/******************* 节点定义 *******************/
// NodeBehavior node handler
type NodeBehavior interface {
// GetType 获取节点类型
GetType() entity.FlowNodeType
// Validate 验证节点信息
Validate(context.Context, *entity.FlowDef, *entity.FlowNode) error
// Execute 执行节点
Execute(*ExecutionCtx) error
// Leave 离开节点
Leave(*ExecutionCtx) error
}
type DefaultNodeBehavior struct {
}
func (h *DefaultNodeBehavior) Validate(ctx context.Context, flowDef *entity.FlowDef, node *entity.FlowNode) error {
return nil
}
func (h *DefaultNodeBehavior) Execute(ctx *ExecutionCtx) error {
return h.Leave(ctx)
}
func (h *DefaultNodeBehavior) Leave(ctx *ExecutionCtx) error {
// 默认执行流推进下一节点
return GetExecutionApp().ContinueExecution(ctx)
}
/******************* 节点注册器 *******************/
type NodeBehaviorRegistry struct {
nodes sync.Map
}
func (r *NodeBehaviorRegistry) Register(node NodeBehavior) {
if _, loaded := r.nodes.LoadOrStore(node.GetType(), node); loaded {
panic(fmt.Sprintf("handler already registered: %s", node.GetType()))
}
}
func (r *NodeBehaviorRegistry) GetNode(nodeType entity.FlowNodeType) (NodeBehavior, error) {
val, ok := r.nodes.Load(nodeType)
if !ok {
return nil, fmt.Errorf("node handler not found: %s", nodeType)
}
return val.(NodeBehavior), nil
}
var nodeBehaviorRegistry = &NodeBehaviorRegistry{}