/ core / node / builder.go
builder.go
  1  package node
  2  
  3  import (
  4  	"context"
  5  	"crypto/rand"
  6  	"encoding/base64"
  7  
  8  	"go.uber.org/fx"
  9  
 10  	"github.com/ipfs/boxo/autoconf"
 11  	"github.com/ipfs/kubo/core/node/helpers"
 12  	"github.com/ipfs/kubo/core/node/libp2p"
 13  	"github.com/ipfs/kubo/repo"
 14  
 15  	ds "github.com/ipfs/go-datastore"
 16  	dsync "github.com/ipfs/go-datastore/sync"
 17  	cfg "github.com/ipfs/kubo/config"
 18  	"github.com/libp2p/go-libp2p/core/crypto"
 19  	peer "github.com/libp2p/go-libp2p/core/peer"
 20  )
 21  
 22  type BuildCfg struct {
 23  	// If online is set, the node will have networking enabled
 24  	Online bool
 25  
 26  	// ExtraOpts is a map of extra options used to configure the ipfs nodes creation
 27  	ExtraOpts map[string]bool
 28  
 29  	// If permanent then node should run more expensive processes
 30  	// that will improve performance in long run
 31  	Permanent bool
 32  
 33  	// DisableEncryptedConnections disables connection encryption *entirely*.
 34  	// DO NOT SET THIS UNLESS YOU'RE TESTING.
 35  	DisableEncryptedConnections bool
 36  
 37  	Routing libp2p.RoutingOption
 38  	Host    libp2p.HostOption
 39  	Repo    repo.Repo
 40  }
 41  
 42  func (cfg *BuildCfg) getOpt(key string) bool {
 43  	if cfg.ExtraOpts == nil {
 44  		return false
 45  	}
 46  
 47  	return cfg.ExtraOpts[key]
 48  }
 49  
 50  func (cfg *BuildCfg) fillDefaults() error {
 51  	if cfg.Repo == nil {
 52  		r, err := defaultRepo(dsync.MutexWrap(ds.NewMapDatastore()))
 53  		if err != nil {
 54  			return err
 55  		}
 56  		cfg.Repo = r
 57  	}
 58  
 59  	if cfg.Routing == nil {
 60  		cfg.Routing = libp2p.DHTOption
 61  	}
 62  
 63  	if cfg.Host == nil {
 64  		cfg.Host = libp2p.DefaultHostOption
 65  	}
 66  
 67  	return nil
 68  }
 69  
 70  // options creates fx option group from this build config
 71  func (cfg *BuildCfg) options(ctx context.Context) (fx.Option, *cfg.Config) {
 72  	err := cfg.fillDefaults()
 73  	if err != nil {
 74  		return fx.Error(err), nil
 75  	}
 76  
 77  	repoOption := fx.Provide(func(lc fx.Lifecycle) repo.Repo {
 78  		lc.Append(fx.Hook{
 79  			OnStop: func(ctx context.Context) error {
 80  				return cfg.Repo.Close()
 81  			},
 82  		})
 83  
 84  		return cfg.Repo
 85  	})
 86  
 87  	metricsCtx := fx.Provide(func() helpers.MetricsCtx {
 88  		return helpers.MetricsCtx(ctx)
 89  	})
 90  
 91  	hostOption := fx.Provide(func() libp2p.HostOption {
 92  		return cfg.Host
 93  	})
 94  
 95  	routingOption := fx.Provide(func() libp2p.RoutingOption {
 96  		return cfg.Routing
 97  	})
 98  
 99  	conf, err := cfg.Repo.Config()
100  	if err != nil {
101  		return fx.Error(err), nil
102  	}
103  
104  	return fx.Options(
105  		repoOption,
106  		hostOption,
107  		routingOption,
108  		metricsCtx,
109  	), conf
110  }
111  
112  func defaultRepo(dstore repo.Datastore) (repo.Repo, error) {
113  	c := cfg.Config{}
114  	priv, pub, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader)
115  	if err != nil {
116  		return nil, err
117  	}
118  
119  	pid, err := peer.IDFromPublicKey(pub)
120  	if err != nil {
121  		return nil, err
122  	}
123  
124  	privkeyb, err := crypto.MarshalPrivateKey(priv)
125  	if err != nil {
126  		return nil, err
127  	}
128  
129  	c.Bootstrap = autoconf.FallbackBootstrapPeers
130  	c.Addresses.Swarm = []string{"/ip4/0.0.0.0/tcp/4001", "/ip4/0.0.0.0/udp/4001/quic-v1"}
131  	c.Identity.PeerID = pid.String()
132  	c.Identity.PrivKey = base64.StdEncoding.EncodeToString(privkeyb)
133  
134  	return &repo.Mock{
135  		D: dstore,
136  		C: c,
137  	}, nil
138  }