feat(ui,snmp): IF-MIB интерфейсы в табл.1 связей, слияние с LLDP, сортировка по локальному порту

Made-with: Cursor
This commit is contained in:
Луценко Андрей Анатольевич
2026-04-10 16:04:16 +10:00
parent 2388b5f3ff
commit a7f80eac9a
7 changed files with 448 additions and 40 deletions
+65 -11
View File
@@ -67,6 +67,8 @@ type Store interface {
ListSNMPResults(scanID string, limit int) []SNMPResult
SaveLLDPResult(scanID string, result LLDPResult) error
ListLLDPResults(scanID string, limit int) []LLDPResult
SaveInterfaceResult(scanID string, result InterfaceResult) error
ListInterfaceResults(scanID string, filterIP string, limit int) []InterfaceResult
}
type HostResult struct {
@@ -101,22 +103,34 @@ type LLDPResult struct {
CheckedAt time.Time `json:"checked_at"`
}
// InterfaceResult — строка IF-MIB (interfaces/ifTable + ifName) для устройства.
type InterfaceResult struct {
IP string `json:"ip"`
IfIndex int `json:"if_index"`
IfDescr string `json:"if_descr"`
IfName string `json:"if_name"`
IfOperStatus string `json:"if_oper_status"`
CheckedAt time.Time `json:"checked_at"`
}
type MemoryStore struct {
mu sync.RWMutex
jobs map[string]ScanJob
hosts map[string][]HostResult
ports map[string][]OpenPortResult
snmp map[string][]SNMPResult
lldp map[string][]LLDPResult
mu sync.RWMutex
jobs map[string]ScanJob
hosts map[string][]HostResult
ports map[string][]OpenPortResult
snmp map[string][]SNMPResult
lldp map[string][]LLDPResult
ifaces map[string][]InterfaceResult
}
func NewMemoryStore() *MemoryStore {
return &MemoryStore{
jobs: make(map[string]ScanJob),
hosts: make(map[string][]HostResult),
ports: make(map[string][]OpenPortResult),
snmp: make(map[string][]SNMPResult),
lldp: make(map[string][]LLDPResult),
jobs: make(map[string]ScanJob),
hosts: make(map[string][]HostResult),
ports: make(map[string][]OpenPortResult),
snmp: make(map[string][]SNMPResult),
lldp: make(map[string][]LLDPResult),
ifaces: make(map[string][]InterfaceResult),
}
}
@@ -305,6 +319,46 @@ func (s *MemoryStore) ListLLDPResults(scanID string, limit int) []LLDPResult {
return out
}
func (s *MemoryStore) SaveInterfaceResult(scanID string, result InterfaceResult) error {
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.jobs[scanID]; !ok {
return errors.New("scan not found")
}
s.ifaces[scanID] = append(s.ifaces[scanID], result)
return nil
}
func (s *MemoryStore) ListInterfaceResults(scanID string, filterIP string, limit int) []InterfaceResult {
if limit <= 0 {
limit = 4096
}
s.mu.RLock()
defer s.mu.RUnlock()
items := s.ifaces[scanID]
var filtered []InterfaceResult
if filterIP != "" {
for _, r := range items {
if r.IP == filterIP {
filtered = append(filtered, r)
}
}
} else {
filtered = append(filtered, items...)
}
sort.Slice(filtered, func(i, j int) bool { return filtered[i].IfIndex < filtered[j].IfIndex })
if len(filtered) <= limit {
out := make([]InterfaceResult, len(filtered))
copy(out, filtered)
return out
}
out := make([]InterfaceResult, limit)
copy(out, filtered[:limit])
return out
}
func applyDefaultOptions(opts *ScanOptions) {
if opts.PingTimeoutMS <= 0 {
opts.PingTimeoutMS = 700