Add support for different configs
License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
413314b44b
commit
3ea0997c93
@ -75,7 +75,7 @@ func (m mybs) Get(c cid.Cid) (block.Block, error) {
|
|||||||
|
|
||||||
func NewGenerator() (*ChainGen, error) {
|
func NewGenerator() (*ChainGen, error) {
|
||||||
mr := repo.NewMemory(nil)
|
mr := repo.NewMemory(nil)
|
||||||
lr, err := mr.Lock()
|
lr, err := mr.Lock(repo.RepoStorageMiner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("taking mem-repo lock failed: %w", err)
|
return nil, xerrors.Errorf("taking mem-repo lock failed: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ var initCmd = &cli.Command{
|
|||||||
|
|
||||||
log.Info("Initializing repo")
|
log.Info("Initializing repo")
|
||||||
|
|
||||||
if err := r.Init(); err != nil {
|
if err := r.Init(repo.RepoStorageMiner); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ var initCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode, r repo.Repo) error {
|
func storageMinerInit(ctx context.Context, cctx *cli.Context, api api.FullNode, r repo.Repo) error {
|
||||||
lr, err := r.Lock()
|
lr, err := r.Lock(repo.RepoStorageMiner)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,10 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"github.com/filecoin-project/lotus/peermgr"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/peermgr"
|
||||||
|
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"gopkg.in/urfave/cli.v2"
|
"gopkg.in/urfave/cli.v2"
|
||||||
@ -53,7 +54,7 @@ var DaemonCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.Init(); err != nil && err != repo.ErrRepoExists {
|
if err := r.Init(repo.RepoFullNode); err != nil && err != repo.ErrRepoExists {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||||
record "github.com/libp2p/go-libp2p-record"
|
record "github.com/libp2p/go-libp2p-record"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/chain"
|
"github.com/filecoin-project/lotus/chain"
|
||||||
@ -100,11 +101,6 @@ const (
|
|||||||
_nInvokes // keep this last
|
_nInvokes // keep this last
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
|
||||||
nodeFull = iota
|
|
||||||
nodeStorageMiner
|
|
||||||
)
|
|
||||||
|
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
// modules is a map of constructors for DI
|
// modules is a map of constructors for DI
|
||||||
//
|
//
|
||||||
@ -117,14 +113,12 @@ type Settings struct {
|
|||||||
// type, and must be applied in correct order
|
// type, and must be applied in correct order
|
||||||
invokes []fx.Option
|
invokes []fx.Option
|
||||||
|
|
||||||
nodeType int
|
nodeType repo.RepoType
|
||||||
|
|
||||||
Online bool // Online option applied
|
Online bool // Online option applied
|
||||||
Config bool // Config option applied
|
Config bool // Config option applied
|
||||||
}
|
}
|
||||||
|
|
||||||
var defConf = config.Default()
|
|
||||||
|
|
||||||
func defaults() []Option {
|
func defaults() []Option {
|
||||||
return []Option{
|
return []Option{
|
||||||
Override(new(helpers.MetricsCtx), context.Background),
|
Override(new(helpers.MetricsCtx), context.Background),
|
||||||
@ -161,10 +155,14 @@ func libp2p() Option {
|
|||||||
Override(new(*pubsub.PubSub), lp2p.GossipSub()),
|
Override(new(*pubsub.PubSub), lp2p.GossipSub()),
|
||||||
|
|
||||||
Override(PstoreAddSelfKeysKey, lp2p.PstoreAddSelfKeys),
|
Override(PstoreAddSelfKeysKey, lp2p.PstoreAddSelfKeys),
|
||||||
Override(StartListeningKey, lp2p.StartListening(defConf.Libp2p.ListenAddresses)),
|
Override(StartListeningKey, lp2p.StartListening(config.DefaultFullNode().Libp2p.ListenAddresses)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isType(t repo.RepoType) func(s *Settings) bool {
|
||||||
|
return func(s *Settings) bool { return s.nodeType == t }
|
||||||
|
}
|
||||||
|
|
||||||
// Online sets up basic libp2p node
|
// Online sets up basic libp2p node
|
||||||
func Online() Option {
|
func Online() Option {
|
||||||
return Options(
|
return Options(
|
||||||
@ -181,7 +179,7 @@ func Online() Option {
|
|||||||
|
|
||||||
// Full node
|
// Full node
|
||||||
|
|
||||||
ApplyIf(func(s *Settings) bool { return s.nodeType == nodeFull },
|
ApplyIf(isType(repo.RepoFullNode),
|
||||||
// TODO: Fix offline mode
|
// TODO: Fix offline mode
|
||||||
|
|
||||||
Override(new(dtypes.BootstrapPeers), modules.BuiltinBootstrap),
|
Override(new(dtypes.BootstrapPeers), modules.BuiltinBootstrap),
|
||||||
@ -230,7 +228,7 @@ func Online() Option {
|
|||||||
),
|
),
|
||||||
|
|
||||||
// Storage miner
|
// Storage miner
|
||||||
ApplyIf(func(s *Settings) bool { return s.nodeType == nodeStorageMiner },
|
ApplyIf(func(s *Settings) bool { return s.nodeType == repo.RepoStorageMiner },
|
||||||
Override(new(*sectorbuilder.SectorBuilder), sectorbuilder.New),
|
Override(new(*sectorbuilder.SectorBuilder), sectorbuilder.New),
|
||||||
Override(new(*sector.Store), sector.NewStore),
|
Override(new(*sector.Store), sector.NewStore),
|
||||||
Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks),
|
Override(new(*sectorblocks.SectorBlocks), sectorblocks.NewSectorBlocks),
|
||||||
@ -260,7 +258,7 @@ func StorageMiner(out *api.StorageMiner) Option {
|
|||||||
),
|
),
|
||||||
|
|
||||||
func(s *Settings) error {
|
func(s *Settings) error {
|
||||||
s.nodeType = nodeStorageMiner
|
s.nodeType = repo.RepoStorageMiner
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -274,7 +272,7 @@ func StorageMiner(out *api.StorageMiner) Option {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Config sets up constructors based on the provided Config
|
// Config sets up constructors based on the provided Config
|
||||||
func Config(cfg *config.Root) Option {
|
func ConfigCommon(cfg *config.Common) Option {
|
||||||
return Options(
|
return Options(
|
||||||
func(s *Settings) error { s.Config = true; return nil },
|
func(s *Settings) error { s.Config = true; return nil },
|
||||||
|
|
||||||
@ -284,27 +282,64 @@ func Config(cfg *config.Root) Option {
|
|||||||
ApplyIf(func(s *Settings) bool { return len(cfg.Libp2p.BootstrapPeers) > 0 },
|
ApplyIf(func(s *Settings) bool { return len(cfg.Libp2p.BootstrapPeers) > 0 },
|
||||||
Override(new(dtypes.BootstrapPeers), modules.ConfigBootstrap(cfg.Libp2p.BootstrapPeers)),
|
Override(new(dtypes.BootstrapPeers), modules.ConfigBootstrap(cfg.Libp2p.BootstrapPeers)),
|
||||||
),
|
),
|
||||||
|
|
||||||
ApplyIf(func(s *Settings) bool { return s.nodeType == nodeFull },
|
|
||||||
Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Repo(r repo.Repo) Option {
|
func ConfigFullNode(cfg *config.FullNode) Option {
|
||||||
lr, err := r.Lock()
|
//ApplyIf(func(s *Settings) bool { return s.nodeType == repo.RepoFullNode }),
|
||||||
|
return Options(
|
||||||
|
ConfigCommon(&cfg.Common),
|
||||||
|
Override(HeadMetricsKey, metrics.SendHeadNotifs(cfg.Metrics.Nickname)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func repoFull(r repo.Repo) Option {
|
||||||
|
lr, err := r.Lock(repo.RepoFullNode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Error(err)
|
return Error(err)
|
||||||
}
|
}
|
||||||
cfg, err := lr.Config()
|
c, err := lr.Config()
|
||||||
|
if err != nil {
|
||||||
|
return Error(err)
|
||||||
|
}
|
||||||
|
cfg, ok := c.(*config.FullNode)
|
||||||
|
if !ok {
|
||||||
|
return Error(xerrors.Errorf("invalid config from repo, got: %T", c))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Options(
|
||||||
|
ConfigFullNode(cfg),
|
||||||
|
Override(new(repo.LockedRepo), modules.LockedRepo(lr)), // module handles closing
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func repoMiner(r repo.Repo) Option {
|
||||||
|
lr, err := r.Lock(repo.RepoStorageMiner)
|
||||||
|
if err != nil {
|
||||||
|
return Error(err)
|
||||||
|
}
|
||||||
|
c, err := lr.Config()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Error(err)
|
return Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cfg, ok := c.(*config.StorageMiner)
|
||||||
|
if !ok {
|
||||||
|
return Error(xerrors.Errorf("invalid config from repo, got: %T", c))
|
||||||
|
}
|
||||||
|
|
||||||
return Options(
|
return Options(
|
||||||
Config(cfg),
|
ConfigCommon(&cfg.Common),
|
||||||
Override(new(repo.LockedRepo), modules.LockedRepo(lr)), // module handles closing
|
Override(new(repo.LockedRepo), modules.LockedRepo(lr)), // module handles closing
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Repo(r repo.Repo) Option {
|
||||||
|
|
||||||
|
return Options(
|
||||||
|
ApplyIf(isType(repo.RepoFullNode), repoFull(r)),
|
||||||
|
ApplyIf(isType(repo.RepoStorageMiner), repoMiner(r)),
|
||||||
|
|
||||||
Override(new(dtypes.MetadataDS), modules.Datastore),
|
Override(new(dtypes.MetadataDS), modules.Datastore),
|
||||||
Override(new(dtypes.ChainBlockstore), modules.ChainBlockstore),
|
Override(new(dtypes.ChainBlockstore), modules.ChainBlockstore),
|
||||||
@ -337,8 +372,9 @@ type StopFunc func(context.Context) error
|
|||||||
// New builds and starts new Filecoin node
|
// New builds and starts new Filecoin node
|
||||||
func New(ctx context.Context, opts ...Option) (StopFunc, error) {
|
func New(ctx context.Context, opts ...Option) (StopFunc, error) {
|
||||||
settings := Settings{
|
settings := Settings{
|
||||||
modules: map[interface{}]fx.Option{},
|
modules: map[interface{}]fx.Option{},
|
||||||
invokes: make([]fx.Option, _nInvokes),
|
invokes: make([]fx.Option, _nInvokes),
|
||||||
|
nodeType: repo.RepoFullNode,
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply module options in the right order
|
// apply module options in the right order
|
||||||
|
@ -1,15 +1,27 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"encoding"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// Root is starting point of the config
|
// Common is common config between full node and miner
|
||||||
type Root struct {
|
type Common struct {
|
||||||
API API
|
API API
|
||||||
Libp2p Libp2p
|
Libp2p Libp2p
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullNode is a full node config
|
||||||
|
type FullNode struct {
|
||||||
|
Common
|
||||||
Metrics Metrics
|
Metrics Metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StorageMiner is a storage miner config
|
||||||
|
type StorageMiner struct {
|
||||||
|
Common
|
||||||
|
}
|
||||||
|
|
||||||
// API contains configs for API endpoint
|
// API contains configs for API endpoint
|
||||||
type API struct {
|
type API struct {
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
@ -26,9 +38,8 @@ type Metrics struct {
|
|||||||
Nickname string
|
Nickname string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default returns the default config
|
func defCommon() Common {
|
||||||
func Default() *Root {
|
return Common{
|
||||||
def := Root{
|
|
||||||
API: API{
|
API: API{
|
||||||
ListenAddress: "/ip6/::1/tcp/1234/http",
|
ListenAddress: "/ip6/::1/tcp/1234/http",
|
||||||
Timeout: Duration(30 * time.Second),
|
Timeout: Duration(30 * time.Second),
|
||||||
@ -40,10 +51,27 @@ func Default() *Root {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return &def
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duration is a wrapper type for time.Duration for decoding it from TOML
|
// Default returns the default config
|
||||||
|
func DefaultFullNode() *FullNode {
|
||||||
|
return &FullNode{
|
||||||
|
Common: defCommon(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultStorageMiner() *StorageMiner {
|
||||||
|
return &StorageMiner{
|
||||||
|
Common: defCommon(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ encoding.TextMarshaler = (*Duration)(nil)
|
||||||
|
var _ encoding.TextUnmarshaler = (*Duration)(nil)
|
||||||
|
|
||||||
|
// Duration is a wrapper type for time.Duration
|
||||||
|
// for decoding and encoding from/to TOML
|
||||||
type Duration time.Duration
|
type Duration time.Duration
|
||||||
|
|
||||||
// UnmarshalText implements interface for TOML decoding
|
// UnmarshalText implements interface for TOML decoding
|
||||||
@ -55,3 +83,8 @@ func (dur *Duration) UnmarshalText(text []byte) error {
|
|||||||
*dur = Duration(d)
|
*dur = Duration(d)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (dur Duration) MarshalText() ([]byte, error) {
|
||||||
|
d := time.Duration(dur)
|
||||||
|
return []byte(d.String()), nil
|
||||||
|
}
|
||||||
|
@ -1,30 +1,32 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/BurntSushi/toml"
|
"github.com/BurntSushi/toml"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FromFile loads config from a specified file overriding defaults specified in
|
// FromFile loads config from a specified file overriding defaults specified in
|
||||||
// the source code. If file does not exist or is empty defaults are asummed.
|
// the def parameter. If file does not exist or is empty defaults are asummed.
|
||||||
func FromFile(path string) (*Root, error) {
|
func FromFile(path string, def interface{}) (interface{}, error) {
|
||||||
file, err := os.Open(path)
|
file, err := os.Open(path)
|
||||||
switch {
|
switch {
|
||||||
case os.IsNotExist(err):
|
case os.IsNotExist(err):
|
||||||
return Default(), nil
|
return def, nil
|
||||||
case err != nil:
|
case err != nil:
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer file.Close() //nolint:errcheck // The file is RO
|
defer file.Close() //nolint:errcheck // The file is RO
|
||||||
return FromReader(file)
|
return FromReader(file, def)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromReader loads config from a reader instance.
|
// FromReader loads config from a reader instance.
|
||||||
func FromReader(reader io.Reader) (*Root, error) {
|
func FromReader(reader io.Reader, def interface{}) (interface{}, error) {
|
||||||
cfg := Default()
|
cfg := def
|
||||||
_, err := toml.DecodeReader(reader, cfg)
|
_, err := toml.DecodeReader(reader, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -32,3 +34,16 @@ func FromReader(reader io.Reader) (*Root, error) {
|
|||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ConfigComment(t interface{}) ([]byte, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
_, _ = buf.WriteString("# Default config:\n")
|
||||||
|
e := toml.NewEncoder(buf)
|
||||||
|
if err := e.Encode(t); err != nil {
|
||||||
|
return nil, xerrors.Errorf("encoding config: %w", err)
|
||||||
|
}
|
||||||
|
b := buf.Bytes()
|
||||||
|
b = bytes.ReplaceAll(b, []byte("\n"), []byte("\n#"))
|
||||||
|
return b, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -14,16 +14,16 @@ func TestDecodeNothing(t *testing.T) {
|
|||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
{
|
{
|
||||||
cfg, err := FromFile(os.DevNull)
|
cfg, err := FromFile(os.DevNull, DefaultFullNode())
|
||||||
assert.Nil(err, "error should be nil")
|
assert.Nil(err, "error should be nil")
|
||||||
assert.Equal(Default(), cfg,
|
assert.Equal(DefaultFullNode(), cfg,
|
||||||
"config from empty file should be the same as default")
|
"config from empty file should be the same as default")
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
cfg, err := FromFile("./does-not-exist.toml")
|
cfg, err := FromFile("./does-not-exist.toml", DefaultFullNode())
|
||||||
assert.Nil(err, "error should be nil")
|
assert.Nil(err, "error should be nil")
|
||||||
assert.Equal(Default(), cfg,
|
assert.Equal(DefaultFullNode(), cfg,
|
||||||
"config from not exisiting file should be the same as default")
|
"config from not exisiting file should be the same as default")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,11 +34,11 @@ func TestParitalConfig(t *testing.T) {
|
|||||||
[API]
|
[API]
|
||||||
Timeout = "10s"
|
Timeout = "10s"
|
||||||
`
|
`
|
||||||
expected := Default()
|
expected := DefaultFullNode()
|
||||||
expected.API.Timeout = Duration(10 * time.Second)
|
expected.API.Timeout = Duration(10 * time.Second)
|
||||||
|
|
||||||
{
|
{
|
||||||
cfg, err := FromReader(bytes.NewReader([]byte(cfgString)))
|
cfg, err := FromReader(bytes.NewReader([]byte(cfgString)), DefaultFullNode())
|
||||||
assert.NoError(err, "error should be nil")
|
assert.NoError(err, "error should be nil")
|
||||||
assert.Equal(expected, cfg,
|
assert.Equal(expected, cfg,
|
||||||
"config from reader should contain changes")
|
"config from reader should contain changes")
|
||||||
@ -55,7 +55,7 @@ func TestParitalConfig(t *testing.T) {
|
|||||||
assert.NoError(err, "closing tmp file should not error")
|
assert.NoError(err, "closing tmp file should not error")
|
||||||
defer os.Remove(fname) //nolint:errcheck
|
defer os.Remove(fname) //nolint:errcheck
|
||||||
|
|
||||||
cfg, err := FromFile(fname)
|
cfg, err := FromFile(fname, DefaultFullNode())
|
||||||
assert.Nil(err, "error should be nil")
|
assert.Nil(err, "error should be nil")
|
||||||
assert.Equal(expected, cfg,
|
assert.Equal(expected, cfg,
|
||||||
"config from reader should contain changes")
|
"config from reader should contain changes")
|
||||||
|
@ -34,7 +34,7 @@ import (
|
|||||||
func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, tnd test.TestNode) test.TestStorageNode {
|
func testStorageNode(ctx context.Context, t *testing.T, waddr address.Address, act address.Address, tnd test.TestNode) test.TestStorageNode {
|
||||||
r := repo.NewMemory(nil)
|
r := repo.NewMemory(nil)
|
||||||
|
|
||||||
lr, err := r.Lock()
|
lr, err := r.Lock(repo.RepoStorageMiner)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||||
|
@ -2,6 +2,7 @@ package repo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -33,13 +34,33 @@ const (
|
|||||||
fsKeystore = "keystore"
|
fsKeystore = "keystore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type RepoType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
_ = iota // Default is invalid
|
||||||
|
RepoFullNode RepoType = iota
|
||||||
|
RepoStorageMiner
|
||||||
|
)
|
||||||
|
|
||||||
|
func defConfForType(t RepoType) interface{} {
|
||||||
|
switch t {
|
||||||
|
case RepoFullNode:
|
||||||
|
return config.DefaultFullNode()
|
||||||
|
case RepoStorageMiner:
|
||||||
|
return config.DefaultStorageMiner()
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unknown RepoType(%d)", int(t)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var log = logging.Logger("repo")
|
var log = logging.Logger("repo")
|
||||||
|
|
||||||
var ErrRepoExists = xerrors.New("repo exists")
|
var ErrRepoExists = xerrors.New("repo exists")
|
||||||
|
|
||||||
// FsRepo is struct for repo, use NewFS to create
|
// FsRepo is struct for repo, use NewFS to create
|
||||||
type FsRepo struct {
|
type FsRepo struct {
|
||||||
path string
|
path string
|
||||||
|
repoType RepoType
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ Repo = &FsRepo{}
|
var _ Repo = &FsRepo{}
|
||||||
@ -65,7 +86,7 @@ func (fsr *FsRepo) Exists() (bool, error) {
|
|||||||
return !notexist, err
|
return !notexist, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsr *FsRepo) Init() error {
|
func (fsr *FsRepo) Init(t RepoType) error {
|
||||||
exist, err := fsr.Exists()
|
exist, err := fsr.Exists()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -79,18 +100,36 @@ func (fsr *FsRepo) Init() error {
|
|||||||
if err != nil && !os.IsExist(err) {
|
if err != nil && !os.IsExist(err) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c, err := os.Create(filepath.Join(fsr.path, fsConfig))
|
|
||||||
if err != nil {
|
if err := fsr.initConfig(t); err != nil {
|
||||||
return err
|
return xerrors.Errorf("init config: %w", err)
|
||||||
}
|
|
||||||
if err := c.Close(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return fsr.initKeystore()
|
return fsr.initKeystore()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fsr *FsRepo) initConfig(t RepoType) error {
|
||||||
|
c, err := os.Create(filepath.Join(fsr.path, fsConfig))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
comm, err := config.ConfigComment(defConfForType(t))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("comment: %w", err)
|
||||||
|
}
|
||||||
|
_, err = c.Write(comm)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("write config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.Close(); err != nil {
|
||||||
|
return xerrors.Errorf("close config: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (fsr *FsRepo) initKeystore() error {
|
func (fsr *FsRepo) initKeystore() error {
|
||||||
kstorePath := filepath.Join(fsr.path, fsKeystore)
|
kstorePath := filepath.Join(fsr.path, fsKeystore)
|
||||||
if _, err := os.Stat(kstorePath); err == nil {
|
if _, err := os.Stat(kstorePath); err == nil {
|
||||||
@ -142,7 +181,7 @@ func (fsr *FsRepo) APIToken() ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Lock acquires exclusive lock on this repo
|
// Lock acquires exclusive lock on this repo
|
||||||
func (fsr *FsRepo) Lock() (LockedRepo, error) {
|
func (fsr *FsRepo) Lock(repoType RepoType) (LockedRepo, error) {
|
||||||
locked, err := fslock.Locked(fsr.path, fsLock)
|
locked, err := fslock.Locked(fsr.path, fsLock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("could not check lock status: %w", err)
|
return nil, xerrors.Errorf("could not check lock status: %w", err)
|
||||||
@ -156,14 +195,16 @@ func (fsr *FsRepo) Lock() (LockedRepo, error) {
|
|||||||
return nil, xerrors.Errorf("could not lock the repo: %w", err)
|
return nil, xerrors.Errorf("could not lock the repo: %w", err)
|
||||||
}
|
}
|
||||||
return &fsLockedRepo{
|
return &fsLockedRepo{
|
||||||
path: fsr.path,
|
path: fsr.path,
|
||||||
closer: closer,
|
repoType: repoType,
|
||||||
|
closer: closer,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type fsLockedRepo struct {
|
type fsLockedRepo struct {
|
||||||
path string
|
path string
|
||||||
closer io.Closer
|
repoType RepoType
|
||||||
|
closer io.Closer
|
||||||
|
|
||||||
ds datastore.Batching
|
ds datastore.Batching
|
||||||
dsErr error
|
dsErr error
|
||||||
@ -219,11 +260,11 @@ func (fsr *fsLockedRepo) Datastore(ns string) (datastore.Batching, error) {
|
|||||||
return namespace.Wrap(fsr.ds, datastore.NewKey(ns)), nil
|
return namespace.Wrap(fsr.ds, datastore.NewKey(ns)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsr *fsLockedRepo) Config() (*config.Root, error) {
|
func (fsr *fsLockedRepo) Config() (interface{}, error) {
|
||||||
if err := fsr.stillValid(); err != nil {
|
if err := fsr.stillValid(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return config.FromFile(fsr.join(fsConfig))
|
return config.FromFile(fsr.join(fsConfig), defConfForType(fsr.repoType))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fsr *fsLockedRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {
|
func (fsr *fsLockedRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {
|
||||||
|
@ -17,7 +17,7 @@ func genFsRepo(t *testing.T) (*FsRepo, func()) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = repo.Init()
|
err = repo.Init(RepoFullNode)
|
||||||
if err != ErrRepoExists && err != nil {
|
if err != ErrRepoExists && err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -25,7 +24,7 @@ type Repo interface {
|
|||||||
APIToken() ([]byte, error)
|
APIToken() ([]byte, error)
|
||||||
|
|
||||||
// Lock locks the repo for exclusive use.
|
// Lock locks the repo for exclusive use.
|
||||||
Lock() (LockedRepo, error)
|
Lock(RepoType) (LockedRepo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type LockedRepo interface {
|
type LockedRepo interface {
|
||||||
@ -36,7 +35,7 @@ type LockedRepo interface {
|
|||||||
Datastore(namespace string) (datastore.Batching, error)
|
Datastore(namespace string) (datastore.Batching, error)
|
||||||
|
|
||||||
// Returns config in this repo
|
// Returns config in this repo
|
||||||
Config() (*config.Root, error)
|
Config() (interface{}, error)
|
||||||
|
|
||||||
// SetAPIEndpoint sets the endpoint of the current API
|
// SetAPIEndpoint sets the endpoint of the current API
|
||||||
// so it can be read by API clients
|
// so it can be read by API clients
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/node/config"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type MemRepo struct {
|
type MemRepo struct {
|
||||||
@ -24,12 +23,13 @@ type MemRepo struct {
|
|||||||
token *byte
|
token *byte
|
||||||
|
|
||||||
datastore datastore.Datastore
|
datastore datastore.Datastore
|
||||||
configF func() *config.Root
|
configF func(t RepoType) interface{}
|
||||||
keystore map[string]types.KeyInfo
|
keystore map[string]types.KeyInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
type lockedMemRepo struct {
|
type lockedMemRepo struct {
|
||||||
mem *MemRepo
|
mem *MemRepo
|
||||||
|
t RepoType
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
|
|
||||||
token *byte
|
token *byte
|
||||||
@ -44,7 +44,7 @@ var _ Repo = &MemRepo{}
|
|||||||
// MemRepoOptions contains options for memory repo
|
// MemRepoOptions contains options for memory repo
|
||||||
type MemRepoOptions struct {
|
type MemRepoOptions struct {
|
||||||
Ds datastore.Datastore
|
Ds datastore.Datastore
|
||||||
ConfigF func() *config.Root
|
ConfigF func(RepoType) interface{}
|
||||||
KeyStore map[string]types.KeyInfo
|
KeyStore map[string]types.KeyInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ func NewMemory(opts *MemRepoOptions) *MemRepo {
|
|||||||
opts = &MemRepoOptions{}
|
opts = &MemRepoOptions{}
|
||||||
}
|
}
|
||||||
if opts.ConfigF == nil {
|
if opts.ConfigF == nil {
|
||||||
opts.ConfigF = config.Default
|
opts.ConfigF = defConfForType
|
||||||
}
|
}
|
||||||
if opts.Ds == nil {
|
if opts.Ds == nil {
|
||||||
opts.Ds = dssync.MutexWrap(datastore.NewMapDatastore())
|
opts.Ds = dssync.MutexWrap(datastore.NewMapDatastore())
|
||||||
@ -92,7 +92,7 @@ func (mem *MemRepo) APIToken() ([]byte, error) {
|
|||||||
return mem.api.token, nil
|
return mem.api.token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mem *MemRepo) Lock() (LockedRepo, error) {
|
func (mem *MemRepo) Lock(t RepoType) (LockedRepo, error) {
|
||||||
select {
|
select {
|
||||||
case mem.repoLock <- struct{}{}:
|
case mem.repoLock <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
@ -102,6 +102,7 @@ func (mem *MemRepo) Lock() (LockedRepo, error) {
|
|||||||
|
|
||||||
return &lockedMemRepo{
|
return &lockedMemRepo{
|
||||||
mem: mem,
|
mem: mem,
|
||||||
|
t: t,
|
||||||
token: mem.token,
|
token: mem.token,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@ -143,11 +144,11 @@ func (lmem *lockedMemRepo) Datastore(ns string) (datastore.Batching, error) {
|
|||||||
return namespace.Wrap(lmem.mem.datastore, datastore.NewKey(ns)), nil
|
return namespace.Wrap(lmem.mem.datastore, datastore.NewKey(ns)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lmem *lockedMemRepo) Config() (*config.Root, error) {
|
func (lmem *lockedMemRepo) Config() (interface{}, error) {
|
||||||
if err := lmem.checkToken(); err != nil {
|
if err := lmem.checkToken(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return lmem.mem.configF(), nil
|
return lmem.mem.configF(lmem.t), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (lmem *lockedMemRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {
|
func (lmem *lockedMemRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {
|
||||||
|
@ -18,12 +18,12 @@ func basicTest(t *testing.T, repo Repo) {
|
|||||||
}
|
}
|
||||||
assert.Nil(t, apima, "with no api endpoint, return should be nil")
|
assert.Nil(t, apima, "with no api endpoint, return should be nil")
|
||||||
|
|
||||||
lrepo, err := repo.Lock()
|
lrepo, err := repo.Lock(RepoFullNode)
|
||||||
assert.NoError(t, err, "should be able to lock once")
|
assert.NoError(t, err, "should be able to lock once")
|
||||||
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
||||||
|
|
||||||
{
|
{
|
||||||
lrepo2, err := repo.Lock()
|
lrepo2, err := repo.Lock(RepoFullNode)
|
||||||
if assert.Error(t, err) {
|
if assert.Error(t, err) {
|
||||||
assert.Equal(t, ErrRepoAlreadyLocked, err)
|
assert.Equal(t, ErrRepoAlreadyLocked, err)
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ func basicTest(t *testing.T, repo Repo) {
|
|||||||
err = lrepo.Close()
|
err = lrepo.Close()
|
||||||
assert.NoError(t, err, "should be able to unlock")
|
assert.NoError(t, err, "should be able to unlock")
|
||||||
|
|
||||||
lrepo, err = repo.Lock()
|
lrepo, err = repo.Lock(RepoFullNode)
|
||||||
assert.NoError(t, err, "should be able to relock")
|
assert.NoError(t, err, "should be able to relock")
|
||||||
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ func basicTest(t *testing.T, repo Repo) {
|
|||||||
assert.Equal(t, ma, apima, "returned API multiaddr should be the same")
|
assert.Equal(t, ma, apima, "returned API multiaddr should be the same")
|
||||||
|
|
||||||
cfg, err := lrepo.Config()
|
cfg, err := lrepo.Config()
|
||||||
assert.Equal(t, config.Default(), cfg, "there should be a default config")
|
assert.Equal(t, config.DefaultFullNode(), cfg, "there should be a default config")
|
||||||
assert.NoError(t, err, "config should not error")
|
assert.NoError(t, err, "config should not error")
|
||||||
|
|
||||||
err = lrepo.Close()
|
err = lrepo.Close()
|
||||||
@ -64,7 +64,7 @@ func basicTest(t *testing.T, repo Repo) {
|
|||||||
k1 := types.KeyInfo{Type: "foo"}
|
k1 := types.KeyInfo{Type: "foo"}
|
||||||
k2 := types.KeyInfo{Type: "bar"}
|
k2 := types.KeyInfo{Type: "bar"}
|
||||||
|
|
||||||
lrepo, err = repo.Lock()
|
lrepo, err = repo.Lock(RepoFullNode)
|
||||||
assert.NoError(t, err, "should be able to relock")
|
assert.NoError(t, err, "should be able to relock")
|
||||||
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
assert.NotNil(t, lrepo, "locked repo shouldn't be nil")
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user