|
|
|
|
@ -12,6 +12,7 @@ import ( |
|
|
|
|
"io" |
|
|
|
|
"log" |
|
|
|
|
"net/netip" |
|
|
|
|
"slices" |
|
|
|
|
"sort" |
|
|
|
|
"strings" |
|
|
|
|
"sync" |
|
|
|
|
@ -680,25 +681,29 @@ func (pr *PingResult) ToPingResponse(pingType tailcfg.PingType) *tailcfg.PingRes |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// SortPeers sorts peers by either the DNS name, hostname, Tailscale IP,
|
|
|
|
|
// or current public key.
|
|
|
|
|
// SortPeers sorts peers by either their DNS name, hostname, Tailscale IP,
|
|
|
|
|
// or ultimately their current public key.
|
|
|
|
|
func SortPeers(peers []*PeerStatus) { |
|
|
|
|
sort.Slice(peers, func(i, j int) bool { return sortKey(peers[i]) < sortKey(peers[j]) }) |
|
|
|
|
slices.SortStableFunc(peers, (*PeerStatus).compare) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func sortKey(ps *PeerStatus) string { |
|
|
|
|
if ps.DNSName != "" { |
|
|
|
|
return ps.DNSName |
|
|
|
|
func (a *PeerStatus) compare(b *PeerStatus) int { |
|
|
|
|
if a.DNSName != "" || b.DNSName != "" { |
|
|
|
|
if v := strings.Compare(a.DNSName, b.DNSName); v != 0 { |
|
|
|
|
return v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if ps.HostName != "" { |
|
|
|
|
return ps.HostName |
|
|
|
|
if a.HostName != "" || b.HostName != "" { |
|
|
|
|
if v := strings.Compare(a.HostName, b.HostName); v != 0 { |
|
|
|
|
return v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// TODO(bradfitz): add PeerStatus.Less and avoid these allocs in a Less func.
|
|
|
|
|
if len(ps.TailscaleIPs) > 0 { |
|
|
|
|
return ps.TailscaleIPs[0].String() |
|
|
|
|
if len(a.TailscaleIPs) > 0 && len(b.TailscaleIPs) > 0 { |
|
|
|
|
if v := a.TailscaleIPs[0].Compare(b.TailscaleIPs[0]); v != 0 { |
|
|
|
|
return v |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
raw := ps.PublicKey.Raw32() |
|
|
|
|
return string(raw[:]) |
|
|
|
|
return a.PublicKey.Compare(b.PublicKey) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// DebugDERPRegionReport is the result of a "tailscale debug derp" command,
|
|
|
|
|
|