Files
origin/util/blueprint/graphpool.go
2025-09-20 07:54:08 +08:00

279 lines
7.0 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 blueprint
import (
"fmt"
"github.com/goccy/go-json"
"os"
"path/filepath"
"strconv"
"strings"
)
// 格式说明Entrance_ID
const (
Entrance = "Entrance_"
)
type GraphPool struct {
mapGraphs map[string]graph
execPool *ExecPool
}
func (gp *GraphPool) Load(graphFilePath string) error {
// 检查路径是否存在
stat, err := os.Stat(graphFilePath)
if err != nil {
return fmt.Errorf("failed to access path %s: %v", graphFilePath, err)
}
// 如果是单个文件,直接处理
if !stat.IsDir() {
return fmt.Errorf("%s is not a directory", graphFilePath)
}
// 遍历目录及其子目录
return filepath.Walk(graphFilePath, func(path string, info os.FileInfo, err error) error {
if err != nil {
fmt.Printf("访问路径出错 %s: %v\n", path, err)
return nil // 继续遍历其他文件
}
// 如果是目录,继续遍历
if info.IsDir() {
return nil
}
// 只处理JSON文件
if filepath.Ext(path) == ".vgf" {
return gp.processJSONFile(path)
}
return nil
})
}
func (gp *GraphPool) Create(graphName string) IGraph {
gr, ok := gp.mapGraphs[graphName]
if !ok {
return nil
}
return &gr
}
func (gp *GraphPool) processJSONFile(filePath string) error {
// 打开文件
file, err := os.Open(filePath)
if err != nil {
return fmt.Errorf("failed to open file %s: %v", filePath, err)
}
defer file.Close()
fileName := filepath.Base(filePath)
ext := filepath.Ext(fileName) // 获取".html"
name := strings.TrimSuffix(fileName, ext) // 获取"name"
var gConfig graphConfig
decoder := json.NewDecoder(file)
if err := decoder.Decode(&gConfig); err != nil {
return fmt.Errorf("failed to decode JSON from file %s: %v", filePath, err)
}
return gp.prepareGraph(name, &gConfig)
}
func (gp *GraphPool) prepareGraph(graphName string, graphConfig *graphConfig) error {
// 找到所有的入口
for _, node := range graphConfig.Nodes {
if strings.HasPrefix(node.Class, Entrance) {
// 取得ID
id := strings.TrimPrefix(node.Class, Entrance)
entranceID, err := strconv.Atoi(id)
if err != nil {
return err
}
// 对入口进行预处理
err = gp.prepareOneEntrance(graphName, int64(entranceID), &node, graphConfig)
if err != nil {
return err
}
}
}
return nil
}
func (gp *GraphPool) getVarExec(nodeCfg *nodeConfig, graphConfig *graphConfig) (IBaseExec, string) {
// 是否为Get_或Set_开头
if strings.HasPrefix(nodeCfg.Class, "Get_") || strings.HasPrefix(nodeCfg.Class, "Set_") {
return gp.execPool.GetExec(nodeCfg.Class), ""
}
// 获取Get_或Set_结尾字符串
var nodeName string
var varName string
if strings.HasSuffix(nodeCfg.Class, "Get_") {
var typ string
varName = strings.TrimSuffix(nodeCfg.Class, "Get_")
varCfg := graphConfig.GetVariablesByName(varName)
if varCfg != nil {
typ = varCfg.Type
}
nodeName = genGetVariablesNodeName(typ)
} else if strings.HasSuffix(nodeCfg.Class, "Set_") {
var typ string
varName = strings.TrimSuffix(nodeCfg.Class, "Set_")
varCfg := graphConfig.GetVariablesByName(varName)
if varCfg != nil {
typ = varCfg.Type
}
nodeName = genSetVariablesNodeName(typ)
}
return gp.execPool.GetExec(nodeName), varName
}
func (gp *GraphPool) genAllNode(graphConfig *graphConfig) (map[string]*execNode, error) {
nodes := make(map[string]*execNode)
for _, node := range graphConfig.Nodes {
var varName string
// 获取不到node则获取变量node
exec := gp.execPool.GetExec(node.Class)
if exec == nil {
exec, varName = gp.getVarExec(&node, graphConfig)
if exec == nil {
return nil, fmt.Errorf("no exec found for node %s", node.Class)
}
}
nodes[node.Id] = &execNode{
Id: node.Id,
baseExec: exec,
preInPort: make([]*prePortNode, exec.GetInPortCount()),
inPortDefaultValue: node.PortDefault,
variableName: varName,
}
}
return nodes, nil
}
func (gp *GraphPool) prepareOneNode(mapNodeExec map[string]*execNode, nodeExec *execNode, graphConfig *graphConfig) error {
// 找到所有出口
var idx int
for ; nodeExec.baseExec.IsOutPortExec(idx); idx++ {
// 找到出口结点
nextExecNode := gp.findOutNextNode(graphConfig, mapNodeExec, nodeExec.Id, idx)
nodeExec.nextNode = append(nodeExec.nextNode, nextExecNode)
}
// 将所有的next填充next
for _, nextOne := range nodeExec.nextNode {
// 对出口进行预处理
err := gp.prepareOneNode(mapNodeExec, nextOne, graphConfig)
if err != nil {
return err
}
}
return nil
}
func (gp *GraphPool) findOutNextNode(graphConfig *graphConfig, mapNodeExec map[string]*execNode, sourceNodeID string, sourcePortIdx int) *execNode {
// 找到出口的NodeID
for _, edge := range graphConfig.Edges {
if edge.SourceNodeID == sourceNodeID && edge.SourcePortIndex == sourcePortIdx {
return mapNodeExec[edge.DesNodeId]
}
}
return nil
}
// prepareOneEntrance 先处理执行Exec入出口连线
func (gp *GraphPool) prepareOneEntrance(graphName string, entranceID int64, nodeCfg *nodeConfig, graphConfig *graphConfig) error {
// 将所有的Node执行结点生成出来
mapNodes, err := gp.genAllNode(graphConfig)
if err != nil {
return err
}
// 从入口结点开始做预处理将next结点都统一生成
nodeExec := mapNodes[nodeCfg.Id]
if nodeExec == nil {
return fmt.Errorf("entrance node %s not found", nodeCfg.Id)
}
err = gp.prepareOneNode(mapNodes, nodeExec, graphConfig)
if err != nil {
return err
}
// 处理inPort前置结点
err = gp.prepareInPort(mapNodes, nodeExec, graphConfig)
if err != nil {
return err
}
var gr graph
gr.entrance = make(map[int64]*execNode, 16)
gr.context = make(map[string]*ExecContext, 16)
gr.entrance[entranceID] = nodeExec
gp.mapGraphs[graphName] = gr
return nil
}
func (gp *GraphPool) findPreInPortNode(mapNodes map[string]*execNode, nodeExec *execNode, graphConfig *graphConfig, portIdx int) *prePortNode {
for _, edge := range graphConfig.Edges {
if edge.DesNodeId == nodeExec.Id && edge.DesPortIndex == portIdx {
srcNode := mapNodes[edge.SourceNodeID]
if srcNode == nil {
return nil
}
var preNode prePortNode
preNode.node = srcNode
preNode.outPortIndex = edge.SourcePortIndex
return &preNode
}
}
return nil
}
func (gp *GraphPool) preparePreInPortNode(mapNodes map[string]*execNode, nodeExec *execNode, graphConfig *graphConfig) error {
// 找到当前结点的所有inPort的前一个端口
for i := 0; i < nodeExec.baseExec.GetInPortCount(); i++ {
// 如果是执行结点,则跳过
if nodeExec.baseExec.IsInPortExec(i) {
continue
}
// 找到入口的上一个结点
preNode := gp.findPreInPortNode(mapNodes, nodeExec, graphConfig, i)
if preNode == nil {
continue
}
nodeExec.preInPort[i] = preNode
}
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
}
}
return nil
}