Commit 06680c4f authored by Janos Guljas's avatar Janos Guljas

add p2p Service Peers method, fix libp2p Disconnect and improve tests

parent 0f3803f0
...@@ -176,7 +176,7 @@ func New(ctx context.Context, o Options) (*Service, error) { ...@@ -176,7 +176,7 @@ func New(ctx context.Context, o Options) (*Service, error) {
return return
} }
s.peers.add(peerID, i.Address) s.peers.add(stream.Conn(), i.Address)
s.metrics.HandledStreamCount.Inc() s.metrics.HandledStreamCount.Inc()
s.logger.Infof("peer %s connected", i.Address) s.logger.Infof("peer %s connected", i.Address)
}) })
...@@ -280,7 +280,7 @@ func (s *Service) Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm ...@@ -280,7 +280,7 @@ func (s *Service) Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm
return swarm.Address{}, err return swarm.Address{}, err
} }
s.peers.add(info.ID, i.Address) s.peers.add(stream.Conn(), i.Address)
s.metrics.CreatedConnectionCount.Inc() s.metrics.CreatedConnectionCount.Inc()
s.logger.Infof("peer %s connected", i.Address) s.logger.Infof("peer %s connected", i.Address)
return i.Address, nil return i.Address, nil
...@@ -302,6 +302,10 @@ func (s *Service) disconnect(peerID libp2ppeer.ID) error { ...@@ -302,6 +302,10 @@ func (s *Service) disconnect(peerID libp2ppeer.ID) error {
return nil return nil
} }
func (s *Service) Peers() []p2p.Peer {
return s.peers.peers()
}
func (s *Service) NewStream(ctx context.Context, overlay swarm.Address, protocolName, protocolVersion, streamName string) (p2p.Stream, error) { func (s *Service) NewStream(ctx context.Context, overlay swarm.Address, protocolName, protocolVersion, streamName string) (p2p.Stream, error) {
peerID, found := s.peers.peerID(overlay) peerID, found := s.peers.peerID(overlay)
if !found { if !found {
......
This diff is collapsed.
...@@ -5,26 +5,31 @@ ...@@ -5,26 +5,31 @@
package libp2p package libp2p
import ( import (
"bytes"
"sort"
"sync" "sync"
"github.com/ethersphere/bee/pkg/p2p"
"github.com/ethersphere/bee/pkg/swarm" "github.com/ethersphere/bee/pkg/swarm"
"github.com/libp2p/go-libp2p-core/network" "github.com/libp2p/go-libp2p-core/network"
libp2ppeer "github.com/libp2p/go-libp2p-core/peer" libp2ppeer "github.com/libp2p/go-libp2p-core/peer"
) )
type peerRegistry struct { type peerRegistry struct {
peers map[string]libp2ppeer.ID // map overlay address to underlay peer id underlays map[string]libp2ppeer.ID // map overlay address to underlay peer id
overlays map[libp2ppeer.ID]swarm.Address // map underlay peer id to overlay address overlays map[libp2ppeer.ID]swarm.Address // map underlay peer id to overlay address
mu sync.RWMutex connections map[libp2ppeer.ID]map[network.Conn]struct{} // list of connections for safe removal on Disconnect notification
mu sync.RWMutex
network.Notifiee // peerRegistry can be the receiver for network.Notify network.Notifiee // peerRegistry can be the receiver for network.Notify
} }
func newPeerRegistry() *peerRegistry { func newPeerRegistry() *peerRegistry {
return &peerRegistry{ return &peerRegistry{
peers: make(map[string]libp2ppeer.ID), underlays: make(map[string]libp2ppeer.ID),
overlays: make(map[libp2ppeer.ID]swarm.Address), overlays: make(map[libp2ppeer.ID]swarm.Address),
Notifiee: new(network.NoopNotifiee), connections: make(map[libp2ppeer.ID]map[network.Conn]struct{}),
Notifiee: new(network.NoopNotifiee),
} }
} }
...@@ -33,16 +38,61 @@ func (r *peerRegistry) Exists(overlay swarm.Address) (found bool) { ...@@ -33,16 +38,61 @@ func (r *peerRegistry) Exists(overlay swarm.Address) (found bool) {
return found return found
} }
func (r *peerRegistry) add(peerID libp2ppeer.ID, overlay swarm.Address) { // Disconnect removes the peer from registry in disconnect.
// peerRegistry has to be set by network.Network.Notify().
func (r *peerRegistry) Disconnected(_ network.Network, c network.Conn) {
peerID := c.RemotePeer()
r.mu.Lock()
defer r.mu.Unlock()
// remove only the related connection,
// not eventually newly created one for the same peer
if _, ok := r.connections[peerID][c]; !ok {
return
}
overlay := r.overlays[peerID]
delete(r.overlays, peerID)
delete(r.underlays, encodeunderlaysKey(overlay))
delete(r.connections[peerID], c)
if len(r.connections[peerID]) == 0 {
delete(r.connections, peerID)
}
}
func (r *peerRegistry) peers() []p2p.Peer {
r.mu.Lock()
peers := make([]p2p.Peer, 0, len(r.overlays))
for _, a := range r.overlays {
peers = append(peers, p2p.Peer{
Address: a,
})
}
r.mu.Unlock()
sort.Slice(peers, func(i, j int) bool {
return bytes.Compare(peers[i].Address.Bytes(), peers[j].Address.Bytes()) == -1
})
return peers
}
func (r *peerRegistry) add(c network.Conn, overlay swarm.Address) {
peerID := c.RemotePeer()
r.mu.Lock() r.mu.Lock()
r.peers[encodePeersKey(overlay)] = peerID r.underlays[encodeunderlaysKey(overlay)] = peerID
r.overlays[peerID] = overlay r.overlays[peerID] = overlay
if _, ok := r.connections[peerID]; !ok {
r.connections[peerID] = make(map[network.Conn]struct{})
}
r.connections[peerID][c] = struct{}{}
r.mu.Unlock() r.mu.Unlock()
} }
func (r *peerRegistry) peerID(overlay swarm.Address) (peerID libp2ppeer.ID, found bool) { func (r *peerRegistry) peerID(overlay swarm.Address) (peerID libp2ppeer.ID, found bool) {
r.mu.RLock() r.mu.RLock()
peerID, found = r.peers[encodePeersKey(overlay)] peerID, found = r.underlays[encodeunderlaysKey(overlay)]
r.mu.RUnlock() r.mu.RUnlock()
return peerID, found return peerID, found
} }
...@@ -58,16 +108,11 @@ func (r *peerRegistry) remove(peerID libp2ppeer.ID) { ...@@ -58,16 +108,11 @@ func (r *peerRegistry) remove(peerID libp2ppeer.ID) {
r.mu.Lock() r.mu.Lock()
overlay := r.overlays[peerID] overlay := r.overlays[peerID]
delete(r.overlays, peerID) delete(r.overlays, peerID)
delete(r.peers, encodePeersKey(overlay)) delete(r.underlays, encodeunderlaysKey(overlay))
delete(r.connections, peerID)
r.mu.Unlock() r.mu.Unlock()
} }
func encodePeersKey(overlay swarm.Address) string { func encodeunderlaysKey(overlay swarm.Address) string {
return string(overlay.Bytes()) return string(overlay.Bytes())
} }
// Disconnect removes the peer from registry in disconnect.
// peerRegistry has to be set by network.Network.Notify().
func (r *peerRegistry) Disconnected(_ network.Network, c network.Conn) {
r.remove(c.RemotePeer())
}
...@@ -17,6 +17,7 @@ type Service struct { ...@@ -17,6 +17,7 @@ type Service struct {
addProtocolFunc func(p2p.ProtocolSpec) error addProtocolFunc func(p2p.ProtocolSpec) error
connectFunc func(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error) connectFunc func(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error)
disconnectFunc func(overlay swarm.Address) error disconnectFunc func(overlay swarm.Address) error
peersFunc func() []p2p.Peer
} }
func WithAddProtocolFunc(f func(p2p.ProtocolSpec) error) Option { func WithAddProtocolFunc(f func(p2p.ProtocolSpec) error) Option {
...@@ -37,6 +38,12 @@ func WithDisconnectFunc(f func(overlay swarm.Address) error) Option { ...@@ -37,6 +38,12 @@ func WithDisconnectFunc(f func(overlay swarm.Address) error) Option {
}) })
} }
func WithPeersFunc(f func() []p2p.Peer) Option {
return optionFunc(func(s *Service) {
s.peersFunc = f
})
}
func New(opts ...Option) *Service { func New(opts ...Option) *Service {
s := new(Service) s := new(Service)
for _, o := range opts { for _, o := range opts {
...@@ -47,25 +54,32 @@ func New(opts ...Option) *Service { ...@@ -47,25 +54,32 @@ func New(opts ...Option) *Service {
func (s *Service) AddProtocol(spec p2p.ProtocolSpec) error { func (s *Service) AddProtocol(spec p2p.ProtocolSpec) error {
if s.addProtocolFunc == nil { if s.addProtocolFunc == nil {
return errors.New("AddProtocol function not configured") return errors.New("function AddProtocol not configured")
} }
return s.addProtocolFunc(spec) return s.addProtocolFunc(spec)
} }
func (s *Service) Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error) { func (s *Service) Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error) {
if s.connectFunc == nil { if s.connectFunc == nil {
return swarm.Address{}, errors.New("Connect function not configured") return swarm.Address{}, errors.New("function Connect not configured")
} }
return s.connectFunc(ctx, addr) return s.connectFunc(ctx, addr)
} }
func (s *Service) Disconnect(overlay swarm.Address) error { func (s *Service) Disconnect(overlay swarm.Address) error {
if s.disconnectFunc == nil { if s.disconnectFunc == nil {
return errors.New("Disconnect function not configured") return errors.New("function Disconnect not configured")
} }
return s.disconnectFunc(overlay) return s.disconnectFunc(overlay)
} }
func (s *Service) Peers() []p2p.Peer {
if s.peersFunc == nil {
return nil
}
return s.peersFunc()
}
type Option interface { type Option interface {
apply(*Service) apply(*Service)
} }
......
...@@ -16,6 +16,7 @@ type Service interface { ...@@ -16,6 +16,7 @@ type Service interface {
AddProtocol(ProtocolSpec) error AddProtocol(ProtocolSpec) error
Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error) Connect(ctx context.Context, addr ma.Multiaddr) (overlay swarm.Address, err error)
Disconnect(overlay swarm.Address) error Disconnect(overlay swarm.Address) error
Peers() []Peer
} }
type Streamer interface { type Streamer interface {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment