-
-
Notifications
You must be signed in to change notification settings - Fork 16
/
discovery.go
145 lines (133 loc) · 5.26 KB
/
discovery.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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
Copyright 2023 Avi Zimmerman <avi.zimmerman@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"fmt"
"log/slog"
"time"
p2pcore "github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/config"
"github.com/multiformats/go-multiaddr"
"github.com/spf13/pflag"
"github.com/webmeshproj/webmesh/pkg/context"
"github.com/webmeshproj/webmesh/pkg/crypto"
"github.com/webmeshproj/webmesh/pkg/meshnet/transport/libp2p"
)
// DiscoveryOptions are options for discovering peers.
type DiscoveryOptions struct {
// Announce is a flag to announce this peer to the discovery service.
// Otherwise this peer will only discover other peers.
Announce bool `koanf:"announce,omitempty"`
// Discover is a flag to use the libp2p kademlia DHT for discovery.
Discover bool `koanf:"discover,omitempty"`
// Rendezvous is the pre-shared key string to use as a rendezvous point for peer discovery.
Rendezvous string `koanf:"rendezvous,omitempty"`
// BootstrapServers is a list of bootstrap servers to use for the DHT.
// If empty or nil, the default bootstrap servers will be used.
BootstrapServers []string `koanf:"bootstrap-servers,omitempty"`
// AnnounceTTL is the TTL for the announcement.
AnnounceTTL time.Duration `koanf:"announce-ttl,omitempty"`
// LocalAddrs is a list of local addresses to announce to the discovery service.
// If empty, the default local addresses will be used.
LocalAddrs []string `koanf:"local-addrs,omitempty"`
// ConnectTimeout is the timeout for connecting to a peer.
ConnectTimeout time.Duration `koanf:"connect-timeout,omitempty"`
}
// NewDiscoveryOptions returns a new DiscoveryOptions for the given PSK.
// Or one ready with sensible defaults if the PSK is empty.
func NewDiscoveryOptions(psk string, announce bool) DiscoveryOptions {
return DiscoveryOptions{
Announce: announce,
Rendezvous: psk,
Discover: psk != "",
AnnounceTTL: time.Minute,
ConnectTimeout: 5 * time.Second,
}
}
// BindFlags binds the flags for the discovery options.
func (o *DiscoveryOptions) BindFlags(prefix string, fs *pflag.FlagSet) {
fs.BoolVar(&o.Announce, prefix+"announce", o.Announce, "announce this peer to the discovery service")
fs.StringVar(&o.Rendezvous, prefix+"rendezvous", o.Rendezvous, "pre-shared key to use as a rendezvous point for peer discovery")
fs.BoolVar(&o.Discover, prefix+"discover", o.Discover, "use the libp2p kademlia DHT for discovery")
fs.StringSliceVar(&o.BootstrapServers, prefix+"bootstrap-servers", o.BootstrapServers, "list of bootstrap servers to use for the DHT")
fs.DurationVar(&o.AnnounceTTL, prefix+"announce-ttl", o.AnnounceTTL, "TTL for the announcement")
fs.StringSliceVar(&o.LocalAddrs, prefix+"local-addrs", o.LocalAddrs, "list of local addresses to announce to the discovery service")
fs.DurationVar(&o.ConnectTimeout, prefix+"connect-timeout", o.ConnectTimeout, "timeout for connecting to a peer")
}
// NewHostConfig returns a new HostOptions for the discovery config.
func (o *DiscoveryOptions) HostOptions(ctx context.Context, key crypto.PrivateKey) libp2p.HostOptions {
return libp2p.HostOptions{
Options: []config.Option{p2pcore.Identity(key.AsPrivKey())},
BootstrapPeers: func() []multiaddr.Multiaddr {
out := make([]multiaddr.Multiaddr, 0)
for _, addr := range o.BootstrapServers {
maddr, err := multiaddr.NewMultiaddr(addr)
if err != nil {
context.LoggerFrom(ctx).Warn("Invalid local multiaddr", slog.String("address", addr))
continue
}
out = append(out, maddr)
}
return out
}(),
LocalAddrs: func() []multiaddr.Multiaddr {
out := make([]multiaddr.Multiaddr, 0)
for _, addr := range o.LocalAddrs {
maddr, err := multiaddr.NewMultiaddr(addr)
if err != nil {
context.LoggerFrom(ctx).Warn("Invalid local multiaddr", slog.String("address", addr))
continue
}
out = append(out, maddr)
}
return out
}(),
ConnectTimeout: o.ConnectTimeout,
}
}
// Validate validates the discovery options.
func (o *DiscoveryOptions) Validate() error {
if o == nil {
return nil
}
if !o.Discover && !o.Announce {
return nil
}
if o.Rendezvous == "" {
return fmt.Errorf("rendezvous must be set when using the kademlia DHT")
}
if o.Announce && o.AnnounceTTL <= 0 {
return fmt.Errorf("announce TTL must be greater than zero")
}
if o.ConnectTimeout <= 0 {
return fmt.Errorf("connect timeout must be greater than zero")
}
if len(o.LocalAddrs) > 0 {
// Make sure all the addresses are valid
for _, addr := range o.LocalAddrs {
_, err := multiaddr.NewMultiaddr(addr)
if err != nil {
return fmt.Errorf("invalid local address: %w", err)
}
}
}
if len(o.BootstrapServers) > 0 {
for _, addr := range o.BootstrapServers {
_, err := multiaddr.NewMultiaddr(addr)
if err != nil {
return fmt.Errorf("invalid bootstrap server address: %w", err)
}
}
}
return nil
}