From 42e7d026252f9f0238e245bec806f3aa3e864aab Mon Sep 17 00:00:00 2001 From: douxu Date: Wed, 27 Nov 2024 09:11:48 +0800 Subject: [PATCH] complete the function of loading topology information and circuit diagram information --- config/config.go | 7 + database/query_component.go | 2 - database/{init_page.go => query_page.go} | 0 .../{init_topologic.go => query_topologic.go} | 45 ++++- diagram/component_map.go | 6 +- diagram/graph.go | 136 ++++++++++++++++ diagram/topologic_set.go | 154 ++---------------- main.go | 6 + orm/circuit_diagram.go | 12 -- orm/circuit_diagram_overview.go | 16 -- 10 files changed, 203 insertions(+), 181 deletions(-) rename database/{init_page.go => query_page.go} (100%) rename database/{init_topologic.go => query_topologic.go} (53%) create mode 100644 diagram/graph.go delete mode 100644 orm/circuit_diagram.go delete mode 100644 orm/circuit_diagram_overview.go diff --git a/config/config.go b/config/config.go index e03a7dc..01f7555 100644 --- a/config/config.go +++ b/config/config.go @@ -13,6 +13,9 @@ import ( // ModelRTConfig define config stuct of model runtime server type ModelRTConfig struct { + GridID int64 + ZoneID int64 + StationID int64 ParseConcurrentQuantity int // parse comtrade file concurrent quantity PostgresDBURI string LCfg log.CutLogConfig // log config @@ -46,6 +49,10 @@ func ReadAndInitConfig(configDir, configName, configType string) (modelRTConfig modelRTConfig.LCfg.MaxBackups = config.GetInt("log_maxbackups") modelRTConfig.LCfg.MaxAge = config.GetInt("log_maxage") + // init model base config from config.yaml + modelRTConfig.GridID = config.GetInt64("grid_id") + modelRTConfig.GridID = config.GetInt64("zone_id") + modelRTConfig.GridID = config.GetInt64("station_id") modelRTConfig.ParseConcurrentQuantity = config.GetInt("parse_concurrent_quantity") return modelRTConfig diff --git a/database/query_component.go b/database/query_component.go index af01b8d..d87b511 100644 --- a/database/query_component.go +++ b/database/query_component.go @@ -29,13 +29,11 @@ func QueryCircuitDiagramComponentFromDB(ctx context.Context, pool *ants.PoolWith } for _, component := range Components { - fmt.Println(component) pool.Invoke(config.ModelParseConfig{ ComponentInfo: component, Context: ctx, }) } - // TODO 加载 Topologic表拓扑关系 return nil } diff --git a/database/init_page.go b/database/query_page.go similarity index 100% rename from database/init_page.go rename to database/query_page.go diff --git a/database/init_topologic.go b/database/query_topologic.go similarity index 53% rename from database/init_topologic.go rename to database/query_topologic.go index 682f737..fde9fbf 100644 --- a/database/init_topologic.go +++ b/database/query_topologic.go @@ -3,11 +3,12 @@ package database import ( "context" - "fmt" "time" + "modelRT/diagram" "modelRT/orm" + "github.com/gofrs/uuid" "go.uber.org/zap" "gorm.io/gorm/clause" ) @@ -39,14 +40,46 @@ func QueryTopologicByPageID(ctx context.Context, logger *zap.Logger, pageID int6 // InitCircuitDiagramTopologic return circuit diagram topologic info from postgres func InitCircuitDiagramTopologic(topologicNodes []orm.Topologic) error { - // find root node - var rootNode orm.Topologic - for index, node := range topologicNodes { + var rootVertex uuid.UUID + + for _, node := range topologicNodes { if node.UUIDFrom.IsNil() { - rootNode = topologicNodes[index] + rootVertex = node.UUIDTo + break } } - fmt.Println(rootNode) + topologicSet := diagram.NewGraph(rootVertex) + + for _, node := range topologicNodes { + if node.UUIDFrom.IsNil() { + continue + } + topologicSet.AddEdge(node.UUIDFrom, node.UUIDTo) + } + return nil +} + +// QueryTopologicFromDB return the result of query topologic info from postgresDB +func QueryTopologicFromDB(ctx context.Context, logger *zap.Logger, gridID, zoneID, stationID int64) error { + allPages, err := QueryAllPages(ctx, logger, gridID, zoneID, stationID) + if err != nil { + logger.Error("query all pages info failed", zap.Int64("gridID", gridID), zap.Int64("zoneID", zoneID), zap.Int64("stationID", stationID), zap.Error(err)) + return err + } + + for _, page := range allPages { + topologicInfos, err := QueryTopologicByPageID(ctx, logger, page.ID) + if err != nil { + logger.Error("query topologic info by pageID failed", zap.Int64("pageID", page.ID), zap.Error(err)) + return err + } + err = InitCircuitDiagramTopologic(topologicInfos) + if err != nil { + logger.Error("init topologic failed", zap.Error(err)) + return err + } + + } return nil } diff --git a/diagram/component_map.go b/diagram/component_map.go index 1c6fe9b..7c2bb32 100644 --- a/diagram/component_map.go +++ b/diagram/component_map.go @@ -2,6 +2,7 @@ package diagram import ( "errors" + "fmt" "sync" cmap "github.com/orcaman/concurrent-map/v2" @@ -12,12 +13,11 @@ var DiagramsOverview sync.Map func GetComponentMap(key string) (*cmap.ConcurrentMap[string, any], error) { value, ok := DiagramsOverview.Load(key) if !ok { - newMap := cmap.New[any]() - return &newMap, nil + return nil, fmt.Errorf("can not find graph by pageID:%s", key) } paramsMap, ok := value.(*cmap.ConcurrentMap[string, any]) if !ok { - return nil, errors.New("") + return nil, errors.New("convert to component map struct failed") } return paramsMap, nil } diff --git a/diagram/graph.go b/diagram/graph.go new file mode 100644 index 0000000..7f43735 --- /dev/null +++ b/diagram/graph.go @@ -0,0 +1,136 @@ +package diagram + +import ( + "errors" + "fmt" + "sync" + + "github.com/gofrs/uuid" +) + +// Graph represents a topological structure using an adjacency list +type Graph struct { + sync.RWMutex + // 根节点 + RootVertex uuid.UUID + // 游离节点 + FreeVertexs map[string]struct{} + VerticeLinks map[string][]uuid.UUID + // 存储多个上级节点同时指向同一下级节点的情况,key为下级节点,value为上级节点集合 + BackLinks map[string][]uuid.UUID +} + +// NewGraph creates a new graph +func NewGraph(root uuid.UUID) *Graph { + return &Graph{ + RootVertex: root, + FreeVertexs: make(map[string]struct{}), + VerticeLinks: make(map[string][]uuid.UUID), + BackLinks: make(map[string][]uuid.UUID), + } +} + +// AddNode adds a node to the graph +func (g *Graph) AddNode(vertex string) { + if _, exists := g.VerticeLinks[vertex]; !exists { + g.VerticeLinks[vertex] = []uuid.UUID{} + } +} + +// CreateBackLink adds a node to the graph +func (g *Graph) CreateBackLink(vertex string) { + if _, exists := g.BackLinks[vertex]; !exists { + g.BackLinks[vertex] = []uuid.UUID{} + } +} + +// AddEdge adds an edge between two VerticeLinks +func (g *Graph) AddEdge(from, to uuid.UUID) { + g.Lock() + defer g.Unlock() + + fromKey := from.String() + toKey := to.String() + + g.CreateBackLink(toKey) + g.BackLinks[toKey] = append(g.BackLinks[toKey], from) + + g.AddNode(fromKey) + g.AddNode(toKey) + g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], to) + + // 创建新的拓扑信息时,如果被链接的点已经存在于游离节点中 + // 则将其移除 + if _, exist := g.FreeVertexs[toKey]; exist { + delete(g.FreeVertexs, toKey) + } +} + +// DelNode delete a node to the graph +func (g *Graph) DelNode(vertex string) error { + childNodes, exists := g.VerticeLinks[vertex] + if exists { + if len(childNodes) > 1 { + return errors.New("delete node failed,that vertex contains more than one child node") + } + delete(g.VerticeLinks, vertex) + } + + parentNodes, exists := g.BackLinks[vertex] + if exists { + if len(parentNodes) > 1 { + return errors.New("delete node failed,that vertex contains more than one parent node") + } + delete(g.BackLinks, vertex) + } else { + return errors.New("that vertex don't have parent node") + } + return nil +} + +// DelEdge delete an edge between two VerticeLinks +func (g *Graph) DelEdge(from, to uuid.UUID) error { + g.Lock() + defer g.Unlock() + + toKey := to.String() + var fromKeys []uuid.UUID + if _, exist := g.BackLinks[toKey]; exist { + fromKeys = g.BackLinks[toKey] + } else { + fromKeys = []uuid.UUID{from} + } + + childvertex := g.VerticeLinks[toKey] + err := g.DelNode(toKey) + if err != nil { + return fmt.Errorf("delete edge failed: %w", err) + } + + for _, fromUUID := range fromKeys { + fromKey := fromUUID.String() + var delIndex int + for index, vertex := range g.VerticeLinks[fromKey] { + if vertex == to { + delIndex = index + } + } + vertex := g.VerticeLinks[fromKey] + copy(vertex[delIndex:], vertex[delIndex+1:]) + vertex = vertex[:len(vertex)-1] + g.VerticeLinks[fromKey] = vertex + } + + fromKey := from.String() + g.VerticeLinks[fromKey] = append(g.VerticeLinks[fromKey], childvertex...) + return nil +} + +// PrintGraph prints the graph in adjacency list format +func (g *Graph) PrintGraph() { + g.RLock() // 读锁 + defer g.RUnlock() + for vertex, edges := range g.VerticeLinks { + fmt.Printf("%s -> %v\n", vertex, edges) + } +} diff --git a/diagram/topologic_set.go b/diagram/topologic_set.go index a5e6f53..3d2682d 100644 --- a/diagram/topologic_set.go +++ b/diagram/topologic_set.go @@ -4,148 +4,18 @@ import ( "errors" "fmt" "sync" - - "github.com/gofrs/uuid" ) -// Graph represents a topological structure using an adjacency list -type Graph struct { - sync.RWMutex - // 根节点 - rootVertex uuid.UUID - // 游离节点 - freeVertexs map[string]struct{} - verticeLinks map[string][]uuid.UUID - // 存储多个上级节点同时指向同一下级节点的情况,key为下级节点,value为上级节点集合 - backLinks map[string][]uuid.UUID +var GraphOverview sync.Map + +func GetGraphMap(key string) (*Graph, error) { + value, ok := GraphOverview.Load(key) + if !ok { + return nil, fmt.Errorf("can not find graph by pageID:%s", key) + } + graph, ok := value.(*Graph) + if !ok { + return nil, errors.New("convert to graph struct failed") + } + return graph, nil } - -// NewGraph creates a new graph -func NewGraph(root uuid.UUID) *Graph { - return &Graph{ - rootVertex: root, - freeVertexs: make(map[string]struct{}), - verticeLinks: make(map[string][]uuid.UUID), - backLinks: make(map[string][]uuid.UUID), - } -} - -// AddNode adds a node to the graph -func (g *Graph) AddNode(vertex string) { - if _, exists := g.verticeLinks[vertex]; !exists { - g.verticeLinks[vertex] = []uuid.UUID{} - } -} - -// CreateBackLink adds a node to the graph -func (g *Graph) CreateBackLink(vertex string) { - if _, exists := g.backLinks[vertex]; !exists { - g.backLinks[vertex] = []uuid.UUID{} - } -} - -// AddEdge adds an edge between two verticeLinks -func (g *Graph) AddEdge(from, to uuid.UUID) { - g.Lock() - defer g.Unlock() - - fromKey := from.String() - toKey := to.String() - - g.CreateBackLink(toKey) - g.backLinks[toKey] = append(g.backLinks[toKey], from) - - g.AddNode(fromKey) - g.AddNode(toKey) - g.verticeLinks[fromKey] = append(g.verticeLinks[fromKey], to) - - // 创建新的拓扑信息时,如果被链接的点已经存在于游离节点中 - // 则将其移除 - if _, exist := g.freeVertexs[toKey]; exist { - delete(g.freeVertexs, toKey) - } -} - -// DelNode delete a node to the graph -func (g *Graph) DelNode(vertex string) error { - childNodes, exists := g.verticeLinks[vertex] - if exists { - if len(childNodes) > 1 { - return errors.New("delete node failed,that vertex contains more than one child node") - } - delete(g.verticeLinks, vertex) - } - - parentNodes, exists := g.backLinks[vertex] - if exists { - if len(parentNodes) > 1 { - return errors.New("delete node failed,that vertex contains more than one parent node") - } - delete(g.backLinks, vertex) - } else { - return errors.New("that vertex don't have parent node") - } - return nil -} - -// DelEdge delete an edge between two verticeLinks -func (g *Graph) DelEdge(from, to uuid.UUID) error { - g.Lock() - defer g.Unlock() - - toKey := to.String() - var fromKeys []uuid.UUID - if _, exist := g.backLinks[toKey]; exist { - fromKeys = g.backLinks[toKey] - } else { - fromKeys = []uuid.UUID{from} - } - - childvertex := g.verticeLinks[toKey] - err := g.DelNode(toKey) - if err != nil { - return fmt.Errorf("delete edge failed: %w", err) - } - - for _, fromUUID := range fromKeys { - fromKey := fromUUID.String() - var delIndex int - for index, vertex := range g.verticeLinks[fromKey] { - if vertex == to { - delIndex = index - } - } - vertex := g.verticeLinks[fromKey] - copy(vertex[delIndex:], vertex[delIndex+1:]) - vertex = vertex[:len(vertex)-1] - g.verticeLinks[fromKey] = vertex - } - - fromKey := from.String() - g.verticeLinks[fromKey] = append(g.verticeLinks[fromKey], childvertex...) - return nil -} - -// PrintGraph prints the graph in adjacency list format -func (g *Graph) PrintGraph() { - g.RLock() // 读锁 - defer g.RUnlock() - for vertex, edges := range g.verticeLinks { - fmt.Printf("%s -> %v\n", vertex, edges) - } -} - -// func main() { -// graph := NewGraph() - -// // Add verticeLinks and edges -// graph.AddEdge("A", "B") -// graph.AddEdge("A", "C") -// graph.AddEdge("B", "D") -// graph.AddEdge("C", "D") -// graph.AddEdge("C", "E") -// graph.AddEdge("E", "F") - -// // Print the graph -// graph.PrintGraph() -// } diff --git a/main.go b/main.go index f8b615c..e1085c7 100644 --- a/main.go +++ b/main.go @@ -73,6 +73,12 @@ func main() { panic(err) } + err = database.QueryTopologicFromDB(ctx, logger, modelRTConfig.GridID, modelRTConfig.ZoneID, modelRTConfig.StationID) + if err != nil { + logger.Error("load topologic info from postgres failed", zap.Error(err)) + panic(err) + } + engine := gin.Default() engine.Use(limiter.Middleware) engine.GET("/model/model_load", handler.ModelLoad) diff --git a/orm/circuit_diagram.go b/orm/circuit_diagram.go deleted file mode 100644 index 2eca324..0000000 --- a/orm/circuit_diagram.go +++ /dev/null @@ -1,12 +0,0 @@ -// Package orm define database data struct -package orm - -type CircuitDiagram struct { - ID int64 `gorm:""` - ParentID int64 - Type int - UUID string - OtherParams string - CreatedTime int64 - UpdateTime int64 -} diff --git a/orm/circuit_diagram_overview.go b/orm/circuit_diagram_overview.go deleted file mode 100644 index 1265435..0000000 --- a/orm/circuit_diagram_overview.go +++ /dev/null @@ -1,16 +0,0 @@ -// Package orm define database data struct -package orm - -import "time" - -type CircuitDiagramOverview struct { - ID int64 `gorm:""` - Name string - CreatedTime time.Time - UpdateTime time.Time -} - -// TableName func respresent return table name of circuit diagram overview -func (co *CircuitDiagramOverview) TableName() string { - return "circuit_diagram_overview" -}