// Package relay provides the public configuration types for iroh relay servers: // relay URLs grouped into a [Map], per-relay [Config], and the [Mode] selecting // which relays an endpoint uses. // // It is the public surface of the Rust crate iroh-relay (the client connection // and wire protocol live in internal packages). // // The Go API is not stable before v1 and may change in any v0 release.
package relay import ( ) // DefaultQUICPort is the default port for relay QUIC address discovery. const DefaultQUICPort = 7842 // number0 production relay hostnames. const ( naEastRelayHostname = "use1-1.relay.n0.iroh-canary.iroh.link." naWestRelayHostname = "usw1-1.relay.n0.iroh-canary.iroh.link." euRelayHostname = "euc1-1.relay.n0.iroh-canary.iroh.link." apRelayHostname = "aps1-1.relay.n0.iroh-canary.iroh.link." ) // number0 staging relay hostname. const stagingEURelayHostname = "staging-euw1-1.relay.iroh.network." // QUICConfig configures relay-based QUIC address discovery. type QUICConfig struct { // Port is the QUIC port on the relay server. Port uint16 } // Config is the configuration for a single relay server. type Config struct { // URL is the relay server URL. URL netaddr.RelayURL // QUIC, if non-nil, enables QUIC address discovery via this relay. QUIC *QUICConfig // AuthToken, if non-empty, is sent to authenticate with the relay. AuthToken string } // NewConfig returns a Config for url with the given optional QUIC config. func ( netaddr.RelayURL, *QUICConfig) Config { return Config{URL: , QUIC: } } // WithAuthToken returns a copy of c with the auth token set. func ( Config) ( string) Config { .AuthToken = return } func ( Config) () string { return .URL.String() } // MarshalText implements encoding.TextMarshaler using the relay URL string. func ( Config) () ([]byte, error) { return []byte(.String()), nil } // Map is a set of relay servers keyed by URL. // // The zero Map is empty and ready to use, but is not safe for concurrent // mutation; build it up before sharing. type Map struct { relays map[string]Config // key: RelayURL.String() } // NewMap builds a Map from the given relay configs. func ( ...Config) *Map { := &Map{relays: make(map[string]Config, len())} for , := range { .Insert() } return } // MapFromURLs builds a Map from relay URLs, each with a default config that // enables QUIC address discovery on [DefaultQUICPort]. net_report only probes // relays whose config has a QUIC section, so a nil default would disable // address discovery for every URL-built map, including [DefaultMap]. A relay // without QAD just fails the probe, which stays latency-only. func ( ...netaddr.RelayURL) *Map { := make([]Config, len()) for , := range { [] = Config{URL: , QUIC: &QUICConfig{Port: DefaultQUICPort}} } return NewMap(...) } // Insert adds or replaces the config for its URL, returning the previous config // and whether one was present. func ( *Map) ( Config) (Config, bool) { if .relays == nil { .relays = map[string]Config{} } := .URL.String() , := .relays[] .relays[] = return , } // Remove deletes the config for url, returning it and whether it was present. func ( *Map) ( netaddr.RelayURL) (Config, bool) { , := .relays[.String()] delete(.relays, .String()) return , } // Get returns the config for url and whether it is present. func ( *Map) ( netaddr.RelayURL) (Config, bool) { , := .relays[.String()] return , } // Contains reports whether url is in the map. func ( *Map) ( netaddr.RelayURL) bool { , := .relays[.String()] return } // Len returns the number of relays. func ( *Map) () int { return len(.relays) } // IsEmpty reports whether the map has no relays. func ( *Map) () bool { return len(.relays) == 0 } // URLs returns the relay URLs in sorted order. func ( *Map) () []netaddr.RelayURL { := slices.Sorted(maps.Keys(.relays)) := make([]netaddr.RelayURL, 0, len()) for , := range { = append(, .relays[].URL) } return } // Configs returns the relay configs in URL-sorted order. func ( *Map) () []Config { := slices.Sorted(maps.Keys(.relays)) := make([]Config, 0, len()) for , := range { = append(, .relays[]) } return } // Clone returns a deep copy of the map. func ( *Map) () *Map { return &Map{relays: maps.Clone(.relays)} } func ( *Map) () string { var strings.Builder .WriteString("RelayMap{") .WriteString(strings.Join(func() []string { := .URLs() := make([]string, len()) for , := range { [] = .String() } return }(), ", ")) .WriteString("}") return .String() } // Mode selects which relay servers an endpoint uses. type Mode struct { kind modeKind custom *Map } type modeKind int const ( modeDisabled modeKind = iota modeDefault modeStaging modeCustom ) // ModeDisabled disables relay servers entirely. func () Mode { return Mode{kind: modeDisabled} } // ModeDefault uses the number0 production relay servers. func () Mode { return Mode{kind: modeDefault} } // ModeStaging uses the number0 staging relay servers. func () Mode { return Mode{kind: modeStaging} } // ModeCustom uses a custom relay map. func ( *Map) Mode { return Mode{kind: modeCustom, custom: } } // ModeCustomURLs uses a custom relay map built from the given URLs. func ( ...netaddr.RelayURL) Mode { return ModeCustom(MapFromURLs(...)) } // Map returns the relay map for this mode. func ( Mode) () *Map { switch .kind { case modeDefault: return DefaultMap() case modeStaging: return StagingMap() case modeCustom: if .custom == nil { return NewMap() } return .custom default: return NewMap() } } // DefaultMap returns the number0 production relay map. func () *Map { return MapFromURLs( mustURL("https://"+naEastRelayHostname), mustURL("https://"+naWestRelayHostname), mustURL("https://"+euRelayHostname), mustURL("https://"+apRelayHostname), ) } // StagingMap returns the number0 staging relay map. func () *Map { return MapFromURLs(mustURL("https://" + stagingEURelayHostname)) } func mustURL( string) netaddr.RelayURL { , := netaddr.ParseRelayURL() if != nil { panic(fmt.Sprintf("relay: invalid default url %q: %v", , )) } return }