Introduce fsrepo
License: MIT Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-datastore"
|
||||
badger "github.com/ipfs/go-ds-badger"
|
||||
fslock "github.com/ipfs/go-fs-lock"
|
||||
"github.com/libp2p/go-libp2p-core/crypto"
|
||||
"github.com/multiformats/go-multiaddr"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-lotus/node/config"
|
||||
)
|
||||
|
||||
const (
|
||||
fsAPI = "api"
|
||||
fsConfig = "config.toml"
|
||||
fsDatastore = "datastore"
|
||||
fsLibp2pKey = "libp2p.priv"
|
||||
fsLock = "repo.lock"
|
||||
)
|
||||
|
||||
type FsRepo struct {
|
||||
path string
|
||||
}
|
||||
|
||||
var _ Repo = &FsRepo{}
|
||||
|
||||
func (fsr *FsRepo) APIEndpoint() (multiaddr.Multiaddr, error) {
|
||||
p := filepath.Join(fsr.path, fsAPI)
|
||||
f, err := os.Open(p)
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
return nil, ErrNoAPIEndpoint
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close() //nolint: errcheck // Read only op
|
||||
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
strma := string(data)
|
||||
strma = strings.TrimSpace(strma)
|
||||
|
||||
apima, err := multiaddr.NewMultiaddr(strma)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return apima, nil
|
||||
}
|
||||
|
||||
func (fsr *FsRepo) Lock() (LockedRepo, error) {
|
||||
closer, err := fslock.Lock(fsr.path, fsLock)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not lock the repo: %w", err)
|
||||
}
|
||||
return &fsLockedRepo{
|
||||
path: fsr.path,
|
||||
closer: closer,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type fsLockedRepo struct {
|
||||
path string
|
||||
closer io.Closer
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) Close() error {
|
||||
err := fsr.closer.Close()
|
||||
fsr.closer = nil
|
||||
return err
|
||||
}
|
||||
|
||||
// join joins path elements with fsr.path
|
||||
func (fsr *fsLockedRepo) join(paths ...string) string {
|
||||
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) stillValid() error {
|
||||
if fsr.closer == nil {
|
||||
return ErrClosedRepo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) Datastore() (datastore.Datastore, error) {
|
||||
return badger.NewDatastore(fsr.join(fsDatastore), nil)
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) Config() (*config.Root, error) {
|
||||
if err := fsr.stillValid(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return config.FromFile(fsr.join(fsConfig))
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) Libp2pIdentity() (crypto.PrivKey, error) {
|
||||
kpath := fsr.join(fsLibp2pKey)
|
||||
stat, err := os.Stat(kpath)
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
pk, err := genLibp2pKey()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not generate private key: %w", err)
|
||||
}
|
||||
pkb, err := pk.Bytes()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not serialize private key: %w", err)
|
||||
}
|
||||
err = ioutil.WriteFile(kpath, pkb, 0600)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not write private key: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if stat.Mode()&0066 != 0 {
|
||||
return nil, xerrors.New("libp2p identity has too wide access permissions, " +
|
||||
fsLibp2pKey + " should have permission 0600")
|
||||
}
|
||||
|
||||
f, err := os.Open(kpath)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not open private key file: %w", err)
|
||||
}
|
||||
defer f.Close() //nolint: errcheck // read-only op
|
||||
|
||||
pkbytes, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not read private key file: %w", err)
|
||||
}
|
||||
|
||||
pk, err := crypto.UnmarshalPrivateKey(pkbytes)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not unmarshal private key: %w", err)
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) SetAPIEndpoint(ma multiaddr.Multiaddr) error {
|
||||
if err := fsr.stillValid(); err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(fsr.join(fsAPI), ma.Bytes(), 0666)
|
||||
}
|
||||
|
||||
func (fsr *fsLockedRepo) Wallet() (interface{}, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
@@ -44,6 +44,14 @@ type MemRepoOptions struct {
|
||||
Wallet interface{}
|
||||
}
|
||||
|
||||
func genLibp2pKey() (crypto.PrivKey, error) {
|
||||
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// NewMemory creates new memory based repo with provided options.
|
||||
// opts can be nil, it will be replaced with defaults.
|
||||
// Any field in opts can be nil, they will be replaced by defaults.
|
||||
@@ -58,7 +66,7 @@ func NewMemory(opts *MemRepoOptions) *MemRepo {
|
||||
opts.Ds = dssync.MutexWrap(datastore.NewMapDatastore())
|
||||
}
|
||||
if opts.Libp2pKey == nil {
|
||||
pk, _, err := crypto.GenerateEd25519Key(rand.Reader)
|
||||
pk, err := genLibp2pKey()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user