| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- package dht
- import (
- "context"
- "errors"
- "time"
- "github.com/anacrolix/dht/v2/krpc"
- "github.com/anacrolix/dht/v2/traversal"
- )
- type TraversalStats = traversal.Stats
- // See BootstrapContext.
- func (s *Server) Bootstrap() (TraversalStats, error) {
- return s.BootstrapContext(context.Background())
- }
- // Populates the node table.
- func (s *Server) BootstrapContext(ctx context.Context) (_ TraversalStats, err error) {
- s.mu.Lock()
- if s.bootstrappingNow {
- s.mu.Unlock()
- err = errors.New("already bootstrapping")
- return
- }
- s.bootstrappingNow = true
- s.mu.Unlock()
- defer func() {
- s.mu.Lock()
- defer s.mu.Unlock()
- s.bootstrappingNow = false
- }()
- // Track number of responses, for STM use. (It's available via atomic in TraversalStats but that
- // won't let wake up STM transactions that are observing the value.)
- t := traversal.Start(traversal.OperationInput{
- Target: krpc.ID(s.id.AsByteArray()),
- K: 16,
- DoQuery: func(ctx context.Context, addr krpc.NodeAddr) traversal.QueryResult {
- return s.FindNode(NewAddr(addr.UDP()), s.id, QueryRateLimiting{}).TraversalQueryResult(addr)
- },
- NodeFilter: s.TraversalNodeFilter,
- })
- nodes, err := s.TraversalStartingNodes()
- if err != nil {
- return
- }
- t.AddNodes(nodes)
- s.mu.Lock()
- s.lastBootstrap = time.Now()
- s.mu.Unlock()
- select {
- case <-ctx.Done():
- err = ctx.Err()
- case <-t.Stalled():
- }
- t.Stop()
- if err != nil {
- // Could test for Stopped and return stats here but the interface doesn't tell the caller if
- // we were successful in taking the stats. We could also take a snapshot instead.
- return
- }
- <-t.Stopped()
- return *t.Stats(), nil
- }
|