Commit 188c37e2 authored by Jeromy Johnson's avatar Jeromy Johnson

Merge pull request #773 from jbenet/feat/builder-master

implement nodebuilder
parents e397e521 7a2545a1
...@@ -99,9 +99,11 @@ func daemonFunc(req cmds.Request, res cmds.Response) { ...@@ -99,9 +99,11 @@ func daemonFunc(req cmds.Request, res cmds.Response) {
return return
} }
// OK!!! Now we're ready to construct the node. // Start assembling corebuilder
// make sure we construct an online node. nb := core.NewNodeBuilder().Online()
node, err := core.NewIPFSNode(ctx.Context, core.Online(repo)) nb.SetRepo(repo)
node, err := nb.Build(ctx.Context)
if err != nil { if err != nil {
res.SetError(err, cmds.ErrNormal) res.SetError(err, cmds.ErrNormal)
return return
......
package core
import (
"errors"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore"
dsync "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore/sync"
repo "github.com/jbenet/go-ipfs/repo"
)
var ErrAlreadyBuilt = errors.New("this builder has already been used")
// NodeBuilder is an object used to generate an IpfsNode
type NodeBuilder struct {
online bool
routing RoutingOption
peerhost HostOption
repo repo.Repo
built bool
}
func NewNodeBuilder() *NodeBuilder {
return &NodeBuilder{
online: false,
routing: DHTOption,
peerhost: DefaultHostOption,
}
}
func defaultRepo() repo.Repo {
return &repo.Mock{
D: dsync.MutexWrap(ds.NewMapDatastore()),
}
}
func (nb *NodeBuilder) Online() *NodeBuilder {
nb.online = true
return nb
}
func (nb *NodeBuilder) Offline() *NodeBuilder {
nb.online = false
return nb
}
func (nb *NodeBuilder) SetRouting(ro RoutingOption) *NodeBuilder {
nb.routing = ro
return nb
}
func (nb *NodeBuilder) SetHost(ho HostOption) *NodeBuilder {
nb.peerhost = ho
return nb
}
func (nb *NodeBuilder) SetRepo(r repo.Repo) *NodeBuilder {
nb.repo = r
return nb
}
func (nb *NodeBuilder) Build(ctx context.Context) (*IpfsNode, error) {
if nb.built {
return nil, ErrAlreadyBuilt
}
nb.built = true
if nb.repo == nil {
nb.repo = defaultRepo()
}
conf := standardWithRouting(nb.repo, nb.online, nb.routing, nb.peerhost)
return NewIPFSNode(ctx, conf)
}
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
package core package core
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"time" "time"
...@@ -146,11 +147,8 @@ func Offline(r repo.Repo) ConfigOption { ...@@ -146,11 +147,8 @@ func Offline(r repo.Repo) ConfigOption {
return Standard(r, false) return Standard(r, false)
} }
func OnlineWithRouting(r repo.Repo, router routing.IpfsRouting) ConfigOption { func OnlineWithOptions(r repo.Repo, router RoutingOption, ho HostOption) ConfigOption {
if router == nil { return standardWithRouting(r, true, router, ho)
panic("router required")
}
return standardWithRouting(r, true, router)
} }
func Online(r repo.Repo) ConfigOption { func Online(r repo.Repo) ConfigOption {
...@@ -159,11 +157,11 @@ func Online(r repo.Repo) ConfigOption { ...@@ -159,11 +157,11 @@ func Online(r repo.Repo) ConfigOption {
// DEPRECATED: use Online, Offline functions // DEPRECATED: use Online, Offline functions
func Standard(r repo.Repo, online bool) ConfigOption { func Standard(r repo.Repo, online bool) ConfigOption {
return standardWithRouting(r, online, nil) return standardWithRouting(r, online, DHTOption, DefaultHostOption)
} }
// TODO refactor so maybeRouter isn't special-cased in this way // TODO refactor so maybeRouter isn't special-cased in this way
func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouting) ConfigOption { func standardWithRouting(r repo.Repo, online bool, routingOption RoutingOption, hostOption HostOption) ConfigOption {
return func(ctx context.Context) (n *IpfsNode, err error) { return func(ctx context.Context) (n *IpfsNode, err error) {
// FIXME perform node construction in the main constructor so it isn't // FIXME perform node construction in the main constructor so it isn't
// necessary to perform this teardown in this scope. // necessary to perform this teardown in this scope.
...@@ -205,7 +203,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti ...@@ -205,7 +203,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti
} }
if online { if online {
if err := n.startOnlineServices(ctx, maybeRouter); err != nil { if err := n.startOnlineServices(ctx, routingOption, hostOption); err != nil {
return nil, err return nil, err
} }
} else { } else {
...@@ -217,7 +215,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti ...@@ -217,7 +215,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti
} }
} }
func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.IpfsRouting) error { func (n *IpfsNode) startOnlineServices(ctx context.Context, routingOption RoutingOption, hostOption HostOption) error {
if n.PeerHost != nil { // already online. if n.PeerHost != nil { // already online.
return debugerror.New("node already online") return debugerror.New("node already online")
...@@ -228,13 +226,13 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing. ...@@ -228,13 +226,13 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
return err return err
} }
peerhost, err := constructPeerHost(ctx, n.Identity, n.Peerstore) peerhost, err := hostOption(ctx, n.Identity, n.Peerstore)
if err != nil { if err != nil {
return debugerror.Wrap(err) return debugerror.Wrap(err)
} }
n.PeerHost = peerhost n.PeerHost = peerhost
if err := n.startOnlineServicesWithHost(ctx, maybeRouter); err != nil { if err := n.startOnlineServicesWithHost(ctx, routingOption); err != nil {
return err return err
} }
...@@ -251,20 +249,16 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing. ...@@ -251,20 +249,16 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
// startOnlineServicesWithHost is the set of services which need to be // startOnlineServicesWithHost is the set of services which need to be
// initialized with the host and _before_ we start listening. // initialized with the host and _before_ we start listening.
func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, maybeRouter routing.IpfsRouting) error { func (n *IpfsNode) startOnlineServicesWithHost(ctx context.Context, routingOption RoutingOption) error {
// setup diagnostics service // setup diagnostics service
n.Diagnostics = diag.NewDiagnostics(n.Identity, n.PeerHost) n.Diagnostics = diag.NewDiagnostics(n.Identity, n.PeerHost)
// setup routing service // setup routing service
if maybeRouter != nil { r, err := routingOption(ctx, n)
n.Routing = maybeRouter if err != nil {
} else { return debugerror.Wrap(err)
dhtRouting, err := constructDHTRouting(ctx, n.PeerHost, n.Repo.Datastore())
if err != nil {
return debugerror.Wrap(err)
}
n.Routing = dhtRouting
} }
n.Routing = r
// setup exchange service // setup exchange service
const alwaysSendToPeer = true // use YesManStrategy const alwaysSendToPeer = true // use YesManStrategy
...@@ -282,16 +276,17 @@ func (n *IpfsNode) teardown() error { ...@@ -282,16 +276,17 @@ func (n *IpfsNode) teardown() error {
log.Debug("core is shutting down...") log.Debug("core is shutting down...")
// owned objects are closed in this teardown to ensure that they're closed // owned objects are closed in this teardown to ensure that they're closed
// regardless of which constructor was used to add them to the node. // regardless of which constructor was used to add them to the node.
var closers []io.Closer closers := []io.Closer{
n.Blocks,
n.Exchange,
n.Repo,
}
addCloser := func(c io.Closer) { // use when field may be nil addCloser := func(c io.Closer) { // use when field may be nil
if c != nil { if c != nil {
closers = append(closers, c) closers = append(closers, c)
} }
} }
addCloser(n.Blocks)
addCloser(n.Exchange)
addCloser(n.Repo)
addCloser(n.Bootstrapper) addCloser(n.Bootstrapper)
if dht, ok := n.Routing.(*dht.IpfsDHT); ok { if dht, ok := n.Routing.(*dht.IpfsDHT); ok {
addCloser(dht) addCloser(dht)
...@@ -444,6 +439,10 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) { ...@@ -444,6 +439,10 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
return listen, nil return listen, nil
} }
type HostOption func(ctx context.Context, id peer.ID, ps peer.Peerstore) (p2phost.Host, error)
var DefaultHostOption HostOption = constructPeerHost
// isolates the complex initialization steps // isolates the complex initialization steps
func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore) (p2phost.Host, error) { func constructPeerHost(ctx context.Context, id peer.ID, ps peer.Peerstore) (p2phost.Host, error) {
...@@ -491,3 +490,15 @@ func constructDHTRouting(ctx context.Context, host p2phost.Host, ds datastore.Th ...@@ -491,3 +490,15 @@ func constructDHTRouting(ctx context.Context, host p2phost.Host, ds datastore.Th
dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord
return dhtRouting, nil return dhtRouting, nil
} }
type RoutingOption func(context.Context, *IpfsNode) (routing.IpfsRouting, error)
var DHTOption RoutingOption = func(ctx context.Context, n *IpfsNode) (routing.IpfsRouting, error) {
if n.PeerHost == nil {
return nil, errors.New("dht requires a peerhost")
}
if n.Repo == nil {
return nil, errors.New("dht requires a datastore. (node has no Repo)")
}
return constructDHTRouting(ctx, n.PeerHost, n.Repo.Datastore())
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment