mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 16:00:25 +08:00
160 lines
3.9 KiB
Go
160 lines
3.9 KiB
Go
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{}
|