feat(snmp,ui): устройства за портом (MAC/IP) в таблице 2

Добавил сбор FDB/ARP по SNMP (BRIDGE-MIB + ipNetToMedia), хранение и API /port-devices.
В UI Таблица 2 теперь показывает MAC/IP за выбранным портом после клика по строке Таблицы 1.

Made-with: Cursor
This commit is contained in:
Луценко Андрей Анатольевич
2026-04-10 17:44:42 +10:00
parent 526c67b5b1
commit 5b82901565
7 changed files with 350 additions and 39 deletions
+39
View File
@@ -69,6 +69,7 @@ func (h *Handler) Routes() http.Handler {
mux.HandleFunc("GET /api/scans/{id}/snmp", h.getScanSNMP)
mux.HandleFunc("GET /api/scans/{id}/lldp", h.getScanLLDP)
mux.HandleFunc("GET /api/scans/{id}/interfaces", h.getScanInterfaces)
mux.HandleFunc("GET /api/scans/{id}/port-devices", h.getScanPortDevices)
mux.HandleFunc("GET /api/scans/{id}/links", h.getScanLinks)
mux.HandleFunc("GET /api/scans/{id}/topology", h.getScanTopology)
mux.HandleFunc("POST /api/admin/purge-scans", h.postAdminPurgeScans)
@@ -330,6 +331,44 @@ func (h *Handler) getScanInterfaces(w http.ResponseWriter, r *http.Request) {
})
}
func (h *Handler) getScanPortDevices(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if id == "" {
writeError(w, http.StatusBadRequest, "scan id is required")
return
}
if _, ok := h.store.GetScan(id); !ok {
writeError(w, http.StatusNotFound, "scan not found")
return
}
ip := strings.TrimSpace(r.URL.Query().Get("ip"))
if ip == "" {
writeError(w, http.StatusBadRequest, "query parameter ip is required")
return
}
ifIndex := 0
if raw := strings.TrimSpace(r.URL.Query().Get("if_index")); raw != "" {
n, err := strconv.Atoi(raw)
if err != nil || n < 0 {
writeError(w, http.StatusBadRequest, "if_index must be >= 0")
return
}
ifIndex = n
}
limit := 20000
if raw := r.URL.Query().Get("limit"); raw != "" {
n, err := strconv.Atoi(raw)
if err != nil || n <= 0 || n > 100000 {
writeError(w, http.StatusBadRequest, "limit must be between 1 and 100000")
return
}
limit = n
}
writeJSON(w, http.StatusOK, map[string]any{
"items": h.store.ListPortDeviceResults(id, ip, ifIndex, limit),
})
}
func (h *Handler) getScanLinks(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
if id == "" {