/
builder.go
189 lines (156 loc) · 4.18 KB
/
builder.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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package node
import (
"context"
"crypto/rand"
"encoding/base64"
"errors"
"go.uber.org/fx"
"github.com/bittorrent/go-btfs/core/node/helpers"
"github.com/bittorrent/go-btfs/core/node/libp2p"
"github.com/bittorrent/go-btfs/repo"
cfg "github.com/bittorrent/go-btfs-config"
ds "github.com/ipfs/go-datastore"
dsync "github.com/ipfs/go-datastore/sync"
ci "github.com/libp2p/go-libp2p/core/crypto"
peer "github.com/libp2p/go-libp2p/core/peer"
)
type BuildCfg struct {
// If online is set, the node will have networking enabled
Online bool
// ExtraOpts is a map of extra options used to configure the btfs nodes creation
ExtraOpts map[string]bool
// If permanent then node should run more expensive processes
// that will improve performance in long run
Permanent bool
// DisableEncryptedConnections disables connection encryption *entirely*.
// DO NOT SET THIS UNLESS YOU'RE TESTING.
DisableEncryptedConnections bool
// If NilRepo is set, a Repo backed by a nil datastore will be constructed
NilRepo bool
Routing libp2p.RoutingOption
Host libp2p.HostOption
Repo repo.Repo
}
func (cfg *BuildCfg) getOpt(key string) bool {
if cfg.ExtraOpts == nil {
return false
}
return cfg.ExtraOpts[key]
}
func (cfg *BuildCfg) fillDefaults() error {
if cfg.Repo != nil && cfg.NilRepo {
return errors.New("cannot set a Repo and specify nilrepo at the same time")
}
if cfg.Repo == nil {
var d ds.Datastore
if cfg.NilRepo {
d = ds.NewNullDatastore()
} else {
d = ds.NewMapDatastore()
}
r, err := defaultRepo(dsync.MutexWrap(d))
if err != nil {
return err
}
cfg.Repo = r
}
if cfg.Routing == nil {
cfg.Routing = libp2p.DHTOption
}
if cfg.Host == nil {
cfg.Host = libp2p.DefaultHostOption
}
return nil
}
// options creates fx option group from this build config
func (cfg *BuildCfg) options(ctx context.Context) (fx.Option, *cfg.Config) {
err := cfg.fillDefaults()
if err != nil {
return fx.Error(err), nil
}
repoOption := fx.Provide(func(lc fx.Lifecycle) repo.Repo {
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return cfg.Repo.Close()
},
})
return cfg.Repo
})
metricsCtx := fx.Provide(func() helpers.MetricsCtx {
return helpers.MetricsCtx(ctx)
})
hostOption := fx.Provide(func() libp2p.HostOption {
return cfg.Host
})
routingOption := fx.Provide(func() libp2p.RoutingOption {
return cfg.Routing
})
conf, err := cfg.Repo.Config()
if err != nil {
return fx.Error(err), nil
}
return fx.Options(
repoOption,
hostOption,
routingOption,
metricsCtx,
), conf
}
// AnnouncePublicIp announces swarm address with default (direct) port
func (bcfg *BuildCfg) AnnouncePublicIp() error {
conf, err := bcfg.Repo.Config()
if err != nil {
return err
}
address, err := cfg.ExternalIP()
if err == nil && !contains(conf.Addresses.Announce, address) {
conf.Addresses.Announce = append(conf.Addresses.Announce, address)
return bcfg.Repo.SetConfig(conf)
}
return err
}
// AnnouncePublicIpWithPort announces swarm address with external port and
// performs internal port validation
func (bcfg *BuildCfg) AnnouncePublicIpWithPort(extPort, intPort int) error {
conf, err := bcfg.Repo.Config()
if err != nil {
return err
}
address, err := cfg.ExternalIPWithPort(extPort, intPort, conf.Addresses.Swarm)
if err == nil && !contains(conf.Addresses.Announce, address) {
conf.Addresses.Announce = append(conf.Addresses.Announce, address)
return bcfg.Repo.SetConfig(conf)
}
return err
}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
func defaultRepo(dstore repo.Datastore) (repo.Repo, error) {
c := cfg.Config{}
priv, pub, err := ci.GenerateKeyPairWithReader(ci.RSA, 2048, rand.Reader)
if err != nil {
return nil, err
}
pid, err := peer.IDFromPublicKey(pub)
if err != nil {
return nil, err
}
privkeyb, err := ci.MarshalPrivateKey(priv)
if err != nil {
return nil, err
}
c.Bootstrap = cfg.DefaultBootstrapAddresses
c.Addresses.Swarm = []string{"/ip4/0.0.0.0/tcp/4001", "/ip4/0.0.0.0/udp/4001/quic"}
c.Identity.PeerID = pid.Pretty()
c.Identity.PrivKey = base64.StdEncoding.EncodeToString(privkeyb)
return &repo.Mock{
D: dstore,
C: c,
}, nil
}