1package peer 2 3import ( 4 "fmt" 5 6 ma "github.com/multiformats/go-multiaddr" 7) 8 9// AddrInfo is a small struct used to pass around a peer with 10// a set of addresses (and later, keys?). 11type AddrInfo struct { 12 ID ID 13 Addrs []ma.Multiaddr 14} 15 16var _ fmt.Stringer = AddrInfo{} 17 18func (pi AddrInfo) String() string { 19 return fmt.Sprintf("{%v: %v}", pi.ID, pi.Addrs) 20} 21 22var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr") 23 24// AddrInfosFromP2pAddrs converts a set of Multiaddrs to a set of AddrInfos. 25func AddrInfosFromP2pAddrs(maddrs ...ma.Multiaddr) ([]AddrInfo, error) { 26 m := make(map[ID][]ma.Multiaddr) 27 for _, maddr := range maddrs { 28 transport, id := SplitAddr(maddr) 29 if id == "" { 30 return nil, ErrInvalidAddr 31 } 32 if transport == nil { 33 if _, ok := m[id]; !ok { 34 m[id] = nil 35 } 36 } else { 37 m[id] = append(m[id], transport) 38 } 39 } 40 ais := make([]AddrInfo, 0, len(m)) 41 for id, maddrs := range m { 42 ais = append(ais, AddrInfo{ID: id, Addrs: maddrs}) 43 } 44 return ais, nil 45} 46 47// SplitAddr splits a p2p Multiaddr into a transport multiaddr and a peer ID. 48// 49// * Returns a nil transport if the address only contains a /p2p part. 50// * Returns a empty peer ID if the address doesn't contain a /p2p part. 51func SplitAddr(m ma.Multiaddr) (transport ma.Multiaddr, id ID) { 52 if m == nil { 53 return nil, "" 54 } 55 56 transport, p2ppart := ma.SplitLast(m) 57 if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P { 58 return m, "" 59 } 60 id = ID(p2ppart.RawValue()) // already validated by the multiaddr library. 61 return transport, id 62} 63 64// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo. 65func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) { 66 transport, id := SplitAddr(m) 67 if id == "" { 68 return nil, ErrInvalidAddr 69 } 70 info := &AddrInfo{ID: id} 71 if transport != nil { 72 info.Addrs = []ma.Multiaddr{transport} 73 } 74 return info, nil 75} 76 77// AddrInfoToP2pAddrs converts an AddrInfo to a list of Multiaddrs. 78func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { 79 var addrs []ma.Multiaddr 80 p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID)) 81 if err != nil { 82 return nil, err 83 } 84 if len(pi.Addrs) == 0 { 85 return []ma.Multiaddr{p2ppart}, nil 86 } 87 for _, addr := range pi.Addrs { 88 addrs = append(addrs, addr.Encapsulate(p2ppart)) 89 } 90 return addrs, nil 91} 92 93func (pi *AddrInfo) Loggable() map[string]interface{} { 94 return map[string]interface{}{ 95 "peerID": pi.ID.Pretty(), 96 "addrs": pi.Addrs, 97 } 98} 99