From 6511fc4ac01209b9c50be006cd113087cbbbb3c0 Mon Sep 17 00:00:00 2001 From: boyce <6549168@qq.com> Date: Wed, 1 Oct 2025 22:26:30 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util/blueprint/blueprint.go | 15 +- util/blueprint/blueprint_test.go | 63 +++------ util/blueprint/exec.go | 45 +++--- util/blueprint/graphpool.go | 21 +-- util/blueprint/node.go | 27 +++- util/blueprint/port.go | 59 +++++++- util/blueprint/register.go | 7 + util/blueprint/sysnodes.go | 226 +++++++++++++++++++++++++++++++ util/stack/stack.go | 41 ++++++ 9 files changed, 411 insertions(+), 93 deletions(-) create mode 100644 util/blueprint/register.go create mode 100644 util/blueprint/sysnodes.go create mode 100644 util/stack/stack.go diff --git a/util/blueprint/blueprint.go b/util/blueprint/blueprint.go index 50b15b2..c566360 100644 --- a/util/blueprint/blueprint.go +++ b/util/blueprint/blueprint.go @@ -1,19 +1,24 @@ package blueprint +import ( + "fmt" +) + type Blueprint struct { execPool ExecPool graphPool GraphPool } -func (bm *Blueprint) Init(execDefFilePath string, graphFilePath string, onRegister func(execPool *ExecPool) error) error { +func (bm *Blueprint) Init(execDefFilePath string, graphFilePath string) error { err := bm.execPool.Load(execDefFilePath) if err != nil { return err } - - err = onRegister(&bm.execPool) - if err != nil { - return err + + for _, e := range execNodes { + if !bm.execPool.Register(e) { + return fmt.Errorf("register exec failed,exec:%s", e.GetName()) + } } err = bm.graphPool.Load(&bm.execPool, graphFilePath) diff --git a/util/blueprint/blueprint_test.go b/util/blueprint/blueprint_test.go index 4447675..38e8953 100644 --- a/util/blueprint/blueprint_test.go +++ b/util/blueprint/blueprint_test.go @@ -1,65 +1,36 @@ package blueprint import ( - "fmt" "testing" ) -type Entrance_IntParam struct { - BaseExecNode -} - -func (em *Entrance_IntParam) GetName() string { - return "Entrance_IntParam" -} - -func (em *Entrance_IntParam) Exec() (int, error) { - return 0, nil -} - -type Output struct { - BaseExecNode -} - -func (em *Output) GetName() string { - return "Output" -} - -func (em *Output) Exec() (int, error) { - val, ok := em.GetInPortInt(1) - if !ok { - return 0, fmt.Errorf("Output Exec inParam not found") - } - - fmt.Printf("Output Exec inParam %d", val) - return 0, nil -} - -func OnRegister(bm *ExecPool) error { - bm.Register(&Entrance_IntParam{}) - bm.Register(&Output{}) - return nil -} - -const ( - EntranceID_IntParam = 3 -) - func TestExecMgr(t *testing.T) { - // + var bp Blueprint - err := bp.Init("./json/", "./vgf/", OnRegister) + err := bp.Init("D:\\Develop\\OriginNodeEditor\\json", "D:\\Develop\\OriginNodeEditor\\vgf") if err != nil { t.Fatalf("init failed,err:%v", err) } - graphTest2 := bp.Create("test2") - - err = graphTest2.Do(EntranceID_IntParam, 1, 2, 3) + graphTest1 := bp.Create("testArray") + err = graphTest1.Do(EntranceID_ArrayParam, 1, []int64{10, 11, 12}) if err != nil { t.Fatalf("Do EntranceID_IntParam failed,err:%v", err) } + //graphTest2 := bp.Create("testForeach") + //err = graphTest2.Do(EntranceID_IntParam, 1, 2, 3) + //if err != nil { + // t.Fatalf("Do EntranceID_IntParam failed,err:%v", err) + //} + + //graphTest2 := bp.Create("test2") + // + //err = graphTest2.Do(EntranceID_IntParam, 1, 2, 3) + //if err != nil { + // t.Fatalf("Do EntranceID_IntParam failed,err:%v", err) + //} + //graph := bp.Create("test1") //err = graph.Do(EntranceID_IntParam, 1, 2, 3) //if err != nil { diff --git a/util/blueprint/exec.go b/util/blueprint/exec.go index 761a1a8..1ab29cb 100644 --- a/util/blueprint/exec.go +++ b/util/blueprint/exec.go @@ -39,11 +39,12 @@ type innerExecNode struct { Package string Description string - InPort []IPort - OutPort []IPort + inPort []IPort + outPort []IPort inPortParamStartIndex int // 输入参数的起始索引,用于排除执行入口 outPortParamStartIndex int // 输出参数的起始索引,用于排除执行出口 + IExecNode } @@ -82,28 +83,28 @@ type BaseExecConfig struct { } func (em *innerExecNode) AppendInPort(port ...IPort) { - if len(em.InPort) == 0 { + if len(em.inPort) == 0 { em.inPortParamStartIndex = -1 } for i := 0; i < len(port); i++ { if !port[i].IsPortExec() && em.inPortParamStartIndex < 0 { - em.inPortParamStartIndex = len(em.InPort) + em.inPortParamStartIndex = len(em.inPort) } - em.InPort = append(em.InPort, port[i]) + em.inPort = append(em.inPort, port[i]) } } func (em *innerExecNode) AppendOutPort(port ...IPort) { - if len(em.OutPort) == 0 { + if len(em.outPort) == 0 { em.outPortParamStartIndex = -1 } for i := 0; i < len(port); i++ { if !port[i].IsPortExec() && em.outPortParamStartIndex < 0 { - em.outPortParamStartIndex = len(em.OutPort) + em.outPortParamStartIndex = len(em.outPort) } - em.OutPort = append(em.OutPort, port[i]) + em.outPort = append(em.outPort, port[i]) } } @@ -117,7 +118,7 @@ func (em *innerExecNode) SetExec(exec IExecNode) { func (em *innerExecNode) CloneInOutPort() ([]IPort, []IPort) { inPorts := make([]IPort, 0, 2) - for _, port := range em.InPort { + for _, port := range em.inPort { if port.IsPortExec() { // 执行入口, 不需要克隆,占位处理 inPorts = append(inPorts, nil) @@ -128,7 +129,7 @@ func (em *innerExecNode) CloneInOutPort() ([]IPort, []IPort) { } outPorts := make([]IPort, 0, 2) - for _, port := range em.OutPort { + for _, port := range em.outPort { if port.IsPortExec() { outPorts = append(outPorts, nil) continue @@ -140,40 +141,40 @@ func (em *innerExecNode) CloneInOutPort() ([]IPort, []IPort) { } func (em *innerExecNode) IsInPortExec(index int) bool { - if index >= len(em.InPort) || index < 0 { + if index >= len(em.inPort) || index < 0 { return false } - return em.InPort[index].IsPortExec() + return em.inPort[index].IsPortExec() } func (em *innerExecNode) IsOutPortExec(index int) bool { - if index >= len(em.OutPort) || index < 0 { + if index >= len(em.outPort) || index < 0 { return false } - return em.OutPort[index].IsPortExec() + return em.outPort[index].IsPortExec() } func (em *innerExecNode) GetInPortCount() int { - return len(em.InPort) + return len(em.inPort) } func (em *innerExecNode) GetOutPortCount() int { - return len(em.OutPort) + return len(em.outPort) } func (em *innerExecNode) GetInPort(index int) IPort { - if index >= len(em.InPort) || index < 0 { + if index >= len(em.inPort) || index < 0 { return nil } - return em.InPort[index] + return em.inPort[index] } func (em *innerExecNode) GetOutPort(index int) IPort { - if index >= len(em.OutPort) || index < 0 { + if index >= len(em.outPort) || index < 0 { return nil } - return em.OutPort[index] + return em.outPort[index] } func (em *innerExecNode) GetInPortParamStartIndex() int { @@ -390,7 +391,7 @@ func (en *BaseExecNode) AppendInPortArrayValStr(index int, val Port_Str) bool { return port.AppendArrayValStr(val) } -func (en *BaseExecNode) GetInPortArrayLen(index int) int { +func (en *BaseExecNode) GetInPortArrayLen(index int) Port_Int { port := en.GetInPort(index) if port == nil { return 0 @@ -462,7 +463,7 @@ func (en *BaseExecNode) AppendOutPortArrayValStr(index int, val Port_Str) bool { return port.AppendArrayValStr(val) } -func (en *BaseExecNode) GetOutPortArrayLen(index int) int { +func (en *BaseExecNode) GetOutPortArrayLen(index int) Port_Int { port := en.GetOutPort(index) if port == nil { return 0 diff --git a/util/blueprint/graphpool.go b/util/blueprint/graphpool.go index fbe2178..14be140 100644 --- a/util/blueprint/graphpool.go +++ b/util/blueprint/graphpool.go @@ -182,6 +182,7 @@ func (gp *GraphPool) prepareOneNode(mapNodeExec map[string]*execNode, nodeExec * if nextExecNode == nil { continue } + nextExecNode.beConnect = true nodeExec.nextNode = append(nodeExec.nextNode, nextExecNode) } @@ -222,13 +223,14 @@ func (gp *GraphPool) prepareOneEntrance(graphName string, entranceID int64, node return fmt.Errorf("entrance node %s not found", nodeCfg.Id) } + nodeExec.isEntrance = true err = gp.prepareOneNode(mapNodes, nodeExec, graphConfig, new(int)) if err != nil { return err } // 处理inPort前置结点 - err = gp.prepareInPort(mapNodes, nodeExec, graphConfig) + err = gp.prepareInPort(mapNodes, graphConfig) if err != nil { return err } @@ -283,19 +285,10 @@ func (gp *GraphPool) preparePreInPortNode(mapNodes map[string]*execNode, nodeExe return nil } -func (gp *GraphPool) prepareInPort(mapNodeExec map[string]*execNode, nodeExec *execNode, graphConfig *graphConfig) error { - for _, nextNode := range nodeExec.nextNode { - if nextNode == nil { - continue - } - - // 对nextNode结点的入口进行预处理 - err := gp.preparePreInPortNode(mapNodeExec, nextNode, graphConfig) - if err != nil { - return err - } - - err = gp.prepareInPort(mapNodeExec, nextNode, graphConfig) +func (gp *GraphPool) prepareInPort(mapNodeExec map[string]*execNode, graphConfig *graphConfig) error { + for _, e := range mapNodeExec { + // 对当前结点的入口进行预处理 + err := gp.preparePreInPortNode(mapNodeExec, e, graphConfig) if err != nil { return err } diff --git a/util/blueprint/node.go b/util/blueprint/node.go index 72f6800..5507ba5 100644 --- a/util/blueprint/node.go +++ b/util/blueprint/node.go @@ -1,6 +1,8 @@ package blueprint -import "fmt" +import ( + "fmt" +) type prePortNode struct { node *execNode // 上个结点 @@ -18,6 +20,23 @@ type execNode struct { inPortDefaultValue map[string]any variableName string // 如果是变量,则有变量名 + beConnect bool // 是否有被连线 + isEntrance bool // 是否是入口结点 +} + +// HasBeConnectLine 是否有被连线 +func (en *execNode) HasBeConnectLine() bool { + return en.beConnect +} + +// HasInPortExec 有前置执行入口 +func (en *execNode) HasInPortExec() bool { + return en.execNode.IsInPortExec(0) +} + +// HasOutPortExec 有前置执行入口 +func (en *execNode) HasOutPortExec() bool { + return en.execNode.IsOutPortExec(0) } func (en *execNode) GetInPortDefaultValue(index int) any { @@ -52,6 +71,7 @@ func (en *execNode) exec(gr *Graph) (int, error) { return -1, err } + //log.Debug("exec node %s", en.execNode.GetName()) return e.Exec() } @@ -67,9 +87,10 @@ func (en *execNode) doSetInPort(gr *Graph, index int, inPort IPort) error { return nil } - if _, ok := gr.context[preNode.node.Id]; !ok { + if _, ok := gr.context[preNode.node.Id]; !ok || + (!preNode.node.HasBeConnectLine() && !preNode.node.isEntrance) { // 如果前一个结点没有执行过,则递归执行前一个结点 - err := preNode.node.Do(gr, nil) + err := preNode.node.Do(gr) if err != nil { return err } diff --git a/util/blueprint/port.go b/util/blueprint/port.go index e8e892b..964b7b7 100644 --- a/util/blueprint/port.go +++ b/util/blueprint/port.go @@ -80,6 +80,13 @@ func (em *Port[T]) GetBool() (Port_Bool, bool) { return false, false } +func (em *Port[T]) GetArray() (Port_Array, bool) { + if t, ok := any(em.PortVal).(Port_Array); ok { + return t, true + } + return nil, false +} + func (em *Port[T]) SetInt(val Port_Int) bool { if t, ok := any(&em.PortVal).(*Port_Int); ok { *t = val @@ -148,9 +155,9 @@ func (em *Port[T]) AppendArrayValStr(val Port_Str) bool { return false } -func (em *Port[T]) GetArrayLen() int { +func (em *Port[T]) GetArrayLen() Port_Int { if t, ok := any(&em.PortVal).(*Port_Array); ok { - return len(*t) + return Port_Int(len(*t)) } return 0 @@ -262,6 +269,51 @@ func (em *Port[T]) setAnyVale(v any) error { default: return fmt.Errorf("port type is %T, but value is %v", em.PortVal, v) } + case []int64: + arr := v.([]int64) + for _, val := range arr { + em.AppendArrayValInt(val) + } + case []int32: + arr := v.([]int32) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []int16: + arr := v.([]int16) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []int8: + arr := v.([]int8) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []uint64: + arr := v.([]uint64) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []uint32: + arr := v.([]uint32) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []uint16: + arr := v.([]uint16) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []uint8: + arr := v.([]uint8) + for _, val := range arr { + em.AppendArrayValInt(Port_Int(val)) + } + case []string: + arr := v.([]string) + for _, val := range arr { + em.AppendArrayValStr(val) + } } return nil @@ -283,6 +335,7 @@ type IPort interface { GetArrayValInt(idx int) (Port_Int, bool) GetArrayValStr(idx int) (Port_Str, bool) GetBool() (Port_Bool, bool) + GetArray() (Port_Array, bool) SetInt(val Port_Int) bool SetFloat(val Port_Float) bool @@ -292,7 +345,7 @@ type IPort interface { SetArrayValStr(idx int, val Port_Str) bool AppendArrayValInt(val Port_Int) bool AppendArrayValStr(val Port_Str) bool - GetArrayLen() int + GetArrayLen() Port_Int Clone() IPort Reset() diff --git a/util/blueprint/register.go b/util/blueprint/register.go new file mode 100644 index 0000000..dc8a2a4 --- /dev/null +++ b/util/blueprint/register.go @@ -0,0 +1,7 @@ +package blueprint + +var execNodes []IExecNode + +func RegExecNode(exec IExecNode) { + execNodes = append(execNodes, exec) +} diff --git a/util/blueprint/sysnodes.go b/util/blueprint/sysnodes.go new file mode 100644 index 0000000..6a942df --- /dev/null +++ b/util/blueprint/sysnodes.go @@ -0,0 +1,226 @@ +package blueprint + +import ( + "fmt" + "github.com/duanhf2012/origin/v2/log" +) + +// 系统入口ID定义,1000以内 +const ( + EntranceID_ArrayParam = 2 + EntranceID_IntParam = 3 +) + +func init() { + RegExecNode(&Entrance_ArrayParam{}) + RegExecNode(&Entrance_IntParam{}) + RegExecNode(&Output{}) + RegExecNode(&Sequence{}) + RegExecNode(&Foreach{}) + RegExecNode(&GetArrayInt{}) + RegExecNode(&GetArrayString{}) + RegExecNode(&GetArrayLen{}) +} + +type Entrance_ArrayParam struct { + BaseExecNode +} + +func (em *Entrance_ArrayParam) GetName() string { + return "Entrance_ArrayParam" +} + +func (em *Entrance_ArrayParam) Exec() (int, error) { + return 0, nil +} + +type Entrance_IntParam struct { + BaseExecNode +} + +func (em *Entrance_IntParam) GetName() string { + return "Entrance_IntParam" +} + +func (em *Entrance_IntParam) Exec() (int, error) { + return 0, nil +} + +type Output struct { + BaseExecNode +} + +func (em *Output) GetName() string { + return "Output" +} + +func (em *Output) Exec() (int, error) { + val, ok := em.GetInPortInt(1) + if !ok { + return 0, fmt.Errorf("Output Exec inParam not found") + } + + fmt.Printf("Output Exec inParam %d", val) + return 0, nil +} + +type Sequence struct { + BaseExecNode +} + +func (em *Sequence) GetName() string { + return "Sequence" +} + +func (em *Sequence) Exec() (int, error) { + for i := range em.outPort { + if !em.outPort[i].IsPortExec() { + break + } + + err := em.DoNext(i) + if err != nil { + return -1, err + } + } + + return -1, nil +} + +type Foreach struct { + BaseExecNode +} + +func (em *Foreach) GetName() string { + return "Foreach" +} + +func (em *Foreach) Exec() (int, error) { + startIndex, ok := em.ExecContext.InputPorts[1].GetInt() + if !ok { + return 0, fmt.Errorf("foreach Exec inParam not found") + } + endIndex, ok := em.ExecContext.InputPorts[2].GetInt() + if !ok { + return 0, fmt.Errorf("foreach Exec inParam not found") + } + + for i := startIndex; i < endIndex; i++ { + em.ExecContext.OutputPorts[2].SetInt(i) + err := em.DoNext(0) + if err != nil { + return -1, err + } + } + + err := em.DoNext(1) + if err != nil { + return -1, err + } + + return -1, nil +} + +type GetArrayInt struct { + BaseExecNode +} + +func (em *GetArrayInt) GetName() string { + return "GetArrayInt" +} + +func (em *GetArrayInt) Exec() (int, error) { + inPort := em.GetInPort(0) + if inPort == nil { + return -1, fmt.Errorf("GetArrayInt inParam not found") + } + outPort := em.GetOutPort(0) + if outPort == nil { + return -1, fmt.Errorf("GetArrayInt outParam not found") + } + + arrIndexPort := em.GetInPort(1) + if arrIndexPort == nil { + return -1, fmt.Errorf("GetArrayInt arrIndexParam not found") + } + arrIndex, ok := arrIndexPort.GetInt() + if !ok { + return -1, fmt.Errorf("GetArrayInt arrIndexParam not found") + } + + if arrIndex < 0 || arrIndex >= inPort.GetArrayLen() { + return -1, fmt.Errorf("GetArrayInt arrIndexParam out of range,index %d", arrIndex) + } + + val, ok := inPort.GetArrayValInt(int(arrIndex)) + if !ok { + log.Errorf("GetArrayValInt failed, idx:%d", arrIndex) + return -1, fmt.Errorf("GetArrayInt inParam not found") + } + + outPort.SetInt(val) + return -1, nil +} + +type GetArrayString struct { + BaseExecNode +} + +func (em *GetArrayString) GetName() string { + return "GetArrayString" +} + +func (em *GetArrayString) Exec() (int, error) { + inPort := em.GetInPort(0) + if inPort == nil { + return -1, fmt.Errorf("GetArrayInt inParam not found") + } + outPort := em.GetOutPort(0) + if outPort == nil { + return -1, fmt.Errorf("GetArrayInt outParam not found") + } + + arrIndexPort := em.GetInPort(1) + if arrIndexPort == nil { + return -1, fmt.Errorf("GetArrayInt arrIndexParam not found") + } + arrIndex, ok := arrIndexPort.GetInt() + if !ok { + return -1, fmt.Errorf("GetArrayInt arrIndexParam not found") + } + + if arrIndex < 0 || arrIndex >= inPort.GetArrayLen() { + return -1, fmt.Errorf("GetArrayInt arrIndexParam out of range,index %d", arrIndex) + } + + val, ok := inPort.GetArrayValStr(int(arrIndex)) + if !ok { + log.Errorf("GetArrayValStr failed, idx:%d", arrIndex) + return -1, fmt.Errorf("GetArrayInt inParam not found") + } + + outPort.SetStr(val) + return -1, nil +} + +type GetArrayLen struct { + BaseExecNode +} + +func (em *GetArrayLen) GetName() string { + return "GetArrayLen" +} + +func (em *GetArrayLen) Exec() (int, error) { + inPort := em.GetInPort(0) + if inPort == nil { + return -1, fmt.Errorf("GetArrayInt inParam not found") + } + outPort := em.GetOutPort(0) + if outPort == nil { + return -1, fmt.Errorf("GetArrayInt outParam not found") + } + + outPort.SetInt(inPort.GetArrayLen()) + return -1, nil +} diff --git a/util/stack/stack.go b/util/stack/stack.go new file mode 100644 index 0000000..1567993 --- /dev/null +++ b/util/stack/stack.go @@ -0,0 +1,41 @@ +package stack + +// Stack 是一个通用类型的栈结构 +type Stack[T any] struct { + items []*T +} + +// Push 将元素压入栈顶 +func (s *Stack[T]) Push(item *T) { + s.items = append(s.items, item) +} + +// Pop 弹出并返回栈顶元素,如果栈为空则返回错误 +func (s *Stack[T]) Pop() *T { + if len(s.items) == 0 { + return nil + } + + index := len(s.items) - 1 + item := s.items[index] + s.items = s.items[:index] + return item +} + +// Peek 返回栈顶元素但不移除,如果栈为空则返回错误 +func (s *Stack[T]) Peek() *T { + if len(s.items) == 0 { + return nil + } + return s.items[len(s.items)-1] +} + +// IsEmpty 检查栈是否为空 +func (s *Stack[T]) IsEmpty() bool { + return len(s.items) == 0 +} + +// Size 返回栈中元素的数量 +func (s *Stack[T]) Size() int { + return len(s.items) +}