peerstore.go 5.38 KB
Newer Older
1 2 3
package peer

import (
4
	"errors"
5 6
	"sync"

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
7
	ic "github.com/jbenet/go-ipfs/p2p/crypto"
8 9 10 11

	ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
	dssync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
	ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 13
)

14 15
// Peerstore provides a threadsafe store of Peer related
// information.
16
type Peerstore interface {
17 18 19 20 21 22 23 24 25 26 27 28
	KeyBook
	AddressBook
	Metrics

	// Peers returns a list of all peer.IDs in this Peerstore
	Peers() []ID

	// PeerInfo returns a peer.PeerInfo struct for given peer.ID.
	// This is a small slice of the information Peerstore has on
	// that peer, useful to other services.
	PeerInfo(ID) PeerInfo

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
29 30 31
	// AddPeerInfo absorbs the information listed in given PeerInfo.
	AddPeerInfo(PeerInfo)

32 33 34 35 36 37
	// Get/Put is a simple registry for other peer-related key/value pairs.
	// if we find something we use often, it should become its own set of
	// methods. this is a last resort.
	Get(id ID, key string) (interface{}, error)
	Put(id ID, key string, val interface{}) error
}
38

39 40
// AddressBook tracks the addresses of Peers
type AddressBook interface {
41 42 43 44
	Addresses(ID) []ma.Multiaddr     // returns addresses for ID
	AddAddress(ID, ma.Multiaddr)     // Adds given addr for ID
	AddAddresses(ID, []ma.Multiaddr) // Adds given addrs for ID
	SetAddresses(ID, []ma.Multiaddr) // Sets given addrs for ID (clears previously stored)
45 46
}

47 48 49 50
type addressMap map[string]ma.Multiaddr

type addressbook struct {
	addrs map[ID]addressMap
51 52 53
	sync.RWMutex
}

54 55 56 57 58 59 60 61 62
func newAddressbook() *addressbook {
	return &addressbook{addrs: map[ID]addressMap{}}
}

func (ab *addressbook) Peers() []ID {
	ab.RLock()
	ps := make([]ID, 0, len(ab.addrs))
	for p := range ab.addrs {
		ps = append(ps, p)
63
	}
64 65
	ab.RUnlock()
	return ps
66 67
}

68 69 70 71 72 73 74 75
func (ab *addressbook) Addresses(p ID) []ma.Multiaddr {
	ab.RLock()
	defer ab.RUnlock()

	maddrs, found := ab.addrs[p]
	if !found {
		return nil
	}
76

77 78 79
	maddrs2 := make([]ma.Multiaddr, 0, len(maddrs))
	for _, m := range maddrs {
		maddrs2 = append(maddrs2, m)
80
	}
81 82
	return maddrs2
}
83

84
func (ab *addressbook) AddAddress(p ID, m ma.Multiaddr) {
85 86 87 88
	ab.AddAddresses(p, []ma.Multiaddr{m})
}

func (ab *addressbook) AddAddresses(p ID, ms []ma.Multiaddr) {
89 90
	ab.Lock()
	defer ab.Unlock()
Brian Tiger Chow's avatar
Brian Tiger Chow committed
91

92
	amap, found := ab.addrs[p]
93
	if !found {
94 95 96 97 98
		amap = addressMap{}
		ab.addrs[p] = amap
	}
	for _, m := range ms {
		amap[m.String()] = m
99
	}
100
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
101

102
func (ab *addressbook) SetAddresses(p ID, ms []ma.Multiaddr) {
103 104 105
	ab.Lock()
	defer ab.Unlock()

106
	amap := addressMap{}
107
	for _, m := range ms {
108
		amap[m.String()] = m
109
	}
110
	ab.addrs[p] = amap // clear what was there before
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
}

// KeyBook tracks the Public keys of Peers.
type KeyBook interface {
	PubKey(ID) ic.PubKey
	AddPubKey(ID, ic.PubKey) error

	PrivKey(ID) ic.PrivKey
	AddPrivKey(ID, ic.PrivKey) error
}

type keybook struct {
	pks map[ID]ic.PubKey
	sks map[ID]ic.PrivKey

	sync.RWMutex // same lock. wont happen a ton.
127 128
}

129 130 131 132 133 134
func newKeybook() *keybook {
	return &keybook{
		pks: map[ID]ic.PubKey{},
		sks: map[ID]ic.PrivKey{},
	}
}
135

136 137 138 139 140
func (kb *keybook) Peers() []ID {
	kb.RLock()
	ps := make([]ID, 0, len(kb.pks)+len(kb.sks))
	for p := range kb.pks {
		ps = append(ps, p)
141
	}
142 143 144 145
	for p := range kb.sks {
		if _, found := kb.pks[p]; !found {
			ps = append(ps, p)
		}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
146
	}
147 148 149 150 151 152 153 154 155
	kb.RUnlock()
	return ps
}

func (kb *keybook) PubKey(p ID) ic.PubKey {
	kb.RLock()
	pk := kb.pks[p]
	kb.RUnlock()
	return pk
156 157
}

158
func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error {
159

160 161 162 163 164 165 166 167
	// check it's correct first
	if !p.MatchesPublicKey(pk) {
		return errors.New("ID does not match PublicKey")
	}

	kb.Lock()
	kb.pks[p] = pk
	kb.Unlock()
168
	return nil
169 170
}

171 172 173 174 175 176 177 178
func (kb *keybook) PrivKey(p ID) ic.PrivKey {
	kb.RLock()
	sk := kb.sks[p]
	kb.RUnlock()
	return sk
}

func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error {
179

180 181
	if sk == nil {
		return errors.New("sk is nil (PrivKey)")
182
	}
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201

	// check it's correct first
	if !p.MatchesPrivateKey(sk) {
		return errors.New("ID does not match PrivateKey")
	}

	kb.Lock()
	kb.sks[p] = sk
	kb.Unlock()
	return nil
}

type peerstore struct {
	keybook
	addressbook
	metrics

	// store other data, like versions
	ds ds.ThreadSafeDatastore
202
}
203

204 205 206 207 208 209 210
// NewPeerstore creates a threadsafe collection of peers.
func NewPeerstore() Peerstore {
	return &peerstore{
		keybook:     *newKeybook(),
		addressbook: *newAddressbook(),
		metrics:     *(NewMetrics()).(*metrics),
		ds:          dssync.MutexWrap(ds.NewMapDatastore()),
211
	}
212 213 214 215 216 217 218 219 220 221 222
}

func (ps *peerstore) Put(p ID, key string, val interface{}) error {
	dsk := ds.NewKey(string(p) + "/" + key)
	return ps.ds.Put(dsk, val)
}

func (ps *peerstore) Get(p ID, key string) (interface{}, error) {
	dsk := ds.NewKey(string(p) + "/" + key)
	return ps.ds.Get(dsk)
}
223

224 225 226 227 228 229 230
func (ps *peerstore) Peers() []ID {
	set := map[ID]struct{}{}
	for _, p := range ps.keybook.Peers() {
		set[p] = struct{}{}
	}
	for _, p := range ps.addressbook.Peers() {
		set[p] = struct{}{}
231 232
	}

233 234 235
	pps := make([]ID, 0, len(set))
	for p := range set {
		pps = append(pps, p)
236
	}
237 238
	return pps
}
239

240 241 242 243 244
func (ps *peerstore) PeerInfo(p ID) PeerInfo {
	return PeerInfo{
		ID:    p,
		Addrs: ps.addressbook.Addresses(p),
	}
245 246
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
247 248 249 250
func (ps *peerstore) AddPeerInfo(pi PeerInfo) {
	ps.AddAddresses(pi.ID, pi.Addrs)
}

251 252 253 254 255 256
func PeerInfos(ps Peerstore, peers []ID) []PeerInfo {
	pi := make([]PeerInfo, len(peers))
	for i, p := range peers {
		pi[i] = ps.PeerInfo(p)
	}
	return pi
257 258
}

259 260 261 262 263 264
func PeerInfoIDs(pis []PeerInfo) []ID {
	ps := make([]ID, len(pis))
	for i, pi := range pis {
		ps[i] = pi.ID
	}
	return ps
265
}