github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/discovery/dhtdiscovery/node.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package dhtdiscovery
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  
    24  	"github.com/libp2p/go-libp2p"
    25  	"github.com/libp2p/go-libp2p/core/host"
    26  	"github.com/libp2p/go-libp2p/core/peer"
    27  	"github.com/multiformats/go-multiaddr"
    28  	"github.com/rs/zerolog/log"
    29  )
    30  
    31  // Node represents DHT server-client in P2P network.
    32  type Node struct {
    33  	libP2PConfig     libp2p.Config
    34  	libP2PNode       host.Host
    35  	libP2PNodeCtx    context.Context
    36  	libP2PNodeCancel context.CancelFunc
    37  
    38  	bootstrapPeers []*peer.AddrInfo
    39  }
    40  
    41  // NewNode create an instance of DHT node.
    42  func NewNode(listenAddress string, bootstrapPeerAddresses []string) (*Node, error) {
    43  	node := &Node{
    44  		bootstrapPeers: make([]*peer.AddrInfo, len(bootstrapPeerAddresses)),
    45  	}
    46  
    47  	// Parse and validate configuration
    48  	listenAddr, err := multiaddr.NewMultiaddr(listenAddress)
    49  	if err != nil {
    50  		return nil, fmt.Errorf("failed to parse DHT listen address: %w", err)
    51  	}
    52  
    53  	for i, peerAddress := range bootstrapPeerAddresses {
    54  		peerAddr, err := multiaddr.NewMultiaddr(peerAddress)
    55  		if err != nil {
    56  			return nil, fmt.Errorf("failed to parse DHT peer address: %w", err)
    57  		}
    58  
    59  		if node.bootstrapPeers[i], err = peer.AddrInfoFromP2pAddr(peerAddr); err != nil {
    60  			return nil, fmt.Errorf("failed to parse DHT peer info: %w", err)
    61  		}
    62  	}
    63  
    64  	// Preparing config for libp2p Host. Other options can be added here.
    65  	if err = node.libP2PConfig.Apply(
    66  		libp2p.ListenAddrs(listenAddr),
    67  		libp2p.FallbackDefaults,
    68  	); err != nil {
    69  		return nil, fmt.Errorf("failed to configure DHT node: %w", err)
    70  	}
    71  
    72  	return node, nil
    73  }
    74  
    75  // Start begins DHT bootstrapping process.
    76  func (n *Node) Start() (err error) {
    77  	// Prepare context which stops the libp2p host.
    78  	n.libP2PNodeCtx, n.libP2PNodeCancel = context.WithCancel(context.Background())
    79  
    80  	// Start libp2p node.
    81  	n.libP2PNode, err = n.libP2PConfig.NewNode()
    82  	if err != nil {
    83  		return fmt.Errorf("failed to start DHT node: %w", err)
    84  	}
    85  
    86  	log.Info().Msgf("DHT node started on %s with ID=%s", n.libP2PNode.Addrs(), n.libP2PNode.ID())
    87  
    88  	// Start connecting to the bootstrap peer nodes early. They will tell us about the other nodes in the network.
    89  	for _, peerInfo := range n.bootstrapPeers {
    90  		go n.connectToPeer(*peerInfo)
    91  	}
    92  
    93  	return nil
    94  }
    95  
    96  // Stop stops DHT node.
    97  func (n *Node) Stop() {
    98  	n.libP2PNodeCancel()
    99  	n.libP2PNode.Close()
   100  }
   101  
   102  func (n *Node) connectToPeer(peerInfo peer.AddrInfo) {
   103  	if err := n.libP2PNode.Connect(n.libP2PNodeCtx, peerInfo); err != nil {
   104  		log.Warn().Err(err).Msgf("Failed to contact DHT peer %s", peerInfo.ID)
   105  
   106  		return
   107  	}
   108  
   109  	log.Info().Msgf("Connection established with DHT peer: %v", peerInfo)
   110  }