topology_storage.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package storage
  2. import (
  3. "crypto/rand"
  4. "encoding/json"
  5. "fmt"
  6. "log"
  7. "os"
  8. "path/filepath"
  9. "sync"
  10. "time"
  11. "network-topology-discovery/pkg/models"
  12. )
  13. // TopologyStorage 拓扑存储管理
  14. type TopologyStorage struct {
  15. mu sync.RWMutex
  16. dataDir string
  17. topologies map[string]*models.Topology
  18. currentTopoID string
  19. }
  20. // NewTopologyStorage 创建拓扑存储
  21. func NewTopologyStorage(dataDir string) (*TopologyStorage, error) {
  22. s := &TopologyStorage{
  23. dataDir: dataDir,
  24. topologies: make(map[string]*models.Topology),
  25. }
  26. // 确保数据目录存在
  27. if err := os.MkdirAll(dataDir, 0755); err != nil {
  28. return nil, fmt.Errorf("failed to create data directory: %w", err)
  29. }
  30. // 加载拓扑元数据
  31. if err := s.loadMeta(); err != nil {
  32. if !os.IsNotExist(err) {
  33. return nil, fmt.Errorf("failed to load topology meta: %w", err)
  34. }
  35. log.Printf("Creating new topology storage at %s", dataDir)
  36. }
  37. return s, nil
  38. }
  39. // loadMeta 加载拓扑元数据
  40. func (s *TopologyStorage) loadMeta() error {
  41. metaFile := filepath.Join(s.dataDir, "topologies.json")
  42. data, err := os.ReadFile(metaFile)
  43. if err != nil {
  44. return err
  45. }
  46. var topos []models.Topology
  47. if err := json.Unmarshal(data, &topos); err != nil {
  48. return fmt.Errorf("failed to parse topology meta: %w", err)
  49. }
  50. for i := range topos {
  51. s.topologies[topos[i].ID] = &topos[i]
  52. }
  53. log.Printf("Loaded %d topologies from meta", len(topos))
  54. return nil
  55. }
  56. // saveMeta 保存拓扑元数据
  57. func (s *TopologyStorage) saveMeta() error {
  58. topos := make([]models.Topology, 0, len(s.topologies))
  59. for _, topo := range s.topologies {
  60. topos = append(topos, *topo)
  61. }
  62. data, err := json.MarshalIndent(topos, "", " ")
  63. if err != nil {
  64. return fmt.Errorf("failed to marshal topologies: %w", err)
  65. }
  66. metaFile := filepath.Join(s.dataDir, "topologies.json")
  67. if err := os.WriteFile(metaFile, data, 0644); err != nil {
  68. return fmt.Errorf("failed to write topology meta: %w", err)
  69. }
  70. return nil
  71. }
  72. // CreateTopology 创建新拓扑
  73. func (s *TopologyStorage) CreateTopology(name, description, scanRange string, sshPort int, username string) (*models.Topology, error) {
  74. s.mu.Lock()
  75. defer s.mu.Unlock()
  76. topo := &models.Topology{
  77. ID: generateID(),
  78. Name: name,
  79. Description: description,
  80. ScanRange: scanRange,
  81. SSHPort: sshPort,
  82. Username: username,
  83. CreatedAt: time.Now(),
  84. UpdatedAt: time.Now(),
  85. DeviceCount: 0,
  86. }
  87. s.topologies[topo.ID] = topo
  88. // 创建该拓扑的设备文件
  89. deviceFile := filepath.Join(s.dataDir, topo.ID+"_devices.json")
  90. if _, err := os.Stat(deviceFile); os.IsNotExist(err) {
  91. if err := os.WriteFile(deviceFile, []byte("[]"), 0644); err != nil {
  92. return nil, fmt.Errorf("failed to create device file: %w", err)
  93. }
  94. }
  95. // 保存元数据
  96. if err := s.saveMeta(); err != nil {
  97. return nil, err
  98. }
  99. log.Printf("Topology created: %s (%s)", topo.Name, topo.ID)
  100. return topo, nil
  101. }
  102. // GetTopology 获取拓扑
  103. func (s *TopologyStorage) GetTopology(id string) (*models.Topology, error) {
  104. s.mu.RLock()
  105. defer s.mu.RUnlock()
  106. topo, exists := s.topologies[id]
  107. if !exists {
  108. return nil, fmt.Errorf("topology not found: %s", id)
  109. }
  110. return topo, nil
  111. }
  112. // GetAllTopologies 获取所有拓扑
  113. func (s *TopologyStorage) GetAllTopologies() ([]models.Topology, error) {
  114. s.mu.RLock()
  115. defer s.mu.RUnlock()
  116. topos := make([]models.Topology, 0, len(s.topologies))
  117. for _, topo := range s.topologies {
  118. topos = append(topos, *topo)
  119. }
  120. return topos, nil
  121. }
  122. // UpdateTopology 更新拓扑
  123. func (s *TopologyStorage) UpdateTopology(id string, updates map[string]interface{}) error {
  124. s.mu.Lock()
  125. defer s.mu.Unlock()
  126. topo, exists := s.topologies[id]
  127. if !exists {
  128. return fmt.Errorf("topology not found: %s", id)
  129. }
  130. if name, ok := updates["name"].(string); ok {
  131. topo.Name = name
  132. }
  133. if desc, ok := updates["description"].(string); ok {
  134. topo.Description = desc
  135. }
  136. if scanRange, ok := updates["scan_range"].(string); ok {
  137. topo.ScanRange = scanRange
  138. }
  139. if sshPort, ok := updates["ssh_port"].(float64); ok {
  140. topo.SSHPort = int(sshPort)
  141. }
  142. if username, ok := updates["username"].(string); ok {
  143. topo.Username = username
  144. }
  145. topo.UpdatedAt = time.Now()
  146. return s.saveMeta()
  147. }
  148. // DeleteTopology 删除拓扑及其所有数据
  149. func (s *TopologyStorage) DeleteTopology(id string) error {
  150. s.mu.Lock()
  151. defer s.mu.Unlock()
  152. if _, exists := s.topologies[id]; !exists {
  153. return fmt.Errorf("topology not found: %s", id)
  154. }
  155. // 删除设备文件
  156. deviceFile := filepath.Join(s.dataDir, id+"_devices.json")
  157. if err := os.Remove(deviceFile); err != nil && !os.IsNotExist(err) {
  158. log.Printf("Warning: failed to delete device file for topology %s: %v", id, err)
  159. }
  160. delete(s.topologies, id)
  161. // 更新当前拓扑
  162. if s.currentTopoID == id {
  163. s.currentTopoID = ""
  164. }
  165. return s.saveMeta()
  166. }
  167. // SetCurrentTopology 设置当前拓扑
  168. func (s *TopologyStorage) SetCurrentTopology(id string) error {
  169. if _, err := s.GetTopology(id); err != nil {
  170. return err
  171. }
  172. s.mu.Lock()
  173. defer s.mu.Unlock()
  174. s.currentTopoID = id
  175. log.Printf("Current topology set to: %s", id)
  176. return nil
  177. }
  178. // GetCurrentTopologyID 获取当前拓扑ID
  179. func (s *TopologyStorage) GetCurrentTopologyID() string {
  180. s.mu.RLock()
  181. defer s.mu.RUnlock()
  182. return s.currentTopoID
  183. }
  184. // GetDeviceFilePath 获取拓扑的设备文件路径
  185. func (s *TopologyStorage) GetDeviceFilePath(topoID string) string {
  186. return filepath.Join(s.dataDir, topoID+"_devices.json")
  187. }
  188. // generateID 生成唯一ID
  189. func generateID() string {
  190. b := make([]byte, 16)
  191. rand.Read(b)
  192. return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
  193. }