implement nodebuilder
Jeromy committed
Feb 11, 2015 at 21:47 UTC
7a2545a14b17630a19f40be97fdba52b8f5ec9c9
3 files changed
+113
-27
cmd/ipfs/daemon.go
+5
-3
@@ -99,9 +99,11 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
99
return
100
}
101
102
- // OK!!! Now we're ready to construct the node.
103
- // make sure we construct an online node.
104
- node, err := core.NewIPFSNode(ctx.Context, core.Online(repo))
102
+ // Start assembling corebuilder
103
+ nb := core.NewNodeBuilder().Online()
104
+ nb.SetRepo(repo)
105
+
106
+ node, err := nb.Build(ctx.Context)
107
if err != nil {
108
res.SetError(err, cmds.ErrNormal)
109
return
core/builder.go
new
+73
@@ -0,0 +1,73 @@
1
+package core
2
+
3
+import (
4
+ "errors"
5
+
6
+ context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7
+ ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
8
+ dsync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
9
+
10
+ repo "github.com/jbenet/go-ipfs/repo"
11
+)
12
+
13
+var ErrAlreadyBuilt = errors.New("this builder has already been used")
14
+
15
+// NodeBuilder is an object used to generate an IpfsNode
16
+type NodeBuilder struct {
17
+ online bool
18
+ routing RoutingOption
19
+ peerhost HostOption
20
+ repo repo.Repo
21
+ built bool
22
+}
23
+
24
+func NewNodeBuilder() *NodeBuilder {
25
+ return &NodeBuilder{
26
+ online: false,
27
+ routing: DHTOption,
28
+ peerhost: DefaultHostOption,
29
+ }
30
+}
31
+
32
+func defaultRepo() repo.Repo {
33
+ return &repo.Mock{
34
+ D: dsync.MutexWrap(ds.NewMapDatastore()),
35
+ }
36
+}
37
+
38
+func (nb *NodeBuilder) Online() *NodeBuilder {
39
+ nb.online = true
40
+ return nb
41
+}
42
+
43
+func (nb *NodeBuilder) Offline() *NodeBuilder {
44
+ nb.online = false
45
+ return nb
46
+}
47
+
48
+func (nb *NodeBuilder) SetRouting(ro RoutingOption) *NodeBuilder {
49
+ nb.routing = ro
50
+ return nb
51
+}
52
+
53
+func (nb *NodeBuilder) SetHost(ho HostOption) *NodeBuilder {
54
+ nb.peerhost = ho
55
+ return nb
56
+}
57
+
58
+func (nb *NodeBuilder) SetRepo(r repo.Repo) *NodeBuilder {
59
+ nb.repo = r
60
+ return nb
61
+}
62
+
63
+func (nb *NodeBuilder) Build(ctx context.Context) (*IpfsNode, error) {
64
+ if nb.built {
65
+ return nil, ErrAlreadyBuilt
66
+ }
67
+ nb.built = true
68
+ if nb.repo == nil {
69
+ nb.repo = defaultRepo()
70
+ }
71
+ conf := standardWithRouting(nb.repo, nb.online, nb.routing, nb.peerhost)
72
+ return NewIPFSNode(ctx, conf)
73
+}
core/core.go
+35
-24
@@ -3,6 +3,7 @@
3
package core
4
5
import (
6
+ "errors"
7
"fmt"
8
"io"
9
"time"
@@ -146,11 +147,8 @@ func Offline(r repo.Repo) ConfigOption {
147
return Standard(r, false)
148
}
149
149
-func OnlineWithRouting(r repo.Repo, router routing.IpfsRouting) ConfigOption {
150
- if router == nil {
151
- panic("router required")
152
- }
153
- return standardWithRouting(r, true, router)
150
+func OnlineWithOptions(r repo.Repo, router RoutingOption, ho HostOption) ConfigOption {
151
+ return standardWithRouting(r, true, router, ho)
152
}
153
154
func Online(r repo.Repo) ConfigOption {
@@ -159,11 +157,11 @@ func Online(r repo.Repo) ConfigOption {
157
158
// DEPRECATED: use Online, Offline functions
159
func Standard(r repo.Repo, online bool) ConfigOption {
162
- return standardWithRouting(r, online, nil)
160
+ return standardWithRouting(r, online, DHTOption, DefaultHostOption)
161
}
162
163
// TODO refactor so maybeRouter isn't special-cased in this way
166
-func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouting) ConfigOption {
164
+func standardWithRouting(r repo.Repo, online bool, routingOption RoutingOption, hostOption HostOption) ConfigOption {
165
return func(ctx context.Context) (n *IpfsNode, err error) {
166
// FIXME perform node construction in the main constructor so it isn't
167
// necessary to perform this teardown in this scope.
@@ -205,7 +203,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti
203
}
204
205
if online {
208
- if err := n.startOnlineServices(ctx, maybeRouter); err != nil {
206
+ if err := n.startOnlineServices(ctx, routingOption, hostOption); err != nil {
207
return nil, err
208
}
209
} else {
@@ -217,7 +215,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti
215
}
216
}
217
220
-func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.IpfsRouting) error {
218
+func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption) error {
219
220
if n.PeerHost != nil { // already online.
221
return debugerror.New("node already online")
@@ -228,13 +226,13 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
226
return err
227
}
228
231
- peerhost, err := constructPeerHost(ctx, n.Identity, n.Peerstore)
229
+ peerhost, err := hostOption(ctx, n.Identity, n.Peerstore)
230
if err != nil {
231
return debugerror.Wrap(err)
232
}
233
n.PeerHost = peerhost
234
237
- if err := n.startOnlineServicesWithHost(ctx, maybeRouter); err != nil {
235
+ if err := n.startOnlineServicesWithHost(ctx, routingOption); err != nil {
236
return err
237
}
238
@@ -251,20 +249,16 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
249
250
// startOnlineServicesWithHost is the set of services which need to be
251
// initialized with the host and _before_ we start listening.
254
-func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, maybeRouter routing.IpfsRouting) error {
252
+func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, routingOption RoutingOption) error {
253
// setup diagnostics service
254
n.Diagnostics = diag.NewDiagnostics(n.Identity, n.PeerHost)
255
256
// setup routing service
259
- if maybeRouter != nil {
260
- n.Routing = maybeRouter
261
- } else {
262
- dhtRouting, err := constructDHTRouting(ctx, n.PeerHost, n.Repo.Datastore())
263
- if err != nil {
264
- return debugerror.Wrap(err)
265
- }
266
- n.Routing = dhtRouting
257
+ r, err := routingOption(ctx, n)
258
+ if err != nil {
259
+ return debugerror.Wrap(err)
260
}
261
+ n.Routing = r
262
263
// setup exchange service
264
const alwaysSendToPeer = true // use YesManStrategy
@@ -282,16 +276,17 @@ func (n *IpfsNode) teardown() error {
276
log.Debug("core is shutting down...")
277
// owned objects are closed in this teardown to ensure that they're closed
278
// regardless of which constructor was used to add them to the node.
285
- var closers []io.Closer
279
+ closers := []io.Closer{
280
+ n.Blocks,
281
+ n.Exchange,
282
+ n.Repo,
283
+ }
284
addCloser := func(c io.Closer) { // use when field may be nil
285
if c != nil {
286
closers = append(closers, c)
287
}
288
}
289
292
- addCloser(n.Blocks)
293
- addCloser(n.Exchange)
294
- addCloser(n.Repo)
290
addCloser(n.Bootstrapper)
291
if dht, ok := n.Routing.(*dht.IpfsDHT); ok {
292
addCloser(dht)
@@ -444,6 +439,10 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
439
return listen, nil
440
}
441
442
+type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore) (p2phost.Host, error)
443
+
444
+var DefaultHostOption HostOption = constructPeerHost
445
+
446
// isolates the complex initialization steps
447
func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore) (p2phost.Host, error) {
448
@@ -491,3 +490,15 @@ func constructDHTRouting(ctx context.Context, host p2phost.Host, ds datastore.Th
490
dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord
491
return dhtRouting, nil
492
}
493
+
494
+type RoutingOption func(context.Context, *IpfsNode) (routing.IpfsRouting, error)
495
+
496
+var DHTOption RoutingOption = func(ctx context.Context, n *IpfsNode) (routing.IpfsRouting, error) {
497
+ if n.PeerHost == nil {
498
+ return nil, errors.New("dht requires a peerhost")
499
+ }
500
+ if n.Repo == nil {
501
+ return nil, errors.New("dht requires a datastore. (node has no Repo)")
502
+ }
503
+ return constructDHTRouting(ctx, n.PeerHost, n.Repo.Datastore())
504
+}