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) {
return
}
// OK!!! Now we're ready to construct the node.
// make sure we construct an online node.
node, err := core.NewIPFSNode(ctx.Context, core.Online(repo))
// Start assembling corebuilder
nb := core.NewNodeBuilder().Online()
nb.SetRepo(repo)
node, err := nb.Build(ctx.Context)
if err != nil {
res.SetError(err, cmds.ErrNormal)
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 @@
package core
import (
"errors"
"fmt"
"io"
"time"
......@@ -146,11 +147,8 @@ func Offline(r repo.Repo) ConfigOption {
return Standard(r, false)
}
func OnlineWithRouting(r repo.Repo, router routing.IpfsRouting) ConfigOption {
if router == nil {
panic("router required")
}
return standardWithRouting(r, true, router)
func OnlineWithOptions(r repo.Repo, router RoutingOption, ho HostOption) ConfigOption {
return standardWithRouting(r, true, router, ho)
}
func Online(r repo.Repo) ConfigOption {
......@@ -159,11 +157,11 @@ func Online(r repo.Repo) ConfigOption {
// DEPRECATED: use Online, Offline functions
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
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) {
// FIXME perform node construction in the main constructor so it isn't
// necessary to perform this teardown in this scope.
......@@ -205,7 +203,7 @@ func standardWithRouting(r repo.Repo, online bool, maybeRouter routing.IpfsRouti
}
if online {
if err := n.startOnlineServices(ctx, maybeRouter); err != nil {
if err := n.startOnlineServices(ctx, routingOption, hostOption); err != nil {
return nil, err
}
} else {
......@@ -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.
return debugerror.New("node already online")
......@@ -228,13 +226,13 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
return err
}
peerhost, err := constructPeerHost(ctx, n.Identity, n.Peerstore)
peerhost, err := hostOption(ctx, n.Identity, n.Peerstore)
if err != nil {
return debugerror.Wrap(err)
}
n.PeerHost = peerhost
if err := n.startOnlineServicesWithHost(ctx, maybeRouter); err != nil {
if err := n.startOnlineServicesWithHost(ctx, routingOption); err != nil {
return err
}
......@@ -251,20 +249,16 @@ func (n *IpfsNode) startOnlineServices(ctx context.Context, maybeRouter routing.
// startOnlineServicesWithHost is the set of services which need to be
// 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
n.Diagnostics = diag.NewDiagnostics(n.Identity, n.PeerHost)
// setup routing service
if maybeRouter != nil {
n.Routing = maybeRouter
} else {
dhtRouting, err := constructDHTRouting(ctx, n.PeerHost, n.Repo.Datastore())
r, err := routingOption(ctx, n)
if err != nil {
return debugerror.Wrap(err)
}
n.Routing = dhtRouting
}
n.Routing = r
// setup exchange service
const alwaysSendToPeer = true // use YesManStrategy
......@@ -282,16 +276,17 @@ func (n *IpfsNode) teardown() error {
log.Debug("core is shutting down...")
// 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.
var closers []io.Closer
closers := []io.Closer{
n.Blocks,
n.Exchange,
n.Repo,
}
addCloser := func(c io.Closer) { // use when field may be nil
if c != nil {
closers = append(closers, c)
}
}
addCloser(n.Blocks)
addCloser(n.Exchange)
addCloser(n.Repo)
addCloser(n.Bootstrapper)
if dht, ok := n.Routing.(*dht.IpfsDHT); ok {
addCloser(dht)
......@@ -444,6 +439,10 @@ func listenAddresses(cfg *config.Config) ([]ma.Multiaddr, error) {
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
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
dhtRouting.Validator[IpnsValidatorTag] = namesys.ValidateIpnsRecord
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