func (pm *PeerManager) UnregisterSession(ses uint64) {
	pm.psLk.Lock()
	defer pm.psLk.Unlock()
	for p := range pm.peerSessions {
		delete(pm.peerSessions[p], ses)
		if len(pm.peerSessions[p]) == 0 {
			delete(pm.peerSessions, p)
		}
	}
	delete(pm.sessions, ses)
}
UnregisterSession tells the PeerManager that the given session is no longer
interested in PeerManager events.
package peermanager
import (
	"context"
	"sync"
	logging "github.com/ipfs/go-log"
	"github.com/ipfs/go-metrics-interface"
	cid "github.com/ipfs/go-cid"
	peer "github.com/libp2p/go-libp2p-core/peer"
)
var log = logging.Logger("bs:peermgr")
type PeerQueue interface {
	AddBroadcastWantHaves([]cid.Cid)
	AddWants([]cid.Cid, []cid.Cid)
	AddCancels([]cid.Cid)
	ResponseReceived(ks []cid.Cid)
	Startup()
	Shutdown()
}
type Session interface {
	ID() uint64
	SignalAvailability(peer.ID, bool)
}
type PeerQueueFactory func(ctx context.Context, p peer.ID) PeerQueue
type PeerManager struct {
	pqLk sync.RWMutex
	peerQueues map[peer.ID]PeerQueue
	pwm        *peerWantManager
	createPeerQueue PeerQueueFactory
	ctx             context.Context
	psLk         sync.RWMutex
	sessions     map[uint64]Session
	peerSessions map[peer.ID]map[uint64]struct{}
	self peer.ID
}
func New(ctx context.Context, createPeerQueue PeerQueueFactory, self peer.ID) *PeerManager {
	wantGauge := metrics.NewCtx(ctx, "wantlist_total", "Number of items in wantlist.").Gauge()
	wantBlockGauge := metrics.NewCtx(ctx, "want_blocks_total", "Number of want-blocks in wantlist.").Gauge()
	return &PeerManager{
		peerQueues:      make(map[peer.ID]PeerQueue),
		pwm:             newPeerWantManager(wantGauge, wantBlockGauge),
		createPeerQueue: createPeerQueue,
		ctx:             ctx,
		self:            self,
		sessions:     make(map[uint64]Session),
		peerSessions: make(map[peer.ID]map[uint64]struct{}),
	}
}
func (pm *PeerManager) AvailablePeers() []peer.ID {
	return pm.ConnectedPeers()
}
func (pm *PeerManager) ConnectedPeers() []peer.ID {
	pm.pqLk.RLock()
	defer pm.pqLk.RUnlock()
	peers := make([]peer.ID, 0, len(pm.peerQueues))
	for p := range pm.peerQueues {
		peers = append(peers, p)
	}
	return peers
}
func (pm *PeerManager) Connected(p peer.ID) {
	pm.pqLk.Lock()
	defer pm.pqLk.Unlock()
	pq := pm.getOrCreate(p)
	pm.pwm.addPeer(pq, p)
	pm.signalAvailability(p, true)
}
func (pm *PeerManager) Disconnected(p peer.ID) {
	pm.pqLk.Lock()
	defer pm.pqLk.Unlock()
	pq, ok := pm.peerQueues[p]
	if !ok {
		return
	}
	pm.signalAvailability(p, false)
	delete(pm.peerQueues, p)
	pq.Shutdown()
	pm.pwm.removePeer(p)
}
func (pm *PeerManager) ResponseReceived(p peer.ID, ks []cid.Cid) {
	pm.pqLk.Lock()
	pq, ok := pm.peerQueues[p]
	pm.pqLk.Unlock()
	if ok {
		pq.ResponseReceived(ks)
	}
}
func (pm *PeerManager) BroadcastWantHaves(ctx context.Context, wantHaves []cid.Cid) {
	pm.pqLk.Lock()
	defer pm.pqLk.Unlock()
	pm.pwm.broadcastWantHaves(wantHaves)
}
func (pm *PeerManager) SendWants(ctx context.Context, p peer.ID, wantBlocks []cid.Cid, wantHaves []cid.Cid) {
	pm.pqLk.Lock()
	defer pm.pqLk.Unlock()
	if _, ok := pm.peerQueues[p]; ok {
		pm.pwm.sendWants(p, wantBlocks, wantHaves)
	}
}
func (pm *PeerManager) SendCancels(ctx context.Context, cancelKs []cid.Cid) {
	pm.pqLk.Lock()
	defer pm.pqLk.Unlock()
	pm.pwm.sendCancels(cancelKs)
}
func (pm *PeerManager) CurrentWants() []cid.Cid {
	pm.pqLk.RLock()
	defer pm.pqLk.RUnlock()
	return pm.pwm.getWants()
}
func (pm *PeerManager) CurrentWantBlocks() []cid.Cid {
	pm.pqLk.RLock()
	defer pm.pqLk.RUnlock()
	return pm.pwm.getWantBlocks()
}
func (pm *PeerManager) CurrentWantHaves() []cid.Cid {
	pm.pqLk.RLock()
	defer pm.pqLk.RUnlock()
	return pm.pwm.getWantHaves()
}
func (pm *PeerManager) getOrCreate(p peer.ID) PeerQueue {
	pq, ok := pm.peerQueues[p]
	if !ok {
		pq = pm.createPeerQueue(pm.ctx, p)
		pq.Startup()
		pm.peerQueues[p] = pq
	}
	return pq
}
func (pm *PeerManager) RegisterSession(p peer.ID, s Session) {
	pm.psLk.Lock()
	defer pm.psLk.Unlock()
	if _, ok := pm.sessions[s.ID()]; !ok {
		pm.sessions[s.ID()] = s
	}
	if _, ok := pm.peerSessions[p]; !ok {
		pm.peerSessions[p] = make(map[uint64]struct{})
	}
	pm.peerSessions[p][s.ID()] = struct{}{}
}