github.com/aergoio/aergo@v1.3.1/p2p/peerfinder.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package p2p
     7  
     8  import (
     9  	"github.com/aergoio/aergo-lib/log"
    10  	"github.com/aergoio/aergo/message"
    11  	"github.com/aergoio/aergo/p2p/p2pcommon"
    12  	"github.com/aergoio/aergo/p2p/p2putil"
    13  	"github.com/aergoio/aergo/types"
    14  	"time"
    15  )
    16  
    17  const (
    18  	macConcurrentQueryCount = 4
    19  	// TODO manage coolTime and reconnect interval together in same file.
    20  	firstReconnectCoolTime = time.Minute >> 1
    21  )
    22  
    23  func NewPeerFinder(logger *log.Logger, pm *peerManager, actorService p2pcommon.ActorService, maxCap int, useDiscover, usePolaris bool) p2pcommon.PeerFinder {
    24  	var pf p2pcommon.PeerFinder
    25  	if !useDiscover {
    26  		logger.Info().Msg("peer discover option is disabled, so select static peer finder.")
    27  		pf = &staticPeerFinder{pm:pm, logger:logger}
    28  	} else {
    29  		logger.Info().Bool("usePolaris",usePolaris).Msg("peer discover option is enabled, so select dynamic peer finder.")
    30  		dp := &dynamicPeerFinder{logger: logger, pm: pm, actorService: actorService, maxCap: maxCap, usePolaris:usePolaris}
    31  		dp.qStats = make(map[types.PeerID]*queryStat)
    32  		pf = dp
    33  	}
    34  	return pf
    35  
    36  }
    37  
    38  // staticPeerFinder is for BP or backup node. it will not query to polaris or other peers
    39  type staticPeerFinder struct {
    40  	pm     *peerManager
    41  	logger *log.Logger
    42  }
    43  
    44  var _ p2pcommon.PeerFinder = (*staticPeerFinder)(nil)
    45  
    46  func (dp *staticPeerFinder) OnPeerDisconnect(peer p2pcommon.RemotePeer) {
    47  }
    48  
    49  func (dp *staticPeerFinder) OnPeerConnect(pid types.PeerID) {
    50  }
    51  
    52  func (dp *staticPeerFinder) CheckAndFill() {
    53  }
    54  
    55  
    56  // dynamicPeerFinder is triggering map query to Polaris or address query to other connected peer
    57  // to discover peer
    58  // It is not thread-safe. Thread safety is responsible to the caller.
    59  type dynamicPeerFinder struct {
    60  	logger       *log.Logger
    61  	pm           *peerManager
    62  	actorService p2pcommon.ActorService
    63  	usePolaris   bool
    64  
    65  	// qStats are logs of query. all connected peers must exist queryStat.
    66  	qStats map[types.PeerID]*queryStat
    67  	maxCap int
    68  
    69  	polarisTurn time.Time
    70  }
    71  
    72  var _ p2pcommon.PeerFinder = (*dynamicPeerFinder)(nil)
    73  
    74  func (dp *dynamicPeerFinder) OnPeerDisconnect(peer p2pcommon.RemotePeer) {
    75  	// And check if to connect more peers
    76  	delete(dp.qStats, peer.ID())
    77  }
    78  
    79  func (dp *dynamicPeerFinder) OnPeerConnect(pid types.PeerID) {
    80  	dp.logger.Debug().Str(p2putil.LogPeerID, p2putil.ShortForm(pid)).Msg("check and remove peerID in pool")
    81  	if stat := dp.qStats[pid]; stat == nil {
    82  		// first query will be sent quickly
    83  		dp.qStats[pid] = &queryStat{pid: pid, nextTurn: time.Now().Add(p2pcommon.PeerFirstInterval)}
    84  	}
    85  }
    86  
    87  func (dp *dynamicPeerFinder) CheckAndFill() {
    88  	// if enough peer is collected already, skip collect
    89  	toConnCount := dp.maxCap - len(dp.pm.waitingPeers)
    90  	if toConnCount <= 0 {
    91  		return
    92  	}
    93  	now := time.Now()
    94  	// query to polaris
    95  	if dp.usePolaris && now.After(dp.polarisTurn) {
    96  		dp.polarisTurn = now.Add(p2pcommon.PolarisQueryInterval)
    97  		dp.logger.Debug().Time("next_turn", dp.polarisTurn).Msg("querying to polaris")
    98  		dp.actorService.SendRequest(message.P2PSvc, &message.MapQueryMsg{Count: MaxAddrListSizePolaris})
    99  	}
   100  	// query to peers
   101  	queried := 0
   102  	for _, stat := range dp.qStats {
   103  		if stat.nextTurn.Before(now) {
   104  			// slowly collect
   105  			stat.lastCheck = now
   106  			stat.nextTurn = now.Add(p2pcommon.PeerQueryInterval)
   107  			dp.actorService.SendRequest(message.P2PSvc, &message.GetAddressesMsg{ToWhom: stat.pid, Size: MaxAddrListSizePeer, Offset: 0})
   108  			queried++
   109  			if queried >= macConcurrentQueryCount {
   110  				break
   111  			}
   112  		}
   113  	}
   114  }
   115  
   116  type queryStat struct {
   117  	pid       types.PeerID
   118  	lastCheck time.Time
   119  	nextTurn  time.Time
   120  }