addrinfo.go 1.74 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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
package peer

import (
	"fmt"
	"strings"

	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")

func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
	if m == nil {
		return nil, ErrInvalidAddr
	}

	// make sure it's a P2P addr
	parts := ma.Split(m)
	if len(parts) < 1 {
		return nil, ErrInvalidAddr
	}

	// TODO(lgierth): we shouldn't assume /p2p is the last part
	p2ppart := parts[len(parts)-1]
	if p2ppart.Protocols()[0].Code != ma.P_P2P {
		return nil, ErrInvalidAddr
	}

	// make sure the /p2p value parses as a peer.ID
	peerIdParts := strings.Split(p2ppart.String(), "/")
	peerIdStr := peerIdParts[len(peerIdParts)-1]
	id, err := IDB58Decode(peerIdStr)
	if err != nil {
		return nil, err
	}

	// we might have received just an /p2p part, which means there's no addr.
	var addrs []ma.Multiaddr
	if len(parts) > 1 {
		addrs = append(addrs, ma.Join(parts[:len(parts)-1]...))
	}

	return &AddrInfo{
		ID:    id,
		Addrs: addrs,
	}, nil
}

func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
	var addrs []ma.Multiaddr
	tpl := "/" + ma.ProtocolWithCode(ma.P_P2P).Name + "/"
	for _, addr := range pi.Addrs {
		p2paddr, err := ma.NewMultiaddr(tpl + IDB58Encode(pi.ID))
		if err != nil {
			return nil, err
		}
		addrs = append(addrs, addr.Encapsulate(p2paddr))
	}
	return addrs, nil
}

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