diff --git a/peerinfo.go b/peerinfo.go index a42d5ef..3226a50 100644 --- a/peerinfo.go +++ b/peerinfo.go @@ -2,6 +2,8 @@ package peerstore import ( "encoding/json" + "fmt" + "strings" "github.com/libp2p/go-libp2p-peer" ma "github.com/multiformats/go-multiaddr" @@ -16,6 +18,38 @@ type PeerInfo struct { Addrs []ma.Multiaddr } +var ErrInvalidAddr = fmt.Errorf("invalid p2p multiaddr") + +func InfoFromP2pAddr(m ma.Multiaddr) (*PeerInfo, error) { + if m == nil { + return nil, ErrInvalidAddr + } + + // make sure it's an IPFS addr + parts := ma.Split(m) + if len(parts) < 1 { + return nil, ErrInvalidAddr + } + + ipfspart := parts[len(parts)-1] // last part + if ipfspart.Protocols()[0].Code != ma.P_IPFS { + return nil, ErrInvalidAddr + } + + // make sure 'ipfs id' parses as a peer.ID + peerIdParts := strings.Split(ipfspart.String(), "/") + peerIdStr := peerIdParts[len(peerIdParts)-1] + id, err := peer.IDB58Decode(peerIdStr) + if err != nil { + return nil, err + } + + return &PeerInfo{ + ID: id, + Addrs: []ma.Multiaddr{ma.Join(parts[:len(parts)-1]...)}, + }, nil +} + func (pi *PeerInfo) Loggable() map[string]interface{} { return map[string]interface{}{ "peerID": pi.ID.Pretty(), diff --git a/peerinfo_test.go b/peerinfo_test.go index ca73430..edad247 100644 --- a/peerinfo_test.go +++ b/peerinfo_test.go @@ -56,3 +56,30 @@ func TestPeerInfoMarshal(t *testing.T) { t.Fatal("loggables gave wrong peerID output") } } + +func TestP2pAddrParsing(t *testing.T) { + a := mustAddr(t, "/ip4/1.2.3.4/tcp/4536") + id, err := peer.IDB58Decode("QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ") + if err != nil { + t.Fatal(err) + } + + p2pa := a.String() + "/ipfs/" + id.Pretty() + p2pma, err := ma.NewMultiaddr(p2pa) + if err != nil { + t.Fatal(err) + } + + pinfo, err := InfoFromP2pAddr(p2pma) + if err != nil { + t.Fatal(err) + } + + if pinfo.ID != id { + t.Fatal("didnt get expected peerID") + } + + if !a.Equal(pinfo.Addrs[0]) { + t.Fatal("didnt get expected address") + } +}