Invert constructor config handling
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Apr 29, 2019 at 23:37 UTC
ed514b91774de87fb1c96f878943e78db0f17fc9
9 files changed
+399
-334
core/core.go
+2
-2
@@ -71,13 +71,13 @@ type IpfsNode struct {
71
// Local node
72
Pinning pin.Pinner // the pinning manager
73
Mounts Mounts `optional:"true"` // current mount state, if any.
74
- PrivateKey ic.PrivKey // the local node's private Key
74
+ PrivateKey ic.PrivKey `optional:"true"` // the local node's private Key
75
PNetFingerprint libp2p.PNetFingerprint `optional:"true"` // fingerprint of private network
76
77
// Services
78
Peerstore pstore.Peerstore `optional:"true"` // storage for other Peer instances
79
Blockstore bstore.GCBlockstore // the block store (lower level)
80
- Filestore *filestore.Filestore // the filestore blockstore
80
+ Filestore *filestore.Filestore `optional:"true"` // the filestore blockstore
81
BaseBlocks node.BaseBlocks // the raw blockstore, no filestore wrapping
82
GCLocker bstore.GCLocker // the locker used to protect the blockstore during gc
83
Blocks bserv.BlockService // the block service, get/add blocks.
core/node/groups.go
+221
-47
@@ -2,72 +2,187 @@ package node
2
3
import (
4
"context"
5
+ "errors"
6
+ "fmt"
7
+ "time"
8
+
9
+ blockstore "github.com/ipfs/go-ipfs-blockstore"
10
+ "github.com/ipfs/go-ipfs-config"
11
+ util "github.com/ipfs/go-ipfs-util"
12
+ peer "github.com/libp2p/go-libp2p-peer"
13
+ "github.com/libp2p/go-libp2p-peerstore/pstoremem"
14
+ pubsub "github.com/libp2p/go-libp2p-pubsub"
15
16
"github.com/ipfs/go-ipfs/core/node/libp2p"
17
"github.com/ipfs/go-ipfs/p2p"
18
"github.com/ipfs/go-ipfs/provider"
19
+ "github.com/ipfs/go-ipfs/reprovide"
20
21
offline "github.com/ipfs/go-ipfs-exchange-offline"
22
offroute "github.com/ipfs/go-ipfs-routing/offline"
12
- uio "github.com/ipfs/go-unixfs/io"
23
"github.com/ipfs/go-path/resolver"
24
+ uio "github.com/ipfs/go-unixfs/io"
25
"go.uber.org/fx"
26
)
27
28
var BaseLibP2P = fx.Options(
18
- fx.Provide(libp2p.AddrFilters),
19
- fx.Provide(libp2p.BandwidthCounter),
29
fx.Provide(libp2p.PNet),
21
- fx.Provide(libp2p.AddrsFactory),
30
fx.Provide(libp2p.ConnectionManager),
23
- fx.Provide(libp2p.NatPortMap),
24
- fx.Provide(libp2p.Relay),
25
- fx.Provide(libp2p.AutoRealy),
31
fx.Provide(libp2p.DefaultTransports),
27
- fx.Provide(libp2p.QUIC),
32
33
fx.Provide(libp2p.Host),
34
35
fx.Provide(libp2p.DiscoveryHandler),
36
33
- fx.Invoke(libp2p.AutoNATService),
37
fx.Invoke(libp2p.PNetChecker),
35
- fx.Invoke(libp2p.StartListening),
36
- fx.Invoke(libp2p.SetupDiscovery),
38
)
39
39
-func LibP2P(cfg *BuildCfg) fx.Option {
40
+func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
41
+
42
+ // parse ConnMgr config
43
+
44
+ grace := config.DefaultConnMgrGracePeriod
45
+ low := config.DefaultConnMgrHighWater
46
+ high := config.DefaultConnMgrHighWater
47
+
48
+ connmgr := fx.Options()
49
+
50
+ if cfg.Swarm.ConnMgr.Type != "none" {
51
+ switch cfg.Swarm.ConnMgr.Type {
52
+ case "":
53
+ // 'default' value is the basic connection manager
54
+ break
55
+ case "basic":
56
+ var err error
57
+ grace, err = time.ParseDuration(cfg.Swarm.ConnMgr.GracePeriod)
58
+ if err != nil {
59
+ return fx.Error(fmt.Errorf("parsing Swarm.ConnMgr.GracePeriod: %s", err))
60
+ }
61
+
62
+ low = cfg.Swarm.ConnMgr.LowWater
63
+ high = cfg.Swarm.ConnMgr.HighWater
64
+ default:
65
+ return fx.Error(fmt.Errorf("unrecognized ConnMgr.Type: %q", cfg.Swarm.ConnMgr.Type))
66
+ }
67
+
68
+ connmgr = fx.Provide(libp2p.ConnectionManager(low, high, grace))
69
+ }
70
+
71
+ // parse PubSub config
72
+
73
+ ps := fx.Options()
74
+ if bcfg.getOpt("pubsub") || bcfg.getOpt("ipnsps") {
75
+ var pubsubOptions []pubsub.Option
76
+ if cfg.Pubsub.DisableSigning {
77
+ pubsubOptions = append(pubsubOptions, pubsub.WithMessageSigning(false))
78
+ }
79
+
80
+ if cfg.Pubsub.StrictSignatureVerification {
81
+ pubsubOptions = append(pubsubOptions, pubsub.WithStrictSignatureVerification(true))
82
+ }
83
+
84
+ switch cfg.Pubsub.Router {
85
+ case "":
86
+ fallthrough
87
+ case "floodsub":
88
+ ps = fx.Provide(libp2p.FloodSub(pubsubOptions...))
89
+ case "gossipsub":
90
+ ps = fx.Provide(libp2p.GossipSub(pubsubOptions...))
91
+ default:
92
+ return fx.Error(fmt.Errorf("unknown pubsub router %s", cfg.Pubsub.Router))
93
+ }
94
+ }
95
+
96
+ // Gather all the options
97
+
98
opts := fx.Options(
99
BaseLibP2P,
100
43
- fx.Provide(libp2p.Security(!cfg.DisableEncryptedConnections)),
44
- maybeProvide(libp2p.Pubsub, cfg.getOpt("pubsub") || cfg.getOpt("ipnsps")),
101
+ fx.Provide(libp2p.AddrFilters(cfg.Swarm.AddrFilters)),
102
+ fx.Invoke(libp2p.SetupDiscovery(cfg.Discovery.MDNS.Enabled, cfg.Discovery.MDNS.Interval)),
103
+ fx.Provide(libp2p.AddrsFactory(cfg.Addresses.Announce, cfg.Addresses.NoAnnounce)),
104
+ fx.Provide(libp2p.SmuxTransport(bcfg.getOpt("mplex"))),
105
+ fx.Provide(libp2p.Relay(cfg.Swarm.DisableRelay, cfg.Swarm.EnableRelayHop)),
106
+ fx.Invoke(libp2p.StartListening(cfg.Addresses.Swarm)),
107
+
108
+ fx.Provide(libp2p.Security(!bcfg.DisableEncryptedConnections, cfg.Experimental.PreferTLS)),
109
46
- fx.Provide(libp2p.SmuxTransport(cfg.getOpt("mplex"))),
110
fx.Provide(libp2p.Routing),
111
fx.Provide(libp2p.BaseRouting),
49
- maybeProvide(libp2p.PubsubRouter, cfg.getOpt("ipnsps")),
112
+ maybeProvide(libp2p.PubsubRouter, bcfg.getOpt("ipnsps")),
113
+
114
+ maybeProvide(libp2p.BandwidthCounter, !cfg.Swarm.DisableBandwidthMetrics),
115
+ maybeProvide(libp2p.NatPortMap, !cfg.Swarm.DisableNatPortMap),
116
+ maybeProvide(libp2p.AutoRealy, cfg.Swarm.EnableAutoRelay),
117
+ maybeProvide(libp2p.QUIC, cfg.Experimental.QUIC),
118
+ maybeProvide(libp2p.AutoNATService(cfg.Experimental.QUIC), cfg.Swarm.EnableAutoNATService),
119
+ connmgr,
120
+ ps,
121
)
122
123
return opts
124
}
125
126
// Storage groups units which setup datastore based persistence and blockstore layers
56
-func Storage(cfg *BuildCfg) fx.Option {
127
+func Storage(bcfg *BuildCfg, cfg *config.Config) fx.Option {
128
+ cacheOpts := blockstore.DefaultCacheOpts()
129
+ cacheOpts.HasBloomFilterSize = cfg.Datastore.BloomFilterSize
130
+ if !bcfg.Permanent {
131
+ cacheOpts.HasBloomFilterSize = 0
132
+ }
133
+
134
+ finalBstore := fx.Provide(GcBlockstoreCtor)
135
+ if cfg.Experimental.FilestoreEnabled || cfg.Experimental.UrlstoreEnabled {
136
+ finalBstore = fx.Provide(FilestoreBlockstoreCtor)
137
+ }
138
+
139
return fx.Options(
140
fx.Provide(RepoConfig),
141
fx.Provide(Datastore),
60
- fx.Provide(BaseBlockstoreCtor(cfg.Permanent, cfg.NilRepo)),
61
- fx.Provide(GcBlockstoreCtor),
142
+ fx.Provide(BaseBlockstoreCtor(cacheOpts, bcfg.NilRepo, cfg.Datastore.HashOnRead)),
143
+ finalBstore,
144
)
145
}
146
147
// Identity groups units providing cryptographic identity
66
-var Identity = fx.Options(
67
- fx.Provide(PeerID),
68
- fx.Provide(PrivateKey),
69
- fx.Provide(libp2p.Peerstore),
70
-)
148
+func Identity(cfg *config.Config) fx.Option {
149
+ // PeerID
150
+
151
+ cid := cfg.Identity.PeerID
152
+ if cid == "" {
153
+ return fx.Error(errors.New("identity was not set in config (was 'ipfs init' run?)"))
154
+ }
155
+ if len(cid) == 0 {
156
+ return fx.Error(errors.New("no peer ID in config! (was 'ipfs init' run?)"))
157
+ }
158
+
159
+ id, err := peer.IDB58Decode(cid)
160
+ if err != nil {
161
+ return fx.Error(fmt.Errorf("peer ID invalid: %s", err))
162
+ }
163
+
164
+ // Private Key
165
+
166
+ if cfg.Identity.PrivKey == "" {
167
+ return fx.Options( // No PK (usually in tests)
168
+ fx.Provide(PeerID(id)),
169
+ fx.Provide(pstoremem.NewPeerstore),
170
+ )
171
+ }
172
+
173
+ sk, err := cfg.Identity.DecodePrivateKey("passphrase todo!")
174
+ if err != nil {
175
+ return fx.Error(err)
176
+ }
177
+
178
+ return fx.Options( // Full identity
179
+ fx.Provide(PeerID(id)),
180
+ fx.Provide(PrivateKey(sk)),
181
+ fx.Provide(pstoremem.NewPeerstore),
182
+
183
+ fx.Invoke(libp2p.PstoreAddSelfKeys),
184
+ )
185
+}
186
187
// IPNS groups namesys related units
188
var IPNS = fx.Options(
@@ -75,33 +190,97 @@ var IPNS = fx.Options(
190
)
191
192
// Providers groups units managing provider routing records
78
-var Providers = fx.Options(
79
- fx.Provide(ProviderQueue),
80
- fx.Provide(ProviderCtor),
81
- fx.Provide(ReproviderCtor),
193
+func Providers(cfg *config.Config) fx.Option {
194
+ reproviderInterval := kReprovideFrequency
195
+ if cfg.Reprovider.Interval != "" {
196
+ dur, err := time.ParseDuration(cfg.Reprovider.Interval)
197
+ if err != nil {
198
+ return fx.Error(err)
199
+ }
200
+
201
+ reproviderInterval = dur
202
+ }
203
83
- fx.Invoke(Reprovider),
84
-)
204
+ var keyProvider fx.Option
205
+ switch cfg.Reprovider.Strategy {
206
+ case "all":
207
+ fallthrough
208
+ case "":
209
+ keyProvider = fx.Provide(reprovide.NewBlockstoreProvider)
210
+ case "roots":
211
+ keyProvider = fx.Provide(reprovide.NewPinnedProvider(true))
212
+ case "pinned":
213
+ keyProvider = fx.Provide(reprovide.NewPinnedProvider(false))
214
+ default:
215
+ return fx.Error(fmt.Errorf("unknown reprovider strategy '%s'", cfg.Reprovider.Strategy))
216
+ }
217
+
218
+ return fx.Options(
219
+ fx.Provide(ProviderQueue),
220
+ fx.Provide(ProviderCtor),
221
+ fx.Provide(ReproviderCtor(reproviderInterval)),
222
+ keyProvider,
223
+
224
+ fx.Invoke(Reprovider),
225
+ )
226
+}
227
228
// Online groups online-only units
87
-func Online(cfg *BuildCfg) fx.Option {
229
+func Online(bcfg *BuildCfg, cfg *config.Config) fx.Option {
230
+
231
+ // Namesys params
232
+
233
+ ipnsCacheSize := cfg.Ipns.ResolveCacheSize
234
+ if ipnsCacheSize == 0 {
235
+ ipnsCacheSize = DefaultIpnsCacheSize
236
+ }
237
+ if ipnsCacheSize < 0 {
238
+ return fx.Error(fmt.Errorf("cannot specify negative resolve cache size"))
239
+ }
240
+
241
+ // Republisher params
242
+
243
+ var repubPeriod, recordLifetime time.Duration
244
+
245
+ if cfg.Ipns.RepublishPeriod != "" {
246
+ d, err := time.ParseDuration(cfg.Ipns.RepublishPeriod)
247
+ if err != nil {
248
+ return fx.Error(fmt.Errorf("failure to parse config setting IPNS.RepublishPeriod: %s", err))
249
+ }
250
+
251
+ if !util.Debug && (d < time.Minute || d > (time.Hour*24)) {
252
+ return fx.Error(fmt.Errorf("config setting IPNS.RepublishPeriod is not between 1min and 1day: %s", d))
253
+ }
254
+
255
+ repubPeriod = d
256
+ }
257
+
258
+ if cfg.Ipns.RecordLifetime != "" {
259
+ d, err := time.ParseDuration(cfg.Ipns.RecordLifetime)
260
+ if err != nil {
261
+ return fx.Error(fmt.Errorf("failure to parse config setting IPNS.RecordLifetime: %s", err))
262
+ }
263
+
264
+ recordLifetime = d
265
+ }
266
+
267
return fx.Options(
268
fx.Provide(OnlineExchange),
90
- fx.Provide(OnlineNamesys),
269
+ fx.Provide(Namesys(ipnsCacheSize)),
270
92
- fx.Invoke(IpnsRepublisher),
271
+ fx.Invoke(IpnsRepublisher(repubPeriod, recordLifetime)),
272
273
fx.Provide(p2p.New),
274
96
- LibP2P(cfg),
97
- Providers,
275
+ LibP2P(bcfg, cfg),
276
+ Providers(cfg),
277
)
278
}
279
280
// Offline groups offline alternatives to Online units
281
var Offline = fx.Options(
282
fx.Provide(offline.Exchange),
104
- fx.Provide(OfflineNamesys),
283
+ fx.Provide(Namesys(0)),
284
fx.Provide(offroute.NewOfflineRouter),
285
fx.Provide(provider.NewOfflineProvider),
286
)
@@ -115,9 +294,9 @@ var Core = fx.Options(
294
fx.Provide(Files),
295
)
296
118
-func Networked(cfg *BuildCfg) fx.Option {
119
- if cfg.Online {
120
- return Online(cfg)
297
+func Networked(bcfg *BuildCfg, cfg *config.Config) fx.Option {
298
+ if bcfg.Online {
299
+ return Online(bcfg, cfg)
300
}
301
return Offline
302
}
@@ -136,20 +315,15 @@ func IPFS(ctx context.Context, bcfg *BuildCfg) fx.Option {
315
// TEMP: setting global sharding switch here
316
uio.UseHAMTSharding = cfg.Experimental.ShardingEnabled
317
139
-
140
-
141
-
142
-
143
-
318
return fx.Options(
319
bcfgOpts,
320
321
fx.Provide(baseProcess),
322
149
- Storage(bcfg),
150
- Identity,
323
+ Storage(bcfg, cfg),
324
+ Identity(cfg),
325
IPNS,
152
- Networked(bcfg),
326
+ Networked(bcfg, cfg),
327
328
Core,
329
)
core/node/identity.go
+14
-35
@@ -1,50 +1,29 @@
1
package node
2
3
import (
4
- "errors"
4
"fmt"
5
7
- "github.com/ipfs/go-ipfs-config"
6
"github.com/libp2p/go-libp2p-crypto"
7
"github.com/libp2p/go-libp2p-peer"
8
)
9
12
-// PeerID loads peer identity form config
13
-func PeerID(cfg *config.Config) (peer.ID, error) {
14
- cid := cfg.Identity.PeerID
15
- if cid == "" {
16
- return "", errors.New("identity was not set in config (was 'ipfs init' run?)")
10
+func PeerID(id peer.ID) func() peer.ID {
11
+ return func() peer.ID {
12
+ return id
13
}
18
- if len(cid) == 0 {
19
- return "", errors.New("no peer ID in config! (was 'ipfs init' run?)")
20
- }
21
-
22
- id, err := peer.IDB58Decode(cid)
23
- if err != nil {
24
- return "", fmt.Errorf("peer ID invalid: %s", err)
25
- }
26
-
27
- return id, nil
14
}
15
16
// PrivateKey loads the private key from config
31
-func PrivateKey(cfg *config.Config, id peer.ID) (crypto.PrivKey, error) {
32
- if cfg.Identity.PrivKey == "" {
33
- return nil, nil
34
- }
35
-
36
- sk, err := cfg.Identity.DecodePrivateKey("passphrase todo!")
37
- if err != nil {
38
- return nil, err
39
- }
40
-
41
- id2, err := peer.IDFromPrivateKey(sk)
42
- if err != nil {
43
- return nil, err
44
- }
45
-
46
- if id2 != id {
47
- return nil, fmt.Errorf("private key in config does not match id: %s != %s", id, id2)
17
+func PrivateKey(sk crypto.PrivKey) func(id peer.ID) (crypto.PrivKey, error) {
18
+ return func(id peer.ID) (crypto.PrivKey, error) {
19
+ id2, err := peer.IDFromPrivateKey(sk)
20
+ if err != nil {
21
+ return nil, err
22
+ }
23
+
24
+ if id2 != id {
25
+ return nil, fmt.Errorf("private key in config does not match id: %s != %s", id, id2)
26
+ }
27
+ return sk, nil
28
}
49
- return sk, nil
29
}
core/node/ipns.go
+16
-35
@@ -4,7 +4,6 @@ import (
4
"fmt"
5
"time"
6
7
- "github.com/ipfs/go-ipfs-config"
7
"github.com/ipfs/go-ipfs-util"
8
"github.com/ipfs/go-ipns"
9
"github.com/libp2p/go-libp2p-crypto"
@@ -27,49 +26,31 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator {
26
}
27
}
28
30
-// OfflineNamesys creates namesys setup for offline operation
31
-func OfflineNamesys(rt routing.IpfsRouting, repo repo.Repo) (namesys.NameSystem, error) {
32
- return namesys.NewNameSystem(rt, repo.Datastore(), 0), nil
33
-}
34
-
35
-// OnlineNamesys createn new namesys setup for online operation
36
-func OnlineNamesys(rt routing.IpfsRouting, repo repo.Repo, cfg *config.Config) (namesys.NameSystem, error) {
37
- cs := cfg.Ipns.ResolveCacheSize
38
- if cs == 0 {
39
- cs = DefaultIpnsCacheSize
29
+// Namesys creates new name system
30
+func Namesys(cacheSize int) func(rt routing.IpfsRouting, repo repo.Repo) (namesys.NameSystem, error) {
31
+ return func(rt routing.IpfsRouting, repo repo.Repo) (namesys.NameSystem, error) {
32
+ return namesys.NewNameSystem(rt, repo.Datastore(), cacheSize), nil
33
}
41
- if cs < 0 {
42
- return nil, fmt.Errorf("cannot specify negative resolve cache size")
43
- }
44
- return namesys.NewNameSystem(rt, repo.Datastore(), cs), nil
34
}
35
36
// IpnsRepublisher runs new IPNS republisher service
48
-func IpnsRepublisher(lc lcProcess, cfg *config.Config, namesys namesys.NameSystem, repo repo.Repo, privKey crypto.PrivKey) error {
49
- repub := republisher.NewRepublisher(namesys, repo.Datastore(), privKey, repo.Keystore())
37
+func IpnsRepublisher(repubPeriod time.Duration, recordLifetime time.Duration) func(lcProcess, namesys.NameSystem, repo.Repo, crypto.PrivKey) error {
38
+ return func(lc lcProcess, namesys namesys.NameSystem, repo repo.Repo, privKey crypto.PrivKey) error {
39
+ repub := republisher.NewRepublisher(namesys, repo.Datastore(), privKey, repo.Keystore())
40
51
- if cfg.Ipns.RepublishPeriod != "" {
52
- d, err := time.ParseDuration(cfg.Ipns.RepublishPeriod)
53
- if err != nil {
54
- return fmt.Errorf("failure to parse config setting IPNS.RepublishPeriod: %s", err)
55
- }
41
+ if repubPeriod != 0 {
42
+ if !util.Debug && (repubPeriod < time.Minute || repubPeriod > (time.Hour*24)) {
43
+ return fmt.Errorf("config setting IPNS.RepublishPeriod is not between 1min and 1day: %s", repubPeriod)
44
+ }
45
57
- if !util.Debug && (d < time.Minute || d > (time.Hour*24)) {
58
- return fmt.Errorf("config setting IPNS.RepublishPeriod is not between 1min and 1day: %s", d)
46
+ repub.Interval = repubPeriod
47
}
48
61
- repub.Interval = d
62
- }
63
-
64
- if cfg.Ipns.RecordLifetime != "" {
65
- d, err := time.ParseDuration(cfg.Ipns.RecordLifetime)
66
- if err != nil {
67
- return fmt.Errorf("failure to parse config setting IPNS.RecordLifetime: %s", err)
49
+ if recordLifetime != 0 {
50
+ repub.RecordLifetime = recordLifetime
51
}
52
70
- repub.RecordLifetime = d
53
+ lc.Append(repub.Run)
54
+ return nil
55
}
72
-
73
- lc.Append(repub.Run)
74
- return nil
56
}
core/node/libp2p/discovery.go
+15
-14
@@ -4,12 +4,12 @@ import (
4
"context"
5
"time"
6
7
- "github.com/ipfs/go-ipfs-config"
8
- "github.com/ipfs/go-ipfs/core/node/helpers"
7
"github.com/libp2p/go-libp2p-host"
8
"github.com/libp2p/go-libp2p-peerstore"
9
"github.com/libp2p/go-libp2p/p2p/discovery"
10
"go.uber.org/fx"
11
+
12
+ "github.com/ipfs/go-ipfs/core/node/helpers"
13
)
14
15
const discoveryConnTimeout = time.Second * 30
@@ -35,18 +35,19 @@ func DiscoveryHandler(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host)
35
}
36
}
37
38
-func SetupDiscovery(mctx helpers.MetricsCtx, lc fx.Lifecycle, cfg *config.Config, host host.Host, handler *discoveryHandler) error {
39
- if cfg.Discovery.MDNS.Enabled {
40
- mdns := cfg.Discovery.MDNS
41
- if mdns.Interval == 0 {
42
- mdns.Interval = 5
43
- }
44
- service, err := discovery.NewMdnsService(helpers.LifecycleCtx(mctx, lc), host, time.Duration(mdns.Interval)*time.Second, discovery.ServiceTag)
45
- if err != nil {
46
- log.Error("mdns error: ", err)
47
- return nil
38
+func SetupDiscovery(mdns bool, mdnsInterval int) func(helpers.MetricsCtx, fx.Lifecycle, host.Host, *discoveryHandler) error {
39
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, handler *discoveryHandler) error {
40
+ if mdns {
41
+ if mdnsInterval == 0 {
42
+ mdnsInterval = 5
43
+ }
44
+ service, err := discovery.NewMdnsService(helpers.LifecycleCtx(mctx, lc), host, time.Duration(mdnsInterval)*time.Second, discovery.ServiceTag)
45
+ if err != nil {
46
+ log.Error("mdns error: ", err)
47
+ return nil
48
+ }
49
+ service.RegisterNotifee(handler)
50
}
49
- service.RegisterNotifee(handler)
51
+ return nil
52
}
51
- return nil
53
}
core/node/libp2p/libp2p.go
+91
-138
@@ -11,7 +11,6 @@ import (
11
"time"
12
13
"github.com/ipfs/go-datastore"
14
- "github.com/ipfs/go-ipfs-config"
14
nilrouting "github.com/ipfs/go-ipfs-routing/none"
15
logging "github.com/ipfs/go-log"
16
"github.com/libp2p/go-libp2p"
@@ -25,7 +24,6 @@ import (
24
"github.com/libp2p/go-libp2p-metrics"
25
"github.com/libp2p/go-libp2p-peer"
26
"github.com/libp2p/go-libp2p-peerstore"
28
- "github.com/libp2p/go-libp2p-peerstore/pstoremem"
27
"github.com/libp2p/go-libp2p-pnet"
28
"github.com/libp2p/go-libp2p-pubsub"
29
"github.com/libp2p/go-libp2p-pubsub-router"
@@ -87,38 +85,30 @@ var DHTOption RoutingOption = constructDHTRouting
85
var DHTClientOption RoutingOption = constructClientDHTRouting
86
var NilRouterOption RoutingOption = nilrouting.ConstructNilRouting
87
90
-func Peerstore(id peer.ID, sk crypto.PrivKey) (peerstore.Peerstore, error) {
91
- ps := pstoremem.NewPeerstore()
92
-
93
- if sk != nil {
94
- if err := ps.AddPubKey(id, sk.GetPublic()); err != nil {
95
- return nil, err
96
- }
97
- if err := ps.AddPrivKey(id, sk); err != nil {
98
- return nil, err
99
- }
88
+func PstoreAddSelfKeys(id peer.ID, sk crypto.PrivKey, ps peerstore.Peerstore) error {
89
+ if err := ps.AddPubKey(id, sk.GetPublic()); err != nil {
90
+ return err
91
}
92
102
- return ps, nil
93
+ return ps.AddPrivKey(id, sk)
94
}
95
105
-func AddrFilters(cfg *config.Config) (opts Libp2pOpts, err error) {
106
- for _, s := range cfg.Swarm.AddrFilters {
107
- f, err := mamask.NewMask(s)
108
- if err != nil {
109
- return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s)
96
+func AddrFilters(filters []string) func() (opts Libp2pOpts, err error) {
97
+ return func() (opts Libp2pOpts, err error) {
98
+ for _, s := range filters {
99
+ f, err := mamask.NewMask(s)
100
+ if err != nil {
101
+ return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s)
102
+ }
103
+ opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f))
104
}
111
- opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f))
105
+ return opts, nil
106
}
113
- return opts, nil
107
}
108
116
-func BandwidthCounter(cfg *config.Config) (opts Libp2pOpts, reporter metrics.Reporter) {
109
+func BandwidthCounter() (opts Libp2pOpts, reporter metrics.Reporter) {
110
reporter = metrics.NewBandwidthCounter()
118
-
119
- if !cfg.Swarm.DisableBandwidthMetrics {
120
- opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter))
121
- }
111
+ opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter))
112
return opts, reporter
113
}
114
@@ -183,9 +173,9 @@ func PNetChecker(repo repo.Repo, ph host.Host, lc fx.Lifecycle) error {
173
return nil
174
}
175
186
-func makeAddrsFactory(cfg config.Addresses) (p2pbhost.AddrsFactory, error) {
176
+func makeAddrsFactory(announce []string, noAnnounce []string) (p2pbhost.AddrsFactory, error) {
177
var annAddrs []ma.Multiaddr
188
- for _, addr := range cfg.Announce {
178
+ for _, addr := range announce {
179
maddr, err := ma.NewMultiaddr(addr)
180
if err != nil {
181
return nil, err
@@ -195,7 +185,7 @@ func makeAddrsFactory(cfg config.Addresses) (p2pbhost.AddrsFactory, error) {
185
186
filters := mafilter.NewFilters()
187
noAnnAddrs := map[string]bool{}
198
- for _, addr := range cfg.NoAnnounce {
188
+ for _, addr := range noAnnounce {
189
f, err := mamask.NewMask(addr)
190
if err == nil {
191
filters.AddDialFilter(f)
@@ -229,41 +219,23 @@ func makeAddrsFactory(cfg config.Addresses) (p2pbhost.AddrsFactory, error) {
219
}, nil
220
}
221
232
-func AddrsFactory(cfg *config.Config) (opts Libp2pOpts, err error) {
233
- addrsFactory, err := makeAddrsFactory(cfg.Addresses)
234
- if err != nil {
235
- return opts, err
222
+func AddrsFactory(announce []string, noAnnounce []string) func() (opts Libp2pOpts, err error) {
223
+ return func() (opts Libp2pOpts, err error) {
224
+ addrsFactory, err := makeAddrsFactory(announce, noAnnounce)
225
+ if err != nil {
226
+ return opts, err
227
+ }
228
+ opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory))
229
+ return
230
}
237
- opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory))
238
- return
231
}
232
241
-func ConnectionManager(cfg *config.Config) (opts Libp2pOpts, err error) {
242
- grace := config.DefaultConnMgrGracePeriod
243
- low := config.DefaultConnMgrHighWater
244
- high := config.DefaultConnMgrHighWater
245
-
246
- switch cfg.Swarm.ConnMgr.Type {
247
- case "":
248
- // 'default' value is the basic connection manager
233
+func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) {
234
+ return func() (opts Libp2pOpts, err error) {
235
+ cm := connmgr.NewConnManager(low, high, grace)
236
+ opts.Opts = append(opts.Opts, libp2p.ConnectionManager(cm))
237
return
250
- case "none":
251
- return opts, nil
252
- case "basic":
253
- grace, err = time.ParseDuration(cfg.Swarm.ConnMgr.GracePeriod)
254
- if err != nil {
255
- return opts, fmt.Errorf("parsing Swarm.ConnMgr.GracePeriod: %s", err)
256
- }
257
-
258
- low = cfg.Swarm.ConnMgr.LowWater
259
- high = cfg.Swarm.ConnMgr.HighWater
260
- default:
261
- return opts, fmt.Errorf("unrecognized ConnMgr.Type: %q", cfg.Swarm.ConnMgr.Type)
238
}
263
-
264
- cm := connmgr.NewConnManager(low, high, grace)
265
- opts.Opts = append(opts.Opts, libp2p.ConnectionManager(cm))
266
- return
239
}
240
241
func makeSmuxTransportOption(mplexExp bool) libp2p.Option {
@@ -315,32 +287,29 @@ func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) {
287
}
288
}
289
318
-func NatPortMap(cfg *config.Config) (opts Libp2pOpts, err error) {
319
- if !cfg.Swarm.DisableNatPortMap {
320
- opts.Opts = append(opts.Opts, libp2p.NATPortMap())
321
- }
290
+func NatPortMap() (opts Libp2pOpts, err error) {
291
+ opts.Opts = append(opts.Opts, libp2p.NATPortMap())
292
return
293
}
294
325
-func Relay(cfg *config.Config) (opts Libp2pOpts, err error) {
326
- if cfg.Swarm.DisableRelay {
327
- // Enabled by default.
328
- opts.Opts = append(opts.Opts, libp2p.DisableRelay())
329
- } else {
330
- relayOpts := []relay.RelayOpt{relay.OptDiscovery}
331
- if cfg.Swarm.EnableRelayHop {
332
- relayOpts = append(relayOpts, relay.OptHop)
295
+func Relay(disable, enableHop bool) func() (opts Libp2pOpts, err error) {
296
+ return func() (opts Libp2pOpts, err error) {
297
+ if disable {
298
+ // Enabled by default.
299
+ opts.Opts = append(opts.Opts, libp2p.DisableRelay())
300
+ } else {
301
+ relayOpts := []relay.RelayOpt{relay.OptDiscovery}
302
+ if enableHop {
303
+ relayOpts = append(relayOpts, relay.OptHop)
304
+ }
305
+ opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
306
}
334
- opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
307
+ return
308
}
336
- return
309
}
310
339
-func AutoRealy(cfg *config.Config) (opts Libp2pOpts, err error) {
340
- // enable autorelay
341
- if cfg.Swarm.EnableAutoRelay {
342
- opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay())
343
- }
311
+func AutoRealy() (opts Libp2pOpts, err error) {
312
+ opts.Opts = append(opts.Opts, libp2p.EnableAutoRelay())
313
return
314
}
315
@@ -349,14 +318,12 @@ func DefaultTransports() (opts Libp2pOpts, err error) {
318
return
319
}
320
352
-func QUIC(cfg *config.Config) (opts Libp2pOpts, err error) {
353
- if cfg.Experimental.QUIC {
354
- opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport))
355
- }
321
+func QUIC() (opts Libp2pOpts, err error) {
322
+ opts.Opts = append(opts.Opts, libp2p.Transport(libp2pquic.NewTransport))
323
return
324
}
325
359
-func Security(enabled bool) interface{} {
326
+func Security(enabled, preferTLS bool) interface{} {
327
if !enabled {
328
return func() (opts Libp2pOpts) {
329
// TODO: shouldn't this be Errorf to guarantee visibility?
@@ -366,8 +333,8 @@ func Security(enabled bool) interface{} {
333
return opts
334
}
335
}
369
- return func(cfg *config.Config) (opts Libp2pOpts) {
370
- if cfg.Experimental.PreferTLS {
336
+ return func() (opts Libp2pOpts) {
337
+ if preferTLS {
338
opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New)))
339
} else {
340
opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(secio.ID, secio.New), libp2p.Security(tls.ID, tls.New)))
@@ -524,58 +491,42 @@ func PubsubRouter(mctx helpers.MetricsCtx, lc fx.Lifecycle, in p2pPSRoutingIn) (
491
}, psRouter
492
}
493
527
-func AutoNATService(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, cfg *config.Config, host host.Host) error {
528
- if !cfg.Swarm.EnableAutoNATService {
529
- return nil
530
- }
494
+func AutoNATService(quic bool) func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
495
+ return func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
496
+ // collect private net option in case swarm.key is presented
497
+ opts, _, err := PNet(repo)
498
+ if err != nil {
499
+ // swarm key exists but was failed to decode
500
+ return err
501
+ }
502
532
- // collect private net option in case swarm.key is presented
533
- opts, _, err := PNet(repo)
534
- if err != nil {
535
- // swarm key exists but was failed to decode
536
- return err
537
- }
503
+ if quic {
504
+ opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport))
505
+ }
506
539
- if cfg.Experimental.QUIC {
540
- opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport))
507
+ _, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...)
508
+ return err
509
}
542
-
543
- _, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...)
544
- return err
510
}
511
547
-func Pubsub(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, cfg *config.Config) (service *pubsub.PubSub, err error) {
548
- var pubsubOptions []pubsub.Option
549
- if cfg.Pubsub.DisableSigning {
550
- pubsubOptions = append(pubsubOptions, pubsub.WithMessageSigning(false))
512
+func FloodSub(pubsubOptions ...pubsub.Option) interface{} {
513
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
514
+ return pubsub.NewFloodSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
515
}
516
+}
517
553
- if cfg.Pubsub.StrictSignatureVerification {
554
- pubsubOptions = append(pubsubOptions, pubsub.WithStrictSignatureVerification(true))
555
- }
556
-
557
- switch cfg.Pubsub.Router {
558
- case "":
559
- fallthrough
560
- case "floodsub":
561
- service, err = pubsub.NewFloodSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
562
-
563
- case "gossipsub":
564
- service, err = pubsub.NewGossipSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
565
-
566
- default:
567
- err = fmt.Errorf("Unknown pubsub router %s", cfg.Pubsub.Router)
518
+func GossipSub(pubsubOptions ...pubsub.Option) interface{} {
519
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
520
+ return pubsub.NewGossipSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
521
}
569
-
570
- return service, err
522
}
523
573
-func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
524
+func listenAddresses(addresses []string) ([]ma.Multiaddr, error) {
525
var listen []ma.Multiaddr
575
- for _, addr := range cfg.Addresses.Swarm {
526
+ for _, addr := range addresses {
527
maddr, err := ma.NewMultiaddr(addr)
528
if err != nil {
578
- return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", cfg.Addresses.Swarm)
529
+ return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", addresses)
530
}
531
listen = append(listen, maddr)
532
}
@@ -583,22 +534,24 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
534
return listen, nil
535
}
536
586
-func StartListening(host host.Host, cfg *config.Config) error {
587
- listenAddrs, err := listenAddresses(cfg)
588
- if err != nil {
589
- return err
590
- }
537
+func StartListening(addresses []string) func(host host.Host) error {
538
+ return func(host host.Host) error {
539
+ listenAddrs, err := listenAddresses(addresses)
540
+ if err != nil {
541
+ return err
542
+ }
543
592
- // Actually start listening:
593
- if err := host.Network().Listen(listenAddrs...); err != nil {
594
- return err
595
- }
544
+ // Actually start listening:
545
+ if err := host.Network().Listen(listenAddrs...); err != nil {
546
+ return err
547
+ }
548
597
- // list out our addresses
598
- addrs, err := host.Network().InterfaceListenAddresses()
599
- if err != nil {
600
- return err
549
+ // list out our addresses
550
+ addrs, err := host.Network().InterfaceListenAddresses()
551
+ if err != nil {
552
+ return err
553
+ }
554
+ log.Infof("Swarm listening at: %s", addrs)
555
+ return nil
556
}
602
- log.Infof("Swarm listening at: %s", addrs)
603
- return nil
557
}
core/node/provider.go
+3
-29
@@ -2,16 +2,12 @@ package node
2
3
import (
4
"context"
5
- "fmt"
5
"time"
6
8
- "github.com/ipfs/go-ipfs-config"
9
- "github.com/ipfs/go-ipld-format"
7
"github.com/libp2p/go-libp2p-routing"
8
"go.uber.org/fx"
9
10
"github.com/ipfs/go-ipfs/core/node/helpers"
14
- "github.com/ipfs/go-ipfs/pin"
11
"github.com/ipfs/go-ipfs/provider"
12
"github.com/ipfs/go-ipfs/repo"
13
"github.com/ipfs/go-ipfs/reprovide"
@@ -42,32 +38,10 @@ func ProviderCtor(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *provider.Queu
38
}
39
40
// ReproviderCtor creates new reprovider
45
-func ReproviderCtor(mctx helpers.MetricsCtx, lc fx.Lifecycle, cfg *config.Config, bs BaseBlocks, ds format.DAGService, pinning pin.Pinner, rt routing.IpfsRouting) (*reprovide.Reprovider, error) {
46
- var keyProvider reprovide.KeyChanFunc
47
-
48
- reproviderInterval := kReprovideFrequency
49
- if cfg.Reprovider.Interval != "" {
50
- dur, err := time.ParseDuration(cfg.Reprovider.Interval)
51
- if err != nil {
52
- return nil, err
53
- }
54
-
55
- reproviderInterval = dur
56
- }
57
-
58
- switch cfg.Reprovider.Strategy {
59
- case "all":
60
- fallthrough
61
- case "":
62
- keyProvider = reprovide.NewBlockstoreProvider(bs)
63
- case "roots":
64
- keyProvider = reprovide.NewPinnedProvider(pinning, ds, true)
65
- case "pinned":
66
- keyProvider = reprovide.NewPinnedProvider(pinning, ds, false)
67
- default:
68
- return nil, fmt.Errorf("unknown reprovider strategy '%s'", cfg.Reprovider.Strategy)
41
+func ReproviderCtor(reproviderInterval time.Duration) func(helpers.MetricsCtx, fx.Lifecycle, routing.IpfsRouting, reprovide.KeyChanFunc) (*reprovide.Reprovider, error) {
42
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt routing.IpfsRouting, keyProvider reprovide.KeyChanFunc) (*reprovide.Reprovider, error) {
43
+ return reprovide.NewReprovider(helpers.LifecycleCtx(mctx, lc), reproviderInterval, rt, keyProvider), nil
44
}
70
- return reprovide.NewReprovider(helpers.LifecycleCtx(mctx, lc), reproviderInterval, rt, keyProvider), nil
45
}
46
47
// Reprovider runs the reprovider service
core/node/storage.go
+18
-17
@@ -42,8 +42,8 @@ func Datastore(repo repo.Repo) datastore.Datastore {
42
type BaseBlocks blockstore.Blockstore
43
44
// BaseBlockstoreCtor creates cached blockstore backed by the provided datastore
45
-func BaseBlockstoreCtor(permanent bool, nilRepo bool) func(mctx helpers.MetricsCtx, repo repo.Repo, cfg *config.Config, lc fx.Lifecycle) (bs BaseBlocks, err error) {
46
- return func(mctx helpers.MetricsCtx, repo repo.Repo, cfg *config.Config, lc fx.Lifecycle) (bs BaseBlocks, err error) {
45
+func BaseBlockstoreCtor(cacheOpts blockstore.CacheOpts, nilRepo bool, hashOnRead bool) func(mctx helpers.MetricsCtx, repo repo.Repo, lc fx.Lifecycle) (bs BaseBlocks, err error) {
46
+ return func(mctx helpers.MetricsCtx, repo repo.Repo, lc fx.Lifecycle) (bs BaseBlocks, err error) {
47
rds := &retrystore.Datastore{
48
Batching: repo.Datastore(),
49
Delay: time.Millisecond * 200,
@@ -54,12 +54,6 @@ func BaseBlockstoreCtor(permanent bool, nilRepo bool) func(mctx helpers.MetricsC
54
bs = blockstore.NewBlockstore(rds)
55
bs = &verifbs.VerifBS{Blockstore: bs}
56
57
- opts := blockstore.DefaultCacheOpts()
58
- opts.HasBloomFilterSize = cfg.Datastore.BloomFilterSize
59
- if !permanent {
60
- opts.HasBloomFilterSize = 0
61
- }
62
-
57
if !nilRepo {
58
ctx, cancel := context.WithCancel(mctx)
59
@@ -69,7 +63,7 @@ func BaseBlockstoreCtor(permanent bool, nilRepo bool) func(mctx helpers.MetricsC
63
return nil
64
},
65
})
72
- bs, err = blockstore.CachedBlockstore(ctx, bs, opts)
66
+ bs, err = blockstore.CachedBlockstore(ctx, bs, cacheOpts)
67
if err != nil {
68
return nil, err
69
}
@@ -78,7 +72,7 @@ func BaseBlockstoreCtor(permanent bool, nilRepo bool) func(mctx helpers.MetricsC
72
bs = blockstore.NewIdStore(bs)
73
bs = cidv0v1.NewBlockstore(bs)
74
81
- if cfg.Datastore.HashOnRead { // TODO: review: this is how it was done originally, is there a reason we can't just pass this directly?
75
+ if hashOnRead { // TODO: review: this is how it was done originally, is there a reason we can't just pass this directly?
76
bs.HashOnRead(true)
77
}
78
@@ -87,16 +81,23 @@ func BaseBlockstoreCtor(permanent bool, nilRepo bool) func(mctx helpers.MetricsC
81
}
82
83
// GcBlockstoreCtor wraps the base blockstore with GC and Filestore layers
90
-func GcBlockstoreCtor(repo repo.Repo, bb BaseBlocks, cfg *config.Config) (gclocker blockstore.GCLocker, gcbs blockstore.GCBlockstore, bs blockstore.Blockstore, fstore *filestore.Filestore) {
84
+func GcBlockstoreCtor(bb BaseBlocks) (gclocker blockstore.GCLocker, gcbs blockstore.GCBlockstore, bs blockstore.Blockstore) {
85
gclocker = blockstore.NewGCLocker()
86
gcbs = blockstore.NewGCBlockstore(bb, gclocker)
87
94
- if cfg.Experimental.FilestoreEnabled || cfg.Experimental.UrlstoreEnabled {
95
- // hash security
96
- fstore = filestore.NewFilestore(bb, repo.FileManager()) // TODO: mark optional
97
- gcbs = blockstore.NewGCBlockstore(fstore, gclocker)
98
- gcbs = &verifbs.VerifBSGC{GCBlockstore: gcbs}
99
- }
88
+ bs = gcbs
89
+ return
90
+}
91
+
92
+// GcBlockstoreCtor wraps GcBlockstore and adds Filestore support
93
+func FilestoreBlockstoreCtor(repo repo.Repo, bb BaseBlocks) (gclocker blockstore.GCLocker, gcbs blockstore.GCBlockstore, bs blockstore.Blockstore, fstore *filestore.Filestore) {
94
+ gclocker, gcbs, bs = GcBlockstoreCtor(bb)
95
+
96
+ // hash security
97
+ fstore = filestore.NewFilestore(bb, repo.FileManager())
98
+ gcbs = blockstore.NewGCBlockstore(fstore, gclocker)
99
+ gcbs = &verifbs.VerifBSGC{GCBlockstore: gcbs}
100
+
101
bs = gcbs
102
return
103
}
reprovide/providers.go
+19
-17
@@ -20,27 +20,29 @@ func NewBlockstoreProvider(bstore blocks.Blockstore) KeyChanFunc {
20
}
21
22
// NewPinnedProvider returns provider supplying pinned keys
23
-func NewPinnedProvider(pinning pin.Pinner, dag ipld.DAGService, onlyRoots bool) KeyChanFunc {
24
- return func(ctx context.Context) (<-chan cid.Cid, error) {
25
- set, err := pinSet(ctx, pinning, dag, onlyRoots)
26
- if err != nil {
27
- return nil, err
28
- }
23
+func NewPinnedProvider(onlyRoots bool) func(pinning pin.Pinner, dag ipld.DAGService) KeyChanFunc {
24
+ return func(pinning pin.Pinner, dag ipld.DAGService) KeyChanFunc {
25
+ return func(ctx context.Context) (<-chan cid.Cid, error) {
26
+ set, err := pinSet(ctx, pinning, dag, onlyRoots)
27
+ if err != nil {
28
+ return nil, err
29
+ }
30
30
- outCh := make(chan cid.Cid)
31
- go func() {
32
- defer close(outCh)
33
- for c := range set.New {
34
- select {
35
- case <-ctx.Done():
36
- return
37
- case outCh <- c:
31
+ outCh := make(chan cid.Cid)
32
+ go func() {
33
+ defer close(outCh)
34
+ for c := range set.New {
35
+ select {
36
+ case <-ctx.Done():
37
+ return
38
+ case outCh <- c:
39
+ }
40
}
39
- }
41
41
- }()
42
+ }()
43
43
- return outCh, nil
44
+ return outCh, nil
45
+ }
46
}
47
}
48