mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-23 19:37:46 +08:00
133 lines
2.9 KiB
Go
133 lines
2.9 KiB
Go
package peer
|
|
|
|
import (
|
|
"sync"
|
|
|
|
ic "github.com/jbenet/go-ipfs/crypto"
|
|
u "github.com/jbenet/go-ipfs/util"
|
|
errors "github.com/jbenet/go-ipfs/util/debugerror"
|
|
)
|
|
|
|
// Peerstore provides a threadsafe collection for peers.
|
|
type Peerstore interface {
|
|
FindOrCreate(ID) (Peer, error)
|
|
Add(Peer) (Peer, error)
|
|
Delete(ID) error
|
|
All() (*Map, error)
|
|
|
|
WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error)
|
|
WithID(id ID) Peer
|
|
WithIDString(id string) Peer
|
|
}
|
|
|
|
type peerstore struct {
|
|
sync.RWMutex
|
|
data map[string]Peer // key is string(ID)
|
|
}
|
|
|
|
// NewPeerstore creates a threadsafe collection of peers.
|
|
func NewPeerstore() Peerstore {
|
|
return &peerstore{
|
|
data: make(map[string]Peer),
|
|
}
|
|
}
|
|
|
|
func (ps *peerstore) FindOrCreate(i ID) (Peer, error) {
|
|
ps.Lock()
|
|
defer ps.Unlock()
|
|
|
|
if i == nil {
|
|
panic("wat")
|
|
}
|
|
|
|
p, ok := ps.data[i.String()]
|
|
if !ok { // not found, construct it ourselves, add it to datastore, and return.
|
|
|
|
// TODO(brian) kinda dangerous, no? If ID is invalid and doesn't
|
|
// correspond to an actual valid peer ID, this peerstore will return an
|
|
// instantiated peer value, allowing the error to propagate. It might
|
|
// be better to nip this at the bud by returning nil and making the
|
|
// client manually add a Peer. To keep the peerstore in control, this
|
|
// can even be a peerstore method that performs cursory validation.
|
|
//
|
|
// Potential bad case: Suppose values arrive from untrusted providers
|
|
// in the DHT.
|
|
p = &peer{id: i}
|
|
ps.data[i.String()] = p
|
|
}
|
|
|
|
// no error, got it back fine
|
|
return p, nil
|
|
}
|
|
|
|
func (p *peerstore) Add(peer Peer) (Peer, error) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
|
|
existing, ok := p.data[peer.Key().String()]
|
|
if !ok { // not found? just add and return.
|
|
p.data[peer.Key().String()] = peer
|
|
return peer, nil
|
|
}
|
|
// already here.
|
|
if peer == existing {
|
|
return peer, nil
|
|
}
|
|
existing.Update(peer) // must do some merging.
|
|
return existing, nil
|
|
}
|
|
|
|
func (p *peerstore) Delete(i ID) error {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
|
|
delete(p.data, i.String())
|
|
return nil
|
|
}
|
|
|
|
func (p *peerstore) All() (*Map, error) {
|
|
p.Lock()
|
|
defer p.Unlock()
|
|
|
|
ps := Map{}
|
|
for k, v := range p.data {
|
|
ps[u.Key(k)] = v
|
|
}
|
|
return &ps, nil
|
|
}
|
|
|
|
// WithKeyPair returns a Peer object with given keys.
|
|
func (ps *peerstore) WithKeyPair(sk ic.PrivKey, pk ic.PubKey) (Peer, error) {
|
|
if sk == nil && pk == nil {
|
|
return nil, errors.Errorf("PeerWithKeyPair nil keys")
|
|
}
|
|
|
|
pk2 := sk.GetPublic()
|
|
if pk == nil {
|
|
pk = pk2
|
|
} else if !pk.Equals(pk2) {
|
|
return nil, errors.Errorf("key mismatch. pubkey is not privkey's pubkey")
|
|
}
|
|
|
|
pkid, err := IDFromPubKey(pk)
|
|
if err != nil {
|
|
return nil, errors.Errorf("Failed to hash public key: %v", err)
|
|
}
|
|
|
|
p := &peer{id: pkid, pubKey: pk, privKey: sk}
|
|
ps.Add(p)
|
|
return p, nil
|
|
}
|
|
|
|
// WithID constructs a peer with given ID.
|
|
func (ps *peerstore) WithID(id ID) Peer {
|
|
p := &peer{id: id}
|
|
ps.Add(p)
|
|
return p
|
|
}
|
|
|
|
// WithIDString constructs a peer with given ID (string).
|
|
func (ps *peerstore) WithIDString(id string) Peer {
|
|
return ps.WithID(ID(id))
|
|
}
|