package dns
import (
"errors"
"net/netip"
"slices"
"strings"
"github.com/tmc/go-iroh/key"
"github.com/tmc/go-iroh/netaddr"
)
const IrohTXTName = "_iroh"
const UserDataMaxLength = 245
var ErrUserDataTooLong = errors .New ("user data: max length exceeded" )
type UserData struct {
s string
}
func NewUserData (s string ) (UserData , error ) {
if len (s ) > UserDataMaxLength {
return UserData {}, ErrUserDataTooLong
}
return UserData {s : s }, nil
}
func (u UserData ) String () string { return u .s }
func (u UserData ) MarshalText () ([]byte , error ) {
return []byte (u .s ), nil
}
func (u *UserData ) UnmarshalText (text []byte ) error {
parsed , err := NewUserData (string (text ))
if err != nil {
return err
}
*u = parsed
return nil
}
type EndpointData struct {
addrs []netaddr .TransportAddr
userData *UserData
}
func NewEndpointData (addrs ...netaddr .TransportAddr ) EndpointData {
d := EndpointData {}
d .AddAddrs (addrs ...)
return d
}
func (d EndpointData ) WithRelayURL (u netaddr .RelayURL ) EndpointData {
return d .WithAddrs (netaddr .RelayAddr {URL : u })
}
func (d *EndpointData ) AddRelayURL (u netaddr .RelayURL ) {
d .AddAddrs (netaddr .RelayAddr {URL : u })
}
func (d EndpointData ) WithIPAddrs (addrs ...netip .AddrPort ) EndpointData {
d = d .clone ()
d .AddIPAddrs (addrs ...)
return d
}
func (d *EndpointData ) AddIPAddrs (addrs ...netip .AddrPort ) {
conv := make ([]netaddr .TransportAddr , len (addrs ))
for i , a := range addrs {
conv [i ] = netaddr .IPAddr {Addr : a }
}
d .AddAddrs (conv ...)
}
func (d EndpointData ) WithAddrs (addrs ...netaddr .TransportAddr ) EndpointData {
d = d .clone ()
d .AddAddrs (addrs ...)
return d
}
func (d *EndpointData ) AddAddrs (addrs ...netaddr .TransportAddr ) {
for _ , a := range addrs {
if !d .contains (a ) {
d .addrs = append (d .addrs , a )
}
}
}
func (d EndpointData ) WithUserData (u *UserData ) EndpointData {
d = d .clone ()
d .userData = u
return d
}
func (d *EndpointData ) SetUserData (u *UserData ) { d .userData = u }
func (d EndpointData ) WithoutIPAddrs () EndpointData {
d = d .clone ()
d .ClearIPAddrs ()
return d
}
func (d *EndpointData ) ClearIPAddrs () {
d .addrs = slices .DeleteFunc (d .addrs , func (a netaddr .TransportAddr ) bool {
_ , ok := a .(netaddr .IPAddr )
return ok
})
}
func (d EndpointData ) WithoutRelayURLs () EndpointData {
d = d .clone ()
d .ClearRelayURLs ()
return d
}
func (d *EndpointData ) ClearRelayURLs () {
d .addrs = slices .DeleteFunc (d .addrs , func (a netaddr .TransportAddr ) bool {
_ , ok := a .(netaddr .RelayAddr )
return ok
})
}
func (d EndpointData ) Addrs () []netaddr .TransportAddr { return slices .Clone (d .addrs ) }
func (d EndpointData ) RelayURLs () []netaddr .RelayURL {
var out []netaddr .RelayURL
for _ , a := range d .addrs {
if r , ok := a .(netaddr .RelayAddr ); ok {
out = append (out , r .URL )
}
}
return out
}
func (d EndpointData ) IPAddrs () []netip .AddrPort {
var out []netip .AddrPort
for _ , a := range d .addrs {
if ip , ok := a .(netaddr .IPAddr ); ok {
out = append (out , ip .Addr )
}
}
return out
}
func (d EndpointData ) UserData () *UserData { return d .userData }
func (d EndpointData ) HasAddrs () bool { return len (d .addrs ) > 0 }
func (d EndpointData ) String () string {
var b strings .Builder
b .WriteString ("EndpointData{addrs:[" )
for i , a := range d .addrs {
if i > 0 {
b .WriteString (", " )
}
b .WriteString (a .String ())
}
b .WriteString ("]" )
if d .userData != nil {
b .WriteString (", user-data:" )
b .WriteString (d .userData .String ())
}
b .WriteString ("}" )
return b .String ()
}
func (d EndpointData ) contains (a netaddr .TransportAddr ) bool {
return slices .ContainsFunc (d .addrs , func (x netaddr .TransportAddr ) bool {
return x .Compare (a ) == 0
})
}
func (d EndpointData ) clone () EndpointData {
d .addrs = slices .Clone (d .addrs )
return d
}
func EndpointDataFromAddr (addr netaddr .EndpointAddr ) EndpointData {
return EndpointData {addrs : addr .Addrs ()}
}
type EndpointInfo struct {
ID key .EndpointID
Data EndpointData
}
func (e EndpointInfo ) String () string {
return "EndpointInfo{id:" + e .ID .String () + ", data:" + e .Data .String () + "}"
}
func EndpointInfoFromAddr (addr netaddr .EndpointAddr ) EndpointInfo {
return EndpointInfo {ID : addr .ID , Data : EndpointDataFromAddr (addr )}
}
func (e EndpointInfo ) Addr () netaddr .EndpointAddr {
return netaddr .NewEndpointAddr (e .ID , e .Data .addrs ...)
}
func (e EndpointInfo ) ToTXTStrings () []string {
return e .toAttrs ().toTxtStrings ()
}
func (e EndpointInfo ) ToSignedPacket (secretKey key .SecretKey , ttl uint32 ) (*SignedPacket , error ) {
packet , err := e .toAttrs ().toPkarrSignedPacket (secretKey , ttl )
if err != nil {
return nil , err
}
return signedPacketFromInternal (packet ), nil
}
func EndpointInfoFromTXTLookup (domainName string , values []string ) (EndpointInfo , error ) {
attrs , err := txtAttrsFromTXTLookup (domainName , values )
if err != nil {
return EndpointInfo {}, err
}
return endpointInfoFromAttrs (attrs ), nil
}
func EndpointInfoFromSignedPacket (packet *SignedPacket ) (EndpointInfo , error ) {
attrs , err := txtAttrsFromPkarrSignedPacket (packet )
if err != nil {
return EndpointInfo {}, err
}
return endpointInfoFromAttrs (attrs ), nil
}
The pages are generated with Golds v0.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 .