159 lines
4.0 KiB
Go
159 lines
4.0 KiB
Go
package diagram
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"modelRT/constant"
|
|
"modelRT/network"
|
|
|
|
"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
|
|
// TODO 在添加拓扑信息时是否考虑过滤重复节点
|
|
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}
|
|
}
|
|
|
|
// Process the situation where the to node is taken as the parent node while deleting edges
|
|
childvertex := g.VerticeLinks[toKey]
|
|
err := g.DelNode(toKey)
|
|
if err != nil {
|
|
return fmt.Errorf("delete edge failed: %w", err)
|
|
}
|
|
|
|
fmt.Println("fromKeys:", fromKeys)
|
|
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]
|
|
if len(vertex) == 1 {
|
|
g.DelNode(fromKey)
|
|
} else {
|
|
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)
|
|
}
|
|
}
|
|
|
|
// UpdateEdge update edge link info between two verticeLinks
|
|
func (g *Graph) UpdateEdge(changeInfo network.TopologicUUIDChangeInfos) error {
|
|
if changeInfo.ChangeType == constant.UUIDFromChangeType || changeInfo.ChangeType == constant.UUIDToChangeType {
|
|
g.DelEdge(changeInfo.OldUUIDFrom, changeInfo.OldUUIDTo)
|
|
g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo)
|
|
} else {
|
|
g.AddEdge(changeInfo.NewUUIDFrom, changeInfo.NewUUIDTo)
|
|
}
|
|
return nil
|
|
}
|