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  }