mirror of
https://github.com/ipfs/kubo.git
synced 2025-09-09 23:42:20 +08:00
Refactor ipnsfs into a more generic and well tested mfs
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
This commit is contained in:
@ -16,7 +16,7 @@ import (
|
||||
|
||||
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
nsfs "github.com/ipfs/go-ipfs/ipnsfs"
|
||||
//mfs "github.com/ipfs/go-ipfs/mfs"
|
||||
namesys "github.com/ipfs/go-ipfs/namesys"
|
||||
offroute "github.com/ipfs/go-ipfs/routing/offline"
|
||||
u "github.com/ipfs/go-ipfs/util"
|
||||
@ -115,12 +115,10 @@ func setupIpnsTest(t *testing.T, node *core.IpfsNode) (*core.IpfsNode, *fstest.M
|
||||
node.Routing = offroute.NewOfflineRouter(node.Repo.Datastore(), node.PrivateKey)
|
||||
node.Namesys = namesys.NewNameSystem(node.Routing, node.Repo.Datastore(), 0)
|
||||
|
||||
ipnsfs, err := nsfs.NewFilesystem(context.Background(), node.DAG, node.Namesys, node.Pinning, node.PrivateKey)
|
||||
err = InitializeKeyspace(node, node.PrivateKey)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
node.IpnsFs = ipnsfs
|
||||
}
|
||||
|
||||
fs, err := NewFileSystem(node, node.PrivateKey, "", "")
|
||||
|
@ -17,9 +17,10 @@ import (
|
||||
|
||||
key "github.com/ipfs/go-ipfs/blocks/key"
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
nsfs "github.com/ipfs/go-ipfs/ipnsfs"
|
||||
dag "github.com/ipfs/go-ipfs/merkledag"
|
||||
mfs "github.com/ipfs/go-ipfs/mfs"
|
||||
ci "github.com/ipfs/go-ipfs/p2p/crypto"
|
||||
path "github.com/ipfs/go-ipfs/path"
|
||||
ft "github.com/ipfs/go-ipfs/unixfs"
|
||||
)
|
||||
|
||||
@ -33,10 +34,15 @@ type FileSystem struct {
|
||||
|
||||
// NewFileSystem constructs new fs using given core.IpfsNode instance.
|
||||
func NewFileSystem(ipfs *core.IpfsNode, sk ci.PrivKey, ipfspath, ipnspath string) (*FileSystem, error) {
|
||||
root, err := CreateRoot(ipfs, []ci.PrivKey{sk}, ipfspath, ipnspath)
|
||||
|
||||
kmap := map[string]ci.PrivKey{
|
||||
"local": sk,
|
||||
}
|
||||
root, err := CreateRoot(ipfs, kmap, ipfspath, ipnspath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &FileSystem{Ipfs: ipfs, RootNode: root}, nil
|
||||
}
|
||||
|
||||
@ -56,53 +62,95 @@ func (f *FileSystem) Destroy() {
|
||||
// Root is the root object of the filesystem tree.
|
||||
type Root struct {
|
||||
Ipfs *core.IpfsNode
|
||||
Keys []ci.PrivKey
|
||||
Keys map[string]ci.PrivKey
|
||||
|
||||
// Used for symlinking into ipfs
|
||||
IpfsRoot string
|
||||
IpnsRoot string
|
||||
LocalDirs map[string]fs.Node
|
||||
Roots map[string]*nsfs.KeyRoot
|
||||
Roots map[string]*keyRoot
|
||||
|
||||
fs *nsfs.Filesystem
|
||||
LocalLink *Link
|
||||
LocalLinks map[string]*Link
|
||||
}
|
||||
|
||||
func CreateRoot(ipfs *core.IpfsNode, keys []ci.PrivKey, ipfspath, ipnspath string) (*Root, error) {
|
||||
func ipnsPubFunc(ipfs *core.IpfsNode, k ci.PrivKey) mfs.PubFunc {
|
||||
return func(ctx context.Context, key key.Key) error {
|
||||
return ipfs.Namesys.Publish(ctx, k, path.FromKey(key))
|
||||
}
|
||||
}
|
||||
|
||||
func loadRoot(ctx context.Context, rt *keyRoot, ipfs *core.IpfsNode, name string) (fs.Node, error) {
|
||||
p, err := path.ParsePath("/ipns/" + name)
|
||||
if err != nil {
|
||||
log.Errorf("mkpath %s: %s", name, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
node, err := core.Resolve(ctx, ipfs, p)
|
||||
if err != nil {
|
||||
log.Errorf("looking up %s: %s", p, err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
root, err := mfs.NewRoot(ctx, ipfs.DAG, node, ipnsPubFunc(ipfs, rt.k))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rt.root = root
|
||||
|
||||
switch val := root.GetValue().(type) {
|
||||
case *mfs.Directory:
|
||||
return &Directory{dir: val}, nil
|
||||
case *mfs.File:
|
||||
return &File{fi: val}, nil
|
||||
default:
|
||||
return nil, errors.New("unrecognized type")
|
||||
}
|
||||
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
type keyRoot struct {
|
||||
k ci.PrivKey
|
||||
alias string
|
||||
root *mfs.Root
|
||||
}
|
||||
|
||||
func CreateRoot(ipfs *core.IpfsNode, keys map[string]ci.PrivKey, ipfspath, ipnspath string) (*Root, error) {
|
||||
ldirs := make(map[string]fs.Node)
|
||||
roots := make(map[string]*nsfs.KeyRoot)
|
||||
for _, k := range keys {
|
||||
roots := make(map[string]*keyRoot)
|
||||
links := make(map[string]*Link)
|
||||
for alias, k := range keys {
|
||||
pkh, err := k.GetPublic().Hash()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
name := key.Key(pkh).B58String()
|
||||
root, err := ipfs.IpnsFs.GetRoot(name)
|
||||
|
||||
kr := &keyRoot{k: k, alias: alias}
|
||||
fsn, err := loadRoot(ipfs.Context(), kr, ipfs, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roots[name] = root
|
||||
roots[name] = kr
|
||||
ldirs[name] = fsn
|
||||
|
||||
switch val := root.GetValue().(type) {
|
||||
case *nsfs.Directory:
|
||||
ldirs[name] = &Directory{dir: val}
|
||||
case *nsfs.File:
|
||||
ldirs[name] = &File{fi: val}
|
||||
default:
|
||||
return nil, errors.New("unrecognized type")
|
||||
// set up alias symlink
|
||||
links[alias] = &Link{
|
||||
Target: name,
|
||||
}
|
||||
}
|
||||
|
||||
return &Root{
|
||||
fs: ipfs.IpnsFs,
|
||||
Ipfs: ipfs,
|
||||
IpfsRoot: ipfspath,
|
||||
IpnsRoot: ipnspath,
|
||||
Keys: keys,
|
||||
LocalDirs: ldirs,
|
||||
LocalLink: &Link{ipfs.Identity.Pretty()},
|
||||
Roots: roots,
|
||||
Ipfs: ipfs,
|
||||
IpfsRoot: ipfspath,
|
||||
IpnsRoot: ipnspath,
|
||||
Keys: keys,
|
||||
LocalDirs: ldirs,
|
||||
LocalLinks: links,
|
||||
Roots: roots,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -121,12 +169,8 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
|
||||
// Local symlink to the node ID keyspace
|
||||
if name == "local" {
|
||||
if s.LocalLink == nil {
|
||||
return nil, fuse.ENOENT
|
||||
}
|
||||
return s.LocalLink, nil
|
||||
if lnk, ok := s.LocalLinks[name]; ok {
|
||||
return lnk, nil
|
||||
}
|
||||
|
||||
nd, ok := s.LocalDirs[name]
|
||||
@ -152,15 +196,15 @@ func (s *Root) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
if segments[0] == "ipfs" {
|
||||
p := strings.Join(resolved.Segments()[1:], "/")
|
||||
return &Link{s.IpfsRoot + "/" + p}, nil
|
||||
} else {
|
||||
log.Error("Invalid path.Path: ", resolved)
|
||||
return nil, errors.New("invalid path from ipns record")
|
||||
}
|
||||
|
||||
log.Error("Invalid path.Path: ", resolved)
|
||||
return nil, errors.New("invalid path from ipns record")
|
||||
}
|
||||
|
||||
func (r *Root) Close() error {
|
||||
for _, kr := range r.Roots {
|
||||
err := kr.Publish(r.Ipfs.Context())
|
||||
for _, mr := range r.Roots {
|
||||
err := mr.root.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -181,13 +225,9 @@ func (r *Root) Forget() {
|
||||
// as well as a symlink to the peerID key
|
||||
func (r *Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
log.Debug("Root ReadDirAll")
|
||||
listing := []fuse.Dirent{
|
||||
{
|
||||
Name: "local",
|
||||
Type: fuse.DT_Link,
|
||||
},
|
||||
}
|
||||
for _, k := range r.Keys {
|
||||
|
||||
var listing []fuse.Dirent
|
||||
for alias, k := range r.Keys {
|
||||
pub := k.GetPublic()
|
||||
hash, err := pub.Hash()
|
||||
if err != nil {
|
||||
@ -197,21 +237,25 @@ func (r *Root) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
Name: key.Key(hash).Pretty(),
|
||||
Type: fuse.DT_Dir,
|
||||
}
|
||||
listing = append(listing, ent)
|
||||
link := fuse.Dirent{
|
||||
Name: alias,
|
||||
Type: fuse.DT_Link,
|
||||
}
|
||||
listing = append(listing, ent, link)
|
||||
}
|
||||
return listing, nil
|
||||
}
|
||||
|
||||
// Directory is wrapper over an ipnsfs directory to satisfy the fuse fs interface
|
||||
// Directory is wrapper over an mfs directory to satisfy the fuse fs interface
|
||||
type Directory struct {
|
||||
dir *nsfs.Directory
|
||||
dir *mfs.Directory
|
||||
|
||||
fs.NodeRef
|
||||
}
|
||||
|
||||
// File is wrapper over an ipnsfs file to satisfy the fuse fs interface
|
||||
// File is wrapper over an mfs file to satisfy the fuse fs interface
|
||||
type File struct {
|
||||
fi *nsfs.File
|
||||
fi *mfs.File
|
||||
|
||||
fs.NodeRef
|
||||
}
|
||||
@ -249,9 +293,9 @@ func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
}
|
||||
|
||||
switch child := child.(type) {
|
||||
case *nsfs.Directory:
|
||||
case *mfs.Directory:
|
||||
return &Directory{dir: child}, nil
|
||||
case *nsfs.File:
|
||||
case *mfs.File:
|
||||
return &File{fi: child}, nil
|
||||
default:
|
||||
// NB: if this happens, we do not want to continue, unpredictable behaviour
|
||||
@ -263,19 +307,17 @@ func (s *Directory) Lookup(ctx context.Context, name string) (fs.Node, error) {
|
||||
// ReadDirAll reads the link structure as directory entries
|
||||
func (dir *Directory) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
|
||||
var entries []fuse.Dirent
|
||||
for _, name := range dir.dir.List() {
|
||||
dirent := fuse.Dirent{Name: name}
|
||||
listing, err := dir.dir.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, entry := range listing {
|
||||
dirent := fuse.Dirent{Name: entry.Name}
|
||||
|
||||
// TODO: make dir.dir.List() return dirinfos
|
||||
child, err := dir.dir.Child(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch child.Type() {
|
||||
case nsfs.TDir:
|
||||
switch mfs.NodeType(entry.Type) {
|
||||
case mfs.TDir:
|
||||
dirent.Type = fuse.DT_Dir
|
||||
case nsfs.TFile:
|
||||
case mfs.TFile:
|
||||
dirent.Type = fuse.DT_File
|
||||
}
|
||||
|
||||
@ -419,7 +461,7 @@ func (dir *Directory) Create(ctx context.Context, req *fuse.CreateRequest, resp
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
fi, ok := child.(*nsfs.File)
|
||||
fi, ok := child.(*mfs.File)
|
||||
if !ok {
|
||||
return nil, nil, errors.New("child creation failed")
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ package ipns
|
||||
import (
|
||||
core "github.com/ipfs/go-ipfs/core"
|
||||
mount "github.com/ipfs/go-ipfs/fuse/mount"
|
||||
ipnsfs "github.com/ipfs/go-ipfs/ipnsfs"
|
||||
)
|
||||
|
||||
// Mount mounts ipns at a given location, and returns a mount.Mount instance.
|
||||
@ -18,14 +17,6 @@ func Mount(ipfs *core.IpfsNode, ipnsmp, ipfsmp string) (mount.Mount, error) {
|
||||
|
||||
allow_other := cfg.Mounts.FuseAllowOther
|
||||
|
||||
if ipfs.IpnsFs == nil {
|
||||
fs, err := ipnsfs.NewFilesystem(ipfs.Context(), ipfs.DAG, ipfs.Namesys, ipfs.Pinning, ipfs.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ipfs.IpnsFs = fs
|
||||
}
|
||||
|
||||
fsys, err := NewFileSystem(ipfs, ipfs.PrivateKey, ipfsmp, ipnsmp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
Reference in New Issue
Block a user