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