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 }