Browse Source

feat(peer): implement AddrInfosFromP2pAddrs and SplitAddr

* SplitAddr is a simpler way to split an address into a multiaddr and an ID.
* AddrInfosFromP2pAddrs converts a set of multiaddrs into a set of AddrInfos.
pull/1683/head
Steven Allen 6 years ago
parent
commit
5a976ee3d8
  1. 46
      core/peer/addrinfo.go
  2. 135
      core/peer/addrinfo_test.go

46
core/peer/addrinfo.go

@ -21,18 +21,51 @@ func (pi AddrInfo) String() string {
var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr") var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr")
func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) { // 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) {
if m == nil { if m == nil {
return nil, ErrInvalidAddr return nil, ""
} }
transport, p2ppart := ma.SplitLast(m) transport, p2ppart := ma.SplitLast(m)
if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P { if p2ppart == nil || p2ppart.Protocol().Code != ma.P_P2P {
return nil, ErrInvalidAddr return m, ""
} }
id, err := IDFromBytes(p2ppart.RawValue()) id = ID(p2ppart.RawValue()) // already validated by the multiaddr library.
if err != nil { return transport, id
return nil, err }
// AddrInfoFromP2pAddr converts a Multiaddr to an AddrInfo.
func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
transport, id := SplitAddr(m)
if id == "" {
return nil, ErrInvalidAddr
} }
info := &AddrInfo{ID: id} info := &AddrInfo{ID: id}
if transport != nil { if transport != nil {
@ -41,6 +74,7 @@ func AddrInfoFromP2pAddr(m ma.Multiaddr) (*AddrInfo, error) {
return info, nil return info, nil
} }
// AddrInfoToP2pAddr converts an AddrInfo to a list of Multiaddrs.
func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) { func AddrInfoToP2pAddrs(pi *AddrInfo) ([]ma.Multiaddr, error) {
var addrs []ma.Multiaddr var addrs []ma.Multiaddr
p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID)) p2ppart, err := ma.NewComponent("p2p", IDB58Encode(pi.ID))

135
core/peer/addrinfo_test.go

@ -0,0 +1,135 @@
package peer_test
import (
"testing"
ma "github.com/multiformats/go-multiaddr"
. "github.com/libp2p/go-libp2p-core/peer"
)
var (
testID ID
maddrFull, maddrTpt, maddrPeer ma.Multiaddr
)
func init() {
var err error
testID, err = IDB58Decode("QmS3zcG7LhYZYSJMhyRZvTddvbNUqtt8BJpaSs6mi1K5Va")
if err != nil {
panic(err)
}
maddrPeer = ma.StringCast("/p2p/" + IDB58Encode(testID))
maddrTpt = ma.StringCast("/ip4/127.0.0.1/tcp/1234")
maddrFull = maddrTpt.Encapsulate(maddrPeer)
}
func TestSplitAddr(t *testing.T) {
tpt, id := SplitAddr(maddrFull)
if !tpt.Equal(maddrTpt) {
t.Fatal("expected transport")
}
if id != testID {
t.Fatalf("%s != %s", id, testID)
}
tpt, id = SplitAddr(maddrPeer)
if tpt != nil {
t.Fatal("expected no transport")
}
if id != testID {
t.Fatalf("%s != %s", id, testID)
}
tpt, id = SplitAddr(maddrTpt)
if !tpt.Equal(maddrTpt) {
t.Fatal("expected a transport")
}
if id != "" {
t.Fatal("expected no peer ID")
}
}
func TestAddrInfoFromP2pAddr(t *testing.T) {
ai, err := AddrInfoFromP2pAddr(maddrFull)
if err != nil {
t.Fatal(err)
}
if len(ai.Addrs) != 1 || !ai.Addrs[0].Equal(maddrTpt) {
t.Fatal("expected transport")
}
if ai.ID != testID {
t.Fatalf("%s != %s", ai.ID, testID)
}
ai, err = AddrInfoFromP2pAddr(maddrPeer)
if err != nil {
t.Fatal(err)
}
if len(ai.Addrs) != 0 {
t.Fatal("expected transport")
}
if ai.ID != testID {
t.Fatalf("%s != %s", ai.ID, testID)
}
_, err = AddrInfoFromP2pAddr(maddrTpt)
if err != ErrInvalidAddr {
t.Fatalf("wrong error: %s", err)
}
}
func TestAddrInfosFromP2pAddrs(t *testing.T) {
infos, err := AddrInfosFromP2pAddrs()
if err != nil {
t.Fatal(err)
}
if len(infos) != 0 {
t.Fatal("expected no addrs")
}
infos, err = AddrInfosFromP2pAddrs(nil)
if err == nil {
t.Fatal("expected nil multiaddr to fail")
}
addrs := []ma.Multiaddr{
ma.StringCast("/ip4/128.199.219.111/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64"),
ma.StringCast("/ip4/104.236.76.40/tcp/4001/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64"),
ma.StringCast("/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd"),
ma.StringCast("/ip4/178.62.158.247/tcp/4001/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd"),
ma.StringCast("/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM"),
}
expected := map[string][]ma.Multiaddr{
"QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64": {
ma.StringCast("/ip4/128.199.219.111/tcp/4001"),
ma.StringCast("/ip4/104.236.76.40/tcp/4001"),
},
"QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd": {
ma.StringCast("/ip4/178.62.158.247/tcp/4001"),
},
"QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM": nil,
}
infos, err = AddrInfosFromP2pAddrs(addrs...)
if err != nil {
t.Fatal(err)
}
for _, info := range infos {
exaddrs, ok := expected[info.ID.Pretty()]
if !ok {
t.Fatalf("didn't expect peer %s", info.ID)
}
if len(info.Addrs) != len(exaddrs) {
t.Fatalf("got %d addrs, expected %d", len(info.Addrs), len(exaddrs))
}
// AddrInfosFromP2pAddrs preserves order. I'd like to keep this
// guarantee for now.
for i, addr := range info.Addrs {
if !exaddrs[i].Equal(addr) {
t.Fatalf("expected %s, got %s", exaddrs[i], addr)
}
}
delete(expected, info.ID.Pretty())
}
}
Loading…
Cancel
Save