addrinfo.go 2.36 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
package peer

import (
	"fmt"

	ma "github.com/multiformats/go-multiaddr"
)

// AddrInfo is a small struct used to pass around a peer with
// a set of addresses (and later, keys?).
type AddrInfo struct {
	ID    ID
	Addrs []ma.Multiaddr
}

var _ fmt.Stringer = AddrInfo{}

func (pi AddrInfo) String() string {
	return fmt.Sprintf("{%v: %v}", pi.ID, pi.Addrs)
}

var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr")

24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
// AddrInfosFromP2pAddrs converts a set of Multiaddrs to a set of AddrInfos.
func AddrInfosFromP2pAddrs(maddrs ...ma.Multiaddr) ([]AddrInfo, error) {
	m := make(map[ID][]ma.Multiaddr)
	for _, maddr := range maddrs {
		transport, id := SplitAddr(maddr)
		if id == "" {
			return nil, ErrInvalidAddr
		}
		if transport == nil {
			if _, ok := m[id]; !ok {
				m[id] = nil
			}
		} else {
			m[id] = append(m[id], transport)
		}
	}
	ais := make([]AddrInfo, 0, len(m))
	for id, maddrs := range m {
		ais = append(ais, AddrInfo{ID: id, Addrs: maddrs})
	}
	return ais, nil
}

// SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID.
//
// * Returns a nil transport if the address only contains a /p2p part.
// * Returns a empty peer ID if the address doesn't contain a /p2p part.
func SplitAddr(m ma.Multiaddr) (transport ma.Multiaddr, id ID) {
52
	if m == nil {
53
		return nil, ""
54 55
	}

Steven Allen's avatar
Steven Allen committed
56 57
	transport, p2ppart := ma.SplitLast(m)
	if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P {
58
		return m, ""
59
	}
60 61 62 63 64 65 66 67 68
	id = ID(p2ppart.RawValue()) // already validated by the multiaddr library.
	return transport, id
}

// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo.
func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
	transport, id := SplitAddr(m)
	if id == "" {
		return nil, ErrInvalidAddr
69
	}
Steven Allen's avatar
Steven Allen committed
70 71 72
	info := &AddrInfo{ID: id}
	if transport != nil {
		info.Addrs = []ma.Multiaddr{transport}
73
	}
Steven Allen's avatar
Steven Allen committed
74
	return info, nil
75 76
}

77
// AddrInfoToP2pAddr converts an AddrInfo to a list of Multiaddrs.
78 79
func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
	var addrs []ma.Multiaddr
Steven Allen's avatar
Steven Allen committed
80 81 82 83
	p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID))
	if err != nil {
		return nil, err
	}
Steven Allen's avatar
Steven Allen committed
84 85 86
	if len(pi.Addrs) == 0 {
		return []ma.Multiaddr{p2ppart}, nil
	}
87
	for _, addr := range pi.Addrs {
Steven Allen's avatar
Steven Allen committed
88
		addrs = append(addrs, addr.Encapsulate(p2ppart))
89 90 91 92 93 94 95 96 97 98
	}
	return addrs, nil
}

func (pi *AddrInfo) Loggable() map[string]interface{} {
	return map[string]interface{}{
		"peerID": pi.ID.Pretty(),
		"addrs":  pi.Addrs,
	}
}