package peer import ( "errors" "sync" u "github.com/jbenet/go-ipfs/util" ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/datastore.go" ) // Peerstore provides a threadsafe collection for peers. type Peerstore interface { Get(ID) (Peer, error) Add(Peer) (Peer, error) Delete(ID) error All() (*Map, error) } type peerstore struct { sync.RWMutex peers ds.Datastore } // NewPeerstore creates a threadsafe collection of peers. func NewPeerstore() Peerstore { return &peerstore{ peers: ds.NewMapDatastore(), } } func (p *peerstore) Get(i ID) (Peer, error) { p.Lock() defer p.Unlock() if i == nil { panic("wat") } k := u.Key(i).DsKey() val, err := p.peers.Get(k) switch err { // some other datastore error default: return nil, err // not found, construct it ourselves, add it to datastore, and return. case ds.ErrNotFound: peer := &peer{id: i} if err := p.peers.Put(k, peer); err != nil { return nil, err } return peer, nil // no error, got it back fine case nil: peer, ok := val.(*peer) if !ok { return nil, errors.New("stored value was not a Peer") } return peer, nil } } func (p *peerstore) Add(peer Peer) (Peer, error) { p.Lock() defer p.Unlock() k := peer.Key().DsKey() val, err := p.peers.Get(k) switch err { // some other datastore error default: return nil, err // not found? just add and return. case ds.ErrNotFound: err := p.peers.Put(k, peer) return peer, err // no error, already here. case nil: peer2, ok := val.(Peer) if !ok { return nil, errors.New("stored value was not a Peer") } if peer == peer2 { return peer, nil } // must do some merging. peer2.Update(peer) return peer2, nil } } func (p *peerstore) Delete(i ID) error { p.Lock() defer p.Unlock() k := u.Key(i).DsKey() return p.peers.Delete(k) } func (p *peerstore) All() (*Map, error) { p.RLock() defer p.RUnlock() l, err := p.peers.KeyList() if err != nil { return nil, err } ps := &Map{} for _, k := range l { val, err := p.peers.Get(k) if err != nil { continue } pval, ok := val.(*peer) if ok { (*ps)[pval.Key()] = pval } } return ps, nil }