|
| 1 | +package unifi |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/json" |
| 5 | + "fmt" |
| 6 | +) |
| 7 | + |
| 8 | +// GetTopology returns network topology data for all provided sites. |
| 9 | +// Uses the v2 API endpoint: GET /proxy/network/v2/api/site/{site}/topology |
| 10 | +func (u *Unifi) GetTopology(sites []*Site) ([]*Topology, error) { |
| 11 | + topologies := make([]*Topology, 0) |
| 12 | + |
| 13 | + for _, site := range sites { |
| 14 | + path := fmt.Sprintf(APITopologyPath, site.Name) |
| 15 | + |
| 16 | + body, err := u.GetJSON(path) |
| 17 | + if err != nil { |
| 18 | + return nil, fmt.Errorf("failed to fetch topology for site %s: %w", site.SiteName, err) |
| 19 | + } |
| 20 | + |
| 21 | + var topo Topology |
| 22 | + if err := json.Unmarshal(body, &topo); err != nil { |
| 23 | + return nil, fmt.Errorf("failed to parse topology for site %s: %w", site.SiteName, err) |
| 24 | + } |
| 25 | + |
| 26 | + topo.SiteName = site.SiteName |
| 27 | + topo.SourceName = u.URL |
| 28 | + topologies = append(topologies, &topo) |
| 29 | + } |
| 30 | + |
| 31 | + return topologies, nil |
| 32 | +} |
| 33 | + |
| 34 | +// TopologyVertex represents a node in the network topology (device or client). |
| 35 | +type TopologyVertex struct { |
| 36 | + AllowedInVisualProgramming bool `json:"allowedInVisualProgramming"` |
| 37 | + Default bool `json:"default"` |
| 38 | + Mac string `json:"mac"` |
| 39 | + Model string `json:"model"` |
| 40 | + Name string `json:"name"` |
| 41 | + State FlexInt `json:"state"` |
| 42 | + Type string `json:"type"` // DEVICE or CLIENT |
| 43 | + UnifiDevice bool `json:"unifiDevice"` |
| 44 | + WifiRadios []TopologyRadio `json:"wifiRadios"` |
| 45 | +} |
| 46 | + |
| 47 | +// TopologyRadio represents a WiFi radio on a device vertex. |
| 48 | +type TopologyRadio struct { |
| 49 | + Channel FlexInt `json:"channel"` |
| 50 | + Protocol string `json:"protocol"` // ax, ac, n, g |
| 51 | + RadioBand string `json:"radioBand"` // ng (2.4GHz), na (5GHz), 6e (6GHz) |
| 52 | +} |
| 53 | + |
| 54 | +// TopologyEdge represents a connection between two vertices in the topology. |
| 55 | +type TopologyEdge struct { |
| 56 | + Channel FlexInt `json:"channel"` |
| 57 | + DownlinkMac string `json:"downlinkMac"` |
| 58 | + DownlinkPortNumber FlexInt `json:"downlinkPortNumber"` |
| 59 | + Duplex string `json:"duplex"` // FULL_DUPLEX, HALF_DUPLEX |
| 60 | + Essid string `json:"essid"` |
| 61 | + ExperienceScore FlexInt `json:"experienceScore"` |
| 62 | + NetworkID string `json:"networkId"` |
| 63 | + Protocol string `json:"protocol"` // ax, ac, n, g |
| 64 | + RadioBand string `json:"radioBand"` // ng, na, 6e |
| 65 | + RateMbps FlexInt `json:"rateMbps"` |
| 66 | + Type string `json:"type"` // WIRED or WIRELESS |
| 67 | + UplinkMac string `json:"uplinkMac"` |
| 68 | + UplinkPortNumber FlexInt `json:"uplinkPortNumber"` |
| 69 | +} |
| 70 | + |
| 71 | +// Topology represents the full network topology for a site. |
| 72 | +type Topology struct { |
| 73 | + Edges []TopologyEdge `json:"edges"` |
| 74 | + HasUnknownSwitch bool `json:"has_unknown_switch"` |
| 75 | + Vertices []TopologyVertex `json:"vertices"` |
| 76 | + |
| 77 | + SiteName string `json:"-"` |
| 78 | + SourceName string `json:"-"` |
| 79 | +} |
0 commit comments