package pstoremem import ( "fmt" "io" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/peerstore" pstore "github.com/libp2p/go-libp2p/p2p/host/peerstore" ) type pstoremem struct { peerstore.Metrics *memoryKeyBook *memoryAddrBook *memoryProtoBook *memoryPeerMetadata } var _ peerstore.Peerstore = &pstoremem{} type Option interface{} // NewPeerstore creates an in-memory thread-safe collection of peers. // It's the caller's responsibility to call RemovePeer to ensure // that memory consumption of the peerstore doesn't grow unboundedly. func NewPeerstore(opts ...Option) (ps *pstoremem, err error) { ab := NewAddrBook() defer func() { if err != nil { ab.Close() } }() var protoBookOpts []ProtoBookOption for _, opt := range opts { switch o := opt.(type) { case ProtoBookOption: protoBookOpts = append(protoBookOpts, o) case AddrBookOption: o(ab) default: return nil, fmt.Errorf("unexpected peer store option: %v", o) } } pb, err := NewProtoBook(protoBookOpts...) if err != nil { return nil, err } return &pstoremem{ Metrics: pstore.NewMetrics(), memoryKeyBook: NewKeyBook(), memoryAddrBook: ab, memoryProtoBook: pb, memoryPeerMetadata: NewPeerMetadata(), }, nil } func (ps *pstoremem) Close() (err error) { var errs []error weakClose := func(name string, c interface{}) { if cl, ok := c.(io.Closer); ok { if err = cl.Close(); err != nil { errs = append(errs, fmt.Errorf("%s error: %s", name, err)) } } } weakClose("keybook", ps.memoryKeyBook) weakClose("addressbook", ps.memoryAddrBook) weakClose("protobook", ps.memoryProtoBook) weakClose("peermetadata", ps.memoryPeerMetadata) if len(errs) > 0 { return fmt.Errorf("failed while closing peerstore; err(s): %q", errs) } return nil } func (ps *pstoremem) Peers() peer.IDSlice { set := map[peer.ID]struct{}{} for _, p := range ps.PeersWithKeys() { set[p] = struct{}{} } for _, p := range ps.PeersWithAddrs() { set[p] = struct{}{} } pps := make(peer.IDSlice, 0, len(set)) for p := range set { pps = append(pps, p) } return pps } func (ps *pstoremem) PeerInfo(p peer.ID) peer.AddrInfo { return peer.AddrInfo{ ID: p, Addrs: ps.memoryAddrBook.Addrs(p), } } // RemovePeer removes entries associated with a peer from: // * the KeyBook // * the ProtoBook // * the PeerMetadata // * the Metrics // It DOES NOT remove the peer from the AddrBook. func (ps *pstoremem) RemovePeer(p peer.ID) { ps.memoryKeyBook.RemovePeer(p) ps.memoryProtoBook.RemovePeer(p) ps.memoryPeerMetadata.RemovePeer(p) ps.Metrics.RemovePeer(p) }