ipfsaddr.go 2.68 KB
Newer Older
1 2 3 4 5
package ipfsaddr

import (
	"errors"

6
	ma "gx/ipfs/QmXY77cVe7rVRQXZZQRioukUM7aRW3BTcAgJe12MCtb3Ji/go-multiaddr"
7

rht's avatar
rht committed
8
	path "github.com/ipfs/go-ipfs/path"
Jeromy's avatar
Jeromy committed
9
	logging "gx/ipfs/QmSpJByNKFX1sCsHBEp3R73FL4NF6FnQTEGyNAXHm2GS52/go-log"
10
	circuit "gx/ipfs/QmVEPsD9h95ToAC7NJpYopFcXyjVJm35xV4tw43J5JdCnL/go-libp2p-circuit"
11
	peer "gx/ipfs/QmXYjuNuxVzXKJCfWasQk1RqkhVLDM9jtUKhqc2WPQmFSB/go-libp2p-peer"
12 13
)

Jeromy's avatar
Jeromy committed
14
var log = logging.Logger("ipfsaddr")
15

16 17
// ErrInvalidAddr signals an address is not a valid IPFS address.
var ErrInvalidAddr = errors.New("invalid IPFS address")
18 19 20 21

type IPFSAddr interface {
	ID() peer.ID
	Multiaddr() ma.Multiaddr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
22
	Transport() ma.Multiaddr
23 24
	String() string
	Equal(b interface{}) bool
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
}

type ipfsAddr struct {
	ma ma.Multiaddr
	id peer.ID
}

func (a ipfsAddr) ID() peer.ID {
	return a.id
}

func (a ipfsAddr) Multiaddr() ma.Multiaddr {
	return a.ma
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
40 41 42 43
func (a ipfsAddr) Transport() ma.Multiaddr {
	return Transport(a)
}

44 45 46 47 48 49 50 51 52 53 54 55 56 57
func (a ipfsAddr) String() string {
	return a.ma.String()
}

func (a ipfsAddr) Equal(b interface{}) bool {
	if ib, ok := b.(IPFSAddr); ok {
		return a.Multiaddr().Equal(ib.Multiaddr())
	}
	if mb, ok := b.(ma.Multiaddr); ok {
		return a.Multiaddr().Equal(mb)
	}
	return false
}

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
// ParseString parses a string representation of an address into an IPFSAddr
func ParseString(str string) (a IPFSAddr, err error) {
	if str == "" {
		return nil, ErrInvalidAddr
	}

	m, err := ma.NewMultiaddr(str)
	if err != nil {
		return nil, err
	}

	return ParseMultiaddr(m)
}

// ParseMultiaddr parses a multiaddr into an IPFSAddr
func ParseMultiaddr(m ma.Multiaddr) (a IPFSAddr, err error) {
74 75 76 77 78 79 80 81
	// never panic.
	defer func() {
		if r := recover(); r != nil {
			log.Debug("recovered from panic: ", r)
			a = nil
			err = ErrInvalidAddr
		}
	}()
82 83 84 85 86

	if m == nil {
		return nil, ErrInvalidAddr
	}

87
	// make sure it's an IPFS addr
88 89 90 91 92 93 94 95 96
	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
	}

97
	// make sure 'ipfs id' parses as a peer.ID
rht's avatar
rht committed
98
	peerIdParts := path.SplitList(ipfspart.String())
99 100 101 102 103 104 105 106
	peerIdStr := peerIdParts[len(peerIdParts)-1]
	id, err := peer.IDB58Decode(peerIdStr)
	if err != nil {
		return nil, err
	}

	return ipfsAddr{ma: m, id: id}, nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
107 108 109

func Transport(iaddr IPFSAddr) (maddr ma.Multiaddr) {
	maddr = iaddr.Multiaddr()
110 111

	// /ipfs/QmId is part of the transport address for p2p-circuit
112 113 114
	// TODO clean up the special case
	// we need a consistent way of composing and consumig multiaddrs
	// so that we don't have to do this
115 116 117 118 119
	_, err := maddr.ValueForProtocol(circuit.P_CIRCUIT)
	if err == nil {
		return maddr
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
120 121 122 123
	split := ma.Split(maddr)
	maddr = ma.Join(split[:len(split)-1]...)
	return
}