package controller import ( "ezops/model" "net/http" "strconv" "sync" "github.com/gin-gonic/gin" "gorm.io/gorm" ) // SNMPHandler SNMP 设备管理 + 采集 handler // Logan.Li type SNMPHandler struct { db *gorm.DB stopCh chan struct{} wg sync.WaitGroup } // NewSNMPHandler 创建 SNMP handler func NewSNMPHandler(db *gorm.DB) *SNMPHandler { return &SNMPHandler{db: db, stopCh: make(chan struct{})} } // ========== SNMP Device CRUD ========== // ListDevices 列出 SNMP 设备 // GET /api/v1/snmp/devices?page=1&page_size=20&keyword= func (h *SNMPHandler) ListDevices(c *gin.Context) { var devices []model.SNMPDevice q := h.db.Model(&model.SNMPDevice{}) if kw := c.Query("keyword"); kw != "" { q = q.Where("name LIKE ? OR ip LIKE ?", "%"+kw+"%", "%"+kw+"%") } page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var total int64 q.Count(&total) q.Offset((page - 1) * pageSize).Limit(pageSize).Order("name ASC").Find(&devices) if devices == nil { devices = []model.SNMPDevice{} } c.JSON(http.StatusOK, model.Response{Code: 200, Data: gin.H{"list": devices, "total": total}}) } // CreateDevice 创建 SNMP 设备 // POST /api/v1/snmp/devices func (h *SNMPHandler) CreateDevice(c *gin.Context) { var req struct { Name string `json:"name" binding:"required"` IP string `json:"ip" binding:"required"` Port int `json:"port"` SnmpVersion string `json:"snmp_version"` Version string `json:"version"` Community string `json:"community"` TemplateID uint `json:"template_id"` DeviceType string `json:"device_type"` Vendor string `json:"vendor"` Description string `json:"description"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()}) return } ver := req.SnmpVersion if ver == "" { ver = req.Version } if ver == "" { ver = "v2c" } device := model.SNMPDevice{ Name: req.Name, IP: req.IP, Port: req.Port, Version: model.SNMPVersion(ver), Community: req.Community, TemplateID: req.TemplateID, DeviceType: req.DeviceType, Vendor: req.Vendor, Description: req.Description, Status: model.SNMPDeviceOffline, } if device.Port == 0 { device.Port = 161 } if device.Community == "" { device.Community = "public" } if err := h.db.Create(&device).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: err.Error()}) return } c.JSON(http.StatusOK, model.Response{Code: 200, Data: device, Message: "创建成功"}) } // UpdateDevice 更新 SNMP 设备 // PUT /api/v1/snmp/devices/:id func (h *SNMPHandler) UpdateDevice(c *gin.Context) { id := c.Param("id") var device model.SNMPDevice if err := h.db.First(&device, id).Error; err != nil { c.JSON(http.StatusNotFound, model.Response{Code: 404, Message: "设备不存在"}) return } if err := c.ShouldBindJSON(&device); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()}) return } h.db.Save(&device) c.JSON(http.StatusOK, model.Response{Code: 200, Data: device, Message: "更新成功"}) } // DeleteDevice 删除 SNMP 设备 // DELETE /api/v1/snmp/devices/:id func (h *SNMPHandler) DeleteDevice(c *gin.Context) { id := c.Param("id") if err := h.db.Delete(&model.SNMPDevice{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: err.Error()}) return } c.JSON(http.StatusOK, model.Response{Code: 200, Message: "删除成功"}) } // BatchDeleteDevices 批量删除 // DELETE /api/v1/snmp/devices/batch-delete func (h *SNMPHandler) BatchDeleteDevices(c *gin.Context) { var req model.IDsRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()}) return } h.db.Where("id IN ?", req.IDs).Delete(&model.SNMPDevice{}) c.JSON(http.StatusOK, model.Response{Code: 200, Message: "批量删除成功"}) } // ========== SNMP Template CRUD ========== // ListTemplates 列出 OID 模板(含 OID 条目)// Logan.Li // GET /api/v1/snmp/templates func (h *SNMPHandler) ListTemplates(c *gin.Context) { var templates []model.SNMPTemplate h.db.Preload("OIDs", func(db *gorm.DB) *gorm.DB { return db.Order("sort_order ASC") }).Order("name ASC").Find(&templates) if templates == nil { templates = []model.SNMPTemplate{} } c.JSON(http.StatusOK, model.Response{Code: 200, Data: gin.H{"list": templates, "total": len(templates)}}) } // CreateTemplate 创建 OID 模板 // POST /api/v1/snmp/templates func (h *SNMPHandler) CreateTemplate(c *gin.Context) { var template model.SNMPTemplate if err := c.ShouldBindJSON(&template); err != nil { c.JSON(http.StatusBadRequest, model.Response{Code: 400, Message: err.Error()}) return } if err := h.db.Create(&template).Error; err != nil { c.JSON(http.StatusInternalServerError, model.Response{Code: 500, Message: err.Error()}) return } c.JSON(http.StatusOK, model.Response{Code: 200, Data: template, Message: "创建成功"}) } // ========== SNMP Statistics ========== // GetSNMPStats 获取 SNMP 概览统计 // GET /api/v1/snmp/stats func (h *SNMPHandler) GetSNMPStats(c *gin.Context) { var total, online int64 h.db.Model(&model.SNMPDevice{}).Count(&total) h.db.Model(&model.SNMPDevice{}).Where("status = ?", "online").Count(&online) c.JSON(http.StatusOK, model.Response{Code: 200, Data: gin.H{ "total": total, "online": online, "abnormal": total - online, }}) }