addrinfo.go 2.65 KB
Newer Older
1 2 3 4 5
package peer

import (
	"fmt"

6
	"github.com/multiformats/go-multiaddr"
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
	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")

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 52
// 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) {
53
	if m == nil {
54
		return nil, ""
55 56
	}

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

65 66 67 68 69 70 71 72 73 74
// AddrInfoFromString builds an AddrInfo from the string representation of a Multiaddr
func AddrInfoFromString(s string) (*AddrInfo, error) {
	a, err := multiaddr.NewMultiaddr(s)
	if err != nil {
		return nil, err
	}

	return AddrInfoFromP2pAddr(a)
}

75 76 77 78 79
// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo.
func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
	transport, id := SplitAddr(m)
	if id == "" {
		return nil, ErrInvalidAddr
80
	}
Steven Allen's avatar
Steven Allen committed
81 82 83
	info := &AddrInfo{ID: id}
	if transport != nil {
		info.Addrs = []ma.Multiaddr{transport}
84
	}
Steven Allen's avatar
Steven Allen committed
85
	return info, nil
86 87
}

Vasco Santos's avatar
Vasco Santos committed
88
// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs.
89 90
func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
	var addrs []ma.Multiaddr
Steven Allen's avatar
Steven Allen committed
91 92 93 94
	p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID))
	if err != nil {
		return nil, err
	}
Steven Allen's avatar
Steven Allen committed
95 96 97
	if len(pi.Addrs) == 0 {
		return []ma.Multiaddr{p2ppart}, nil
	}
98
	for _, addr := range pi.Addrs {
Steven Allen's avatar
Steven Allen committed
99
		addrs = append(addrs, addr.Encapsulate(p2ppart))
100 101 102 103 104 105 106 107 108 109
	}
	return addrs, nil
}

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