package netreportimport ()// Report describes the network environment as measured by a single// [Client.GetReport] run. It is a port of iroh's net_report::Report// (iroh/src/net_report/report.rs:14).//// The zero Report is a valid empty report.typeReportstruct {// Full reports whether this run used the full probe plan. Full bool// UDPv4 reports whether a QAD IPv4 round trip completed and reported an // observed IPv4 address. UDPv4 bool// UDPv6 reports whether a QAD IPv6 round trip completed and reported an // observed IPv6 address. UDPv6 bool// MappingVariesByDestV4 reports whether the observed public IPv4 address // differs across relays, when known. MappingVariesByDestV4 *bool// MappingVariesByDestV6 reports whether the observed public IPv6 address // differs across relays, when known. MappingVariesByDestV6 *bool// PreferredRelay is the relay with the best recent latency, chosen with // hysteresis. It is the zero RelayURL when no relay responded. PreferredRelay netaddr.RelayURL// RelayLatency holds per-relay, per-probe latencies. RelayLatency RelayLatencies// GlobalV4 is the host's public IPv4 address as seen by a relay. It is // absent when no QAD IPv4 observed-address report arrived. GlobalV4 netip.AddrPort// GlobalV6 is the host's public IPv6 address as seen by a relay. It is // absent when no QAD IPv6 observed-address report arrived. GlobalV6 netip.AddrPort// CaptivePortal reports whether a captive portal is intercepting HTTP, when // the check ran (full reports only). CaptivePortal *bool}// HasUDP reports whether any QAD round trip succeeded.func ( *Report) () bool { return .UDPv4 || .UDPv6 }// probeReport is the result of one probe, fed to [Report.update].type probeReport struct { probe Probe relay netaddr.RelayURL latency time.Duration// addr is the reflexive address observed by a QAD probe. It is the zero // AddrPort when no observed-address report arrived, in which case the QAD // branch records latency only. addr netip.AddrPort}// update folds a probeReport into the report, mirroring Report::update// (iroh/src/net_report/report.rs:63).func ( *Report) ( *probeReport) { .RelayLatency.updateRelay(.relay, .latency, .probe)switch .probe {caseProbeQADv4:// Without an observed-address report a QAD probe yields no addr, so we // cannot set UDPv4 or GlobalV4. Latency was already recorded above.if !.addr.IsValid() {return } := canonicalAddrPort(.addr)if !.Addr().Is4() {return// received IPv6 address from IPv4 QAD; ignore. } .UDPv4 = trueif .GlobalV4.IsValid() {if .GlobalV4 == {if .MappingVariesByDestV4 == nil { .MappingVariesByDestV4 = boolPtr(false) } } else { .MappingVariesByDestV4 = boolPtr(true) } } else { .GlobalV4 = }caseProbeQADv6:if !.addr.IsValid() {return } := .addrif !.Addr().Is6() || .Addr().Is4In6() {return// received IPv4 address from IPv6 QAD; ignore. } .UDPv6 = trueif .GlobalV6.IsValid() {if .GlobalV6 == {if .MappingVariesByDestV6 == nil { .MappingVariesByDestV6 = boolPtr(false) } } else { .MappingVariesByDestV6 = boolPtr(true) } } else { .GlobalV6 = } }}// canonicalAddrPort unmaps an IPv4-mapped IPv6 address (::ffff:a.b.c.d) to a// plain IPv4 address, mirroring SocketAddr::ip().to_canonical()// (iroh/src/net_report.rs:806, reportgen.rs:819).func canonicalAddrPort( netip.AddrPort) netip.AddrPort {returnnetip.AddrPortFrom(.Addr().Unmap(), .Port())}func boolPtr( bool) *bool { return & }// RelayLatencies records the lowest latency seen per relay for each probe type.// It is a port of net_report::RelayLatencies (report.rs:130). The zero value is// empty and ready to use.typeRelayLatenciesstruct { ipv4 map[string]time.Duration// key: RelayURL.String() ipv6 map[string]time.Duration https map[string]time.Duration// urls remembers the RelayURL behind each key so iteration and lookup can // return a netaddr.RelayURL without re-parsing. urls map[string]netaddr.RelayURL}// updateRelay records latency for url under probe, keeping the minimum seen.// Mirrors RelayLatencies::update_relay (report.rs:132).func ( *RelayLatencies) ( netaddr.RelayURL, time.Duration, Probe) {if .urls == nil { .urls = map[string]netaddr.RelayURL{} } := .String() .urls[] = := .bucket(, true)if , := []; ! || < { [] = }}// merge folds other into rl, keeping the minimum latency per (url, probe).// Mirrors RelayLatencies::merge (report.rs:150).func ( *RelayLatencies) ( *RelayLatencies) {for , := range .https { .updateRelay(.urls[], , ProbeHTTPS) }for , := range .ipv4 { .updateRelay(.urls[], , ProbeQADv4) }for , := range .ipv6 { .updateRelay(.urls[], , ProbeQADv6) }}// get returns the lowest latency recorded for url across all probe types and// whether any was recorded. Mirrors RelayLatencies::get (report.rs:200).func ( *RelayLatencies) ( netaddr.RelayURL) (time.Duration, bool) { := .String() := time.Duration(0) := falsefor , := range []map[string]time.Duration{.https, .ipv4, .ipv6} {if , := []; && (! || < ) { = = true } }return , }// Snapshot returns the lowest latency recorded for each relay.func ( *RelayLatencies) () map[netaddr.RelayURL]time.Duration { := .relays()iflen() == 0 {returnnil } := make(map[netaddr.RelayURL]time.Duration, len())for , := range {if , := .get(); { [] = } }return}// isEmpty reports whether no latencies have been recorded.func ( *RelayLatencies) () bool {returnlen(.https) == 0 && len(.ipv4) == 0 && len(.ipv6) == 0}// urlsByKey returns each relay url that has at least one recorded latency, in// no particular order. Callers needing determinism must sort.func ( *RelayLatencies) () []netaddr.RelayURL { := map[string]struct{}{}var []netaddr.RelayURLfor , := range []map[string]time.Duration{.https, .ipv4, .ipv6} {for := range {if , := []; {continue } [] = struct{}{} = append(, .urls[]) } }return}func ( *RelayLatencies) ( Probe, bool) map[string]time.Duration {var *map[string]time.Durationswitch {caseProbeHTTPS: = &.httpscaseProbeQADv4: = &.ipv4caseProbeQADv6: = &.ipv6default: = &.https }if * == nil && { * = map[string]time.Duration{} }return *}
The pages are generated with Goldsv0.8.4. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.