github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/p2p/peer/peerstore.go (about) 1 package peer 2 3 import ( 4 "errors" 5 "sync" 6 "time" 7 8 ic "github.com/ipfs/go-ipfs/p2p/crypto" 9 10 ds "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" 11 dssync "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync" 12 ma "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr" 13 ) 14 15 const ( 16 // AddressTTL is the expiration time of addresses. 17 AddressTTL = time.Hour 18 ) 19 20 // Peerstore provides a threadsafe store of Peer related 21 // information. 22 type Peerstore interface { 23 AddrBook 24 KeyBook 25 Metrics 26 27 // Peers returns a list of all peer.IDs in this Peerstore 28 Peers() []ID 29 30 // PeerInfo returns a peer.PeerInfo struct for given peer.ID. 31 // This is a small slice of the information Peerstore has on 32 // that peer, useful to other services. 33 PeerInfo(ID) PeerInfo 34 35 // Get/Put is a simple registry for other peer-related key/value pairs. 36 // if we find something we use often, it should become its own set of 37 // methods. this is a last resort. 38 Get(id ID, key string) (interface{}, error) 39 Put(id ID, key string, val interface{}) error 40 } 41 42 // AddrBook is an interface that fits the new AddrManager. I'm patching 43 // it up in here to avoid changing a ton of the codebase. 44 type AddrBook interface { 45 46 // AddAddr calls AddAddrs(p, []ma.Multiaddr{addr}, ttl) 47 AddAddr(p ID, addr ma.Multiaddr, ttl time.Duration) 48 49 // AddAddrs gives AddrManager addresses to use, with a given ttl 50 // (time-to-live), after which the address is no longer valid. 51 // If the manager has a longer TTL, the operation is a no-op for that address 52 AddAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) 53 54 // SetAddr calls mgr.SetAddrs(p, addr, ttl) 55 SetAddr(p ID, addr ma.Multiaddr, ttl time.Duration) 56 57 // SetAddrs sets the ttl on addresses. This clears any TTL there previously. 58 // This is used when we receive the best estimate of the validity of an address. 59 SetAddrs(p ID, addrs []ma.Multiaddr, ttl time.Duration) 60 61 // Addresses returns all known (and valid) addresses for a given 62 Addrs(p ID) []ma.Multiaddr 63 64 // ClearAddresses removes all previously stored addresses 65 ClearAddrs(p ID) 66 } 67 68 // KeyBook tracks the Public keys of Peers. 69 type KeyBook interface { 70 PubKey(ID) ic.PubKey 71 AddPubKey(ID, ic.PubKey) error 72 73 PrivKey(ID) ic.PrivKey 74 AddPrivKey(ID, ic.PrivKey) error 75 } 76 77 type keybook struct { 78 pks map[ID]ic.PubKey 79 sks map[ID]ic.PrivKey 80 81 sync.RWMutex // same lock. wont happen a ton. 82 } 83 84 func newKeybook() *keybook { 85 return &keybook{ 86 pks: map[ID]ic.PubKey{}, 87 sks: map[ID]ic.PrivKey{}, 88 } 89 } 90 91 func (kb *keybook) Peers() []ID { 92 kb.RLock() 93 ps := make([]ID, 0, len(kb.pks)+len(kb.sks)) 94 for p := range kb.pks { 95 ps = append(ps, p) 96 } 97 for p := range kb.sks { 98 if _, found := kb.pks[p]; !found { 99 ps = append(ps, p) 100 } 101 } 102 kb.RUnlock() 103 return ps 104 } 105 106 func (kb *keybook) PubKey(p ID) ic.PubKey { 107 kb.RLock() 108 pk := kb.pks[p] 109 kb.RUnlock() 110 return pk 111 } 112 113 func (kb *keybook) AddPubKey(p ID, pk ic.PubKey) error { 114 115 // check it's correct first 116 if !p.MatchesPublicKey(pk) { 117 return errors.New("ID does not match PublicKey") 118 } 119 120 kb.Lock() 121 kb.pks[p] = pk 122 kb.Unlock() 123 return nil 124 } 125 126 func (kb *keybook) PrivKey(p ID) ic.PrivKey { 127 kb.RLock() 128 sk := kb.sks[p] 129 kb.RUnlock() 130 return sk 131 } 132 133 func (kb *keybook) AddPrivKey(p ID, sk ic.PrivKey) error { 134 135 if sk == nil { 136 return errors.New("sk is nil (PrivKey)") 137 } 138 139 // check it's correct first 140 if !p.MatchesPrivateKey(sk) { 141 return errors.New("ID does not match PrivateKey") 142 } 143 144 kb.Lock() 145 kb.sks[p] = sk 146 kb.Unlock() 147 return nil 148 } 149 150 type peerstore struct { 151 keybook 152 metrics 153 AddrManager 154 155 // store other data, like versions 156 ds ds.ThreadSafeDatastore 157 } 158 159 // NewPeerstore creates a threadsafe collection of peers. 160 func NewPeerstore() Peerstore { 161 return &peerstore{ 162 keybook: *newKeybook(), 163 metrics: *(NewMetrics()).(*metrics), 164 AddrManager: AddrManager{}, 165 ds: dssync.MutexWrap(ds.NewMapDatastore()), 166 } 167 } 168 169 func (ps *peerstore) Put(p ID, key string, val interface{}) error { 170 dsk := ds.NewKey(string(p) + "/" + key) 171 return ps.ds.Put(dsk, val) 172 } 173 174 func (ps *peerstore) Get(p ID, key string) (interface{}, error) { 175 dsk := ds.NewKey(string(p) + "/" + key) 176 return ps.ds.Get(dsk) 177 } 178 179 func (ps *peerstore) Peers() []ID { 180 set := map[ID]struct{}{} 181 for _, p := range ps.keybook.Peers() { 182 set[p] = struct{}{} 183 } 184 for _, p := range ps.AddrManager.Peers() { 185 set[p] = struct{}{} 186 } 187 188 pps := make([]ID, 0, len(set)) 189 for p := range set { 190 pps = append(pps, p) 191 } 192 return pps 193 } 194 195 func (ps *peerstore) PeerInfo(p ID) PeerInfo { 196 return PeerInfo{ 197 ID: p, 198 Addrs: ps.AddrManager.Addrs(p), 199 } 200 } 201 202 func PeerInfos(ps Peerstore, peers []ID) []PeerInfo { 203 pi := make([]PeerInfo, len(peers)) 204 for i, p := range peers { 205 pi[i] = ps.PeerInfo(p) 206 } 207 return pi 208 } 209 210 func PeerInfoIDs(pis []PeerInfo) []ID { 211 ps := make([]ID, len(pis)) 212 for i, pi := range pis { 213 ps[i] = pi.ID 214 } 215 return ps 216 }