Rewrite constructor to functional opts
This commit is contained in:
parent
f08263662f
commit
de604065fb
@ -2,6 +2,7 @@ package daemon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/filecoin-project/go-lotus/node/config"
|
||||
|
||||
"gopkg.in/urfave/cli.v2"
|
||||
|
||||
@ -15,7 +16,12 @@ var Cmd = &cli.Command{
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := context.Background()
|
||||
|
||||
api, err := node.New(ctx)
|
||||
cfg, err := config.FromFile("./config.toml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
api, err := node.New(ctx, node.Online(), node.Config(cfg))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
251
node/builder.go
251
node/builder.go
@ -2,10 +2,15 @@ package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"errors"
|
||||
"github.com/filecoin-project/go-lotus/node/config"
|
||||
"github.com/ipfs/go-datastore"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/peerstore"
|
||||
"github.com/libp2p/go-libp2p-core/routing"
|
||||
record "github.com/libp2p/go-libp2p-record"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
ci "github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/libp2p/go-libp2p-core/peer"
|
||||
"github.com/libp2p/go-libp2p-peerstore/pstoremem"
|
||||
@ -13,58 +18,130 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-lotus/api"
|
||||
"github.com/filecoin-project/go-lotus/build"
|
||||
"github.com/filecoin-project/go-lotus/node/config"
|
||||
"github.com/filecoin-project/go-lotus/node/modules"
|
||||
"github.com/filecoin-project/go-lotus/node/modules/helpers"
|
||||
"github.com/filecoin-project/go-lotus/node/modules/lp2p"
|
||||
)
|
||||
|
||||
// New builds and starts new Filecoin node
|
||||
func New(ctx context.Context) (api.API, error) {
|
||||
var resAPI api.Struct
|
||||
// special is a type used to give keys to modules which
|
||||
// can't really be identified by the returned type
|
||||
type special struct{ id int }
|
||||
|
||||
online := true
|
||||
var (
|
||||
DefaultTransportsKey = special{0} // Libp2p option
|
||||
PNetKey = special{1} // Option + multiret
|
||||
DiscoveryHandlerKey = special{2} // Private type
|
||||
AddrsFactoryKey = special{3} // Libp2p option
|
||||
SmuxTransportKey = special{4} // Libp2p option
|
||||
RelayKey = special{5} // Libp2p option
|
||||
SecurityKey = special{6} // Libp2p option
|
||||
BaseRoutingKey = special{7} // fx groups + multiret
|
||||
NatPortMapKey = special{8} // Libp2p option
|
||||
ConnectionManagerKey = special{9} // Libp2p option
|
||||
|
||||
)
|
||||
|
||||
type invoke int
|
||||
|
||||
const (
|
||||
PstoreAddSelfKeysKey = invoke(iota)
|
||||
StartListeningKey
|
||||
|
||||
_nInvokes // keep this last
|
||||
)
|
||||
|
||||
type settings struct {
|
||||
modules map[interface{}]fx.Option
|
||||
|
||||
// invokes are separate from modules as they can't be referenced by return
|
||||
// type, and must be applied in correct order
|
||||
invokes []fx.Option
|
||||
|
||||
online bool // Online option applied
|
||||
config bool // Config option applied
|
||||
}
|
||||
|
||||
var defConf = config.Default()
|
||||
|
||||
var defaults = []Option{
|
||||
Override(new(helpers.MetricsCtx), context.Background),
|
||||
|
||||
randomIdentity(),
|
||||
|
||||
Override(new(datastore.Batching), datastore.NewMapDatastore),
|
||||
Override(new(record.Validator), modules.RecordValidator),
|
||||
}
|
||||
|
||||
func Online() Option {
|
||||
return Options(
|
||||
func(s *settings) error { s.online = true; return nil },
|
||||
applyIf(func(s *settings) bool { return s.config },
|
||||
Error(errors.New("the Online option must be set before Config option")),
|
||||
),
|
||||
|
||||
Override(new(peerstore.Peerstore), pstoremem.NewPeerstore),
|
||||
|
||||
Override(DefaultTransportsKey, lp2p.DefaultTransports),
|
||||
Override(PNetKey, lp2p.PNet),
|
||||
|
||||
Override(new(lp2p.RawHost), lp2p.Host),
|
||||
Override(new(host.Host), lp2p.RoutedHost),
|
||||
Override(new(lp2p.BaseIpfsRouting), lp2p.DHTRouting(false)),
|
||||
|
||||
Override(DiscoveryHandlerKey, lp2p.DiscoveryHandler),
|
||||
Override(AddrsFactoryKey, lp2p.AddrsFactory(nil, nil)),
|
||||
Override(SmuxTransportKey, lp2p.SmuxTransport(true)),
|
||||
Override(RelayKey, lp2p.Relay(true, false)),
|
||||
Override(SecurityKey, lp2p.Security(true, false)),
|
||||
|
||||
Override(BaseRoutingKey, lp2p.BaseRouting),
|
||||
Override(new(routing.Routing), lp2p.Routing),
|
||||
|
||||
Override(NatPortMapKey, lp2p.NatPortMap),
|
||||
Override(ConnectionManagerKey, lp2p.ConnectionManager(50, 200, 20*time.Second)),
|
||||
|
||||
Override(PstoreAddSelfKeysKey, lp2p.PstoreAddSelfKeys),
|
||||
Override(StartListeningKey, lp2p.StartListening(defConf.Libp2p.ListenAddresses)),
|
||||
)
|
||||
}
|
||||
|
||||
func Config(cfg *config.Root) Option {
|
||||
return Options(
|
||||
func(s *settings) error { s.config = true; return nil },
|
||||
|
||||
applyIf(func(s *settings) bool { return s.online },
|
||||
Override(StartListeningKey, lp2p.StartListening(cfg.Libp2p.ListenAddresses)),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
// New builds and starts new Filecoin node
|
||||
func New(ctx context.Context, opts ...Option) (api.API, error) {
|
||||
var resAPI api.Struct
|
||||
settings := settings{
|
||||
modules: map[interface{}]fx.Option{},
|
||||
invokes: make([]fx.Option, _nInvokes),
|
||||
}
|
||||
|
||||
if err := Options(Options(defaults...), Options(opts...))(&settings); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctors := make([]fx.Option, 0, len(settings.modules))
|
||||
for _, opt := range settings.modules {
|
||||
ctors = append(ctors, opt)
|
||||
}
|
||||
|
||||
// fill holes in invokes
|
||||
for i, opt := range settings.invokes {
|
||||
if opt == nil {
|
||||
settings.invokes[i] = fx.Options()
|
||||
}
|
||||
}
|
||||
|
||||
app := fx.New(
|
||||
fx.Provide(as(ctx, new(helpers.MetricsCtx))),
|
||||
fx.Provide(func() (*config.Root, error) {
|
||||
return config.FromFile("./config.toml")
|
||||
}),
|
||||
|
||||
//fx.Provide(modules.RandomPeerID),
|
||||
randomIdentity(),
|
||||
memrepo(),
|
||||
|
||||
fx.Provide(modules.RecordValidator),
|
||||
|
||||
ifOpt(online,
|
||||
fx.Provide(
|
||||
pstoremem.NewPeerstore,
|
||||
|
||||
lp2p.DefaultTransports,
|
||||
lp2p.PNet,
|
||||
lp2p.Host,
|
||||
lp2p.RoutedHost,
|
||||
lp2p.DHTRouting(false),
|
||||
|
||||
lp2p.DiscoveryHandler,
|
||||
lp2p.AddrsFactory(nil, nil),
|
||||
lp2p.SmuxTransport(true),
|
||||
lp2p.Relay(true, false),
|
||||
lp2p.Security(true, false),
|
||||
|
||||
lp2p.BaseRouting,
|
||||
lp2p.Routing,
|
||||
|
||||
lp2p.NatPortMap,
|
||||
lp2p.ConnectionManager(50, 200, 20*time.Second),
|
||||
),
|
||||
|
||||
fx.Invoke(
|
||||
lp2p.PstoreAddSelfKeys,
|
||||
lp2p.StartListening,
|
||||
),
|
||||
),
|
||||
fx.Options(ctors...),
|
||||
fx.Options(settings.invokes...),
|
||||
|
||||
fx.Invoke(versionAPI(&resAPI.Internal.Version)),
|
||||
fx.Invoke(idAPI(&resAPI.Internal.ID)),
|
||||
@ -79,36 +156,19 @@ func New(ctx context.Context) (api.API, error) {
|
||||
|
||||
// In-memory / testing
|
||||
|
||||
func memrepo() fx.Option {
|
||||
return fx.Provide(
|
||||
func() datastore.Batching {
|
||||
return datastore.NewMapDatastore()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func randomIdentity() fx.Option {
|
||||
func randomIdentity() Option {
|
||||
sk, pk, err := ci.GenerateKeyPair(ci.RSA, 512)
|
||||
if err != nil {
|
||||
return fx.Error(err)
|
||||
return Error(err)
|
||||
}
|
||||
|
||||
return fx.Options(
|
||||
fx.Provide(as(sk, new(ci.PrivKey))),
|
||||
fx.Provide(as(pk, new(ci.PubKey))),
|
||||
fx.Provide(peer.IDFromPublicKey),
|
||||
return Options(
|
||||
Override(new(ci.PrivKey), sk),
|
||||
Override(new(ci.PubKey), pk),
|
||||
Override(new(peer.ID), peer.IDFromPublicKey),
|
||||
)
|
||||
}
|
||||
|
||||
// UTILS
|
||||
|
||||
func ifOpt(cond bool, options ...fx.Option) fx.Option {
|
||||
if cond {
|
||||
return fx.Options(options...)
|
||||
}
|
||||
return fx.Options()
|
||||
}
|
||||
|
||||
// API IMPL
|
||||
|
||||
// TODO: figure out a better way, this isn't usable in long term
|
||||
@ -129,56 +189,3 @@ func versionAPI(set *func(context.Context) (api.Version, error)) func() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// from go-ipfs
|
||||
// as casts input constructor to a given interface (if a value is given, it
|
||||
// wraps it into a constructor).
|
||||
//
|
||||
// Note: this method may look like a hack, and in fact it is one.
|
||||
// This is here only because https://github.com/uber-go/fx/issues/673 wasn't
|
||||
// released yet
|
||||
//
|
||||
// Note 2: when making changes here, make sure this method stays at
|
||||
// 100% coverage. This makes it less likely it will be terribly broken
|
||||
func as(in interface{}, as interface{}) interface{} {
|
||||
outType := reflect.TypeOf(as)
|
||||
|
||||
if outType.Kind() != reflect.Ptr {
|
||||
panic("outType is not a pointer")
|
||||
}
|
||||
|
||||
if reflect.TypeOf(in).Kind() != reflect.Func {
|
||||
ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false)
|
||||
|
||||
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
||||
out := reflect.New(outType.Elem())
|
||||
out.Elem().Set(reflect.ValueOf(in))
|
||||
|
||||
return []reflect.Value{out.Elem()}
|
||||
}).Interface()
|
||||
}
|
||||
|
||||
inType := reflect.TypeOf(in)
|
||||
|
||||
ins := make([]reflect.Type, inType.NumIn())
|
||||
outs := make([]reflect.Type, inType.NumOut())
|
||||
|
||||
for i := range ins {
|
||||
ins[i] = inType.In(i)
|
||||
}
|
||||
outs[0] = outType.Elem()
|
||||
for i := range outs[1:] {
|
||||
outs[i+1] = inType.Out(i + 1)
|
||||
}
|
||||
|
||||
ctype := reflect.FuncOf(ins, outs, false)
|
||||
|
||||
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
||||
outs := reflect.ValueOf(in).Call(args)
|
||||
out := reflect.New(outType.Elem())
|
||||
out.Elem().Set(outs[0])
|
||||
outs[0] = out.Elem()
|
||||
|
||||
return outs
|
||||
}).Interface()
|
||||
}
|
||||
|
@ -3,9 +3,8 @@ package lp2p
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/node/config"
|
||||
"github.com/libp2p/go-libp2p"
|
||||
host "github.com/libp2p/go-libp2p-core/host"
|
||||
"github.com/libp2p/go-libp2p-core/host"
|
||||
p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||||
mafilter "github.com/libp2p/go-maddr-filter"
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
@ -95,22 +94,24 @@ func listenAddresses(addresses []string) ([]ma.Multiaddr, error) {
|
||||
return listen, nil
|
||||
}
|
||||
|
||||
func StartListening(host host.Host, cfg *config.Root) error {
|
||||
listenAddrs, err := listenAddresses(cfg.Libp2p.ListenAddresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func StartListening(addresses []string) func(host host.Host) error {
|
||||
return func(host host.Host) error {
|
||||
listenAddrs, err := listenAddresses(addresses)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Actually start listening:
|
||||
if err := host.Network().Listen(listenAddrs...); err != nil {
|
||||
return err
|
||||
}
|
||||
// Actually start listening:
|
||||
if err := host.Network().Listen(listenAddrs...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// list out our addresses
|
||||
addrs, err := host.Network().InterfaceListenAddresses()
|
||||
if err != nil {
|
||||
return err
|
||||
// list out our addresses
|
||||
addrs, err := host.Network().InterfaceListenAddresses()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Swarm listening at: %s", addrs)
|
||||
return nil
|
||||
}
|
||||
log.Infof("Swarm listening at: %s", addrs)
|
||||
return nil
|
||||
}
|
||||
|
106
node/options.go
Normal file
106
node/options.go
Normal file
@ -0,0 +1,106 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"go.uber.org/fx"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Option func(*settings) error
|
||||
|
||||
func Override(typ, constructor interface{}) Option {
|
||||
return func(s *settings) error {
|
||||
if i, ok := typ.(invoke); ok {
|
||||
s.invokes[i] = fx.Invoke(constructor)
|
||||
return nil
|
||||
}
|
||||
|
||||
if c, ok := typ.(special); ok {
|
||||
s.modules[c] = fx.Provide(constructor)
|
||||
return nil
|
||||
}
|
||||
ctor := as(constructor, typ)
|
||||
rt := reflect.TypeOf(typ).Elem()
|
||||
|
||||
s.modules[rt] = fx.Provide(ctor)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Options(opts ...Option) Option {
|
||||
return func(s *settings) error {
|
||||
for _, opt := range opts {
|
||||
if err := opt(s); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Error(err error) Option {
|
||||
return func(_ *settings) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func applyIf(check func(s *settings) bool, opts ...Option) Option {
|
||||
return func(s *settings) error {
|
||||
if check(s) {
|
||||
return Options(opts...)(s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// from go-ipfs
|
||||
// as casts input constructor to a given interface (if a value is given, it
|
||||
// wraps it into a constructor).
|
||||
//
|
||||
// Note: this method may look like a hack, and in fact it is one.
|
||||
// This is here only because https://github.com/uber-go/fx/issues/673 wasn't
|
||||
// released yet
|
||||
//
|
||||
// Note 2: when making changes here, make sure this method stays at
|
||||
// 100% coverage. This makes it less likely it will be terribly broken
|
||||
func as(in interface{}, as interface{}) interface{} {
|
||||
outType := reflect.TypeOf(as)
|
||||
|
||||
if outType.Kind() != reflect.Ptr {
|
||||
panic("outType is not a pointer")
|
||||
}
|
||||
|
||||
if reflect.TypeOf(in).Kind() != reflect.Func {
|
||||
ctype := reflect.FuncOf(nil, []reflect.Type{outType.Elem()}, false)
|
||||
|
||||
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
||||
out := reflect.New(outType.Elem())
|
||||
out.Elem().Set(reflect.ValueOf(in))
|
||||
|
||||
return []reflect.Value{out.Elem()}
|
||||
}).Interface()
|
||||
}
|
||||
|
||||
inType := reflect.TypeOf(in)
|
||||
|
||||
ins := make([]reflect.Type, inType.NumIn())
|
||||
outs := make([]reflect.Type, inType.NumOut())
|
||||
|
||||
for i := range ins {
|
||||
ins[i] = inType.In(i)
|
||||
}
|
||||
outs[0] = outType.Elem()
|
||||
for i := range outs[1:] {
|
||||
outs[i+1] = inType.Out(i + 1)
|
||||
}
|
||||
|
||||
ctype := reflect.FuncOf(ins, outs, false)
|
||||
|
||||
return reflect.MakeFunc(ctype, func(args []reflect.Value) (results []reflect.Value) {
|
||||
outs := reflect.ValueOf(in).Call(args)
|
||||
out := reflect.New(outType.Elem())
|
||||
out.Elem().Set(outs[0])
|
||||
outs[0] = out.Elem()
|
||||
|
||||
return outs
|
||||
}).Interface()
|
||||
}
|
Loading…
Reference in New Issue
Block a user