@cryptotaxi247 / kubo / commits / 7a2545a14

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 +}