Feat: 添加SQLite数据库持久化和设备列表显示

- 使用SQLite存储设备数据,重启后数据不丢失
- 添加 /api/devices 接口获取所有设备
- 前端显示完整的设备列表(含接口数、邻居数)
- 设备添加/扫描后自动刷新列表
- 启动时从数据库加载设备到拓扑构建器
This commit is contained in:
Your Name
2026-04-25 23:42:02 +08:00
parent 95ab5e0fdb
commit 32fadd9a7e
5 changed files with 339 additions and 2 deletions
+61 -1
View File
@@ -14,6 +14,7 @@ import (
"network-topology-discovery/internal/config"
"network-topology-discovery/internal/device"
"network-topology-discovery/internal/scanner"
"network-topology-discovery/internal/storage"
"network-topology-discovery/internal/topology"
"network-topology-discovery/pkg/models"
)
@@ -22,6 +23,7 @@ import (
type App struct {
config *config.Config
builder *topology.Builder
storage *storage.Storage
tasks map[string]*models.ScanTask
mu sync.RWMutex
httpServer *http.Server
@@ -29,11 +31,33 @@ type App struct {
// NewApp 创建应用
func NewApp(cfg *config.Config) *App {
return &App{
// 初始化数据库
store, err := storage.NewStorage("network-topology.db")
if err != nil {
log.Printf("Warning: failed to initialize database: %v", err)
}
app := &App{
config: cfg,
builder: topology.NewBuilder(),
storage: store,
tasks: make(map[string]*models.ScanTask),
}
// 从数据库加载设备到拓扑构建器
if store != nil {
devices, err := store.GetAllDevices()
if err != nil {
log.Printf("Warning: failed to load devices from database: %v", err)
} else {
log.Printf("Loaded %d devices from database", len(devices))
for _, dev := range devices {
app.builder.AddDevice(dev)
}
}
}
return app
}
// Start 启动应用
@@ -56,6 +80,7 @@ func (app *App) Start() error {
mux.HandleFunc("/api/scan", app.handleScan)
mux.HandleFunc("/api/scan/{id}", app.handleScanProgress)
mux.HandleFunc("/api/topology", app.handleTopology)
mux.HandleFunc("/api/devices", app.handleGetDevices)
mux.HandleFunc("/api/device", app.handleAddDevice)
mux.HandleFunc("/api/device/{id}", app.handleDeviceDetail)
@@ -183,6 +208,13 @@ func (app *App) runScan(task *models.ScanTask, cidr string, sshPort int, usernam
if discoveredDevice != nil {
devices = append(devices, *discoveredDevice)
app.builder.AddDevice(*discoveredDevice)
// 保存到数据库
if app.storage != nil {
if err := app.storage.SaveDevice(discoveredDevice); err != nil {
log.Printf("Warning: failed to save device %s to database: %v", ip, err)
}
}
}
// 更新进度
@@ -221,6 +253,27 @@ func (app *App) handleTopology(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(graph)
}
// 处理获取所有设备
func (app *App) handleGetDevices(w http.ResponseWriter, r *http.Request) {
var devices []models.Device
// 优先从数据库获取
if app.storage != nil {
var err error
devices, err = app.storage.GetAllDevices()
if err != nil {
log.Printf("Warning: failed to get devices from database: %v", err)
// 降级到从builder获取
devices = app.builder.GetDevices()
}
} else {
devices = app.builder.GetDevices()
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(devices)
}
// 处理添加设备
func (app *App) handleAddDevice(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
@@ -251,6 +304,13 @@ func (app *App) handleAddDevice(w http.ResponseWriter, r *http.Request) {
app.builder.AddDevice(*dev)
// 保存到数据库
if app.storage != nil {
if err := app.storage.SaveDevice(dev); err != nil {
log.Printf("Warning: failed to save device to database: %v", err)
}
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(dev)
}