fix(ipfs): fix problems (#8252)

* fix: 🐛 (ipfs): fix the list error caused by not proper join path function

使用更加规范的路径拼接,修复了有中文或符号的路径无法正常访问的问题

* refactor: 命名规范

* 删除多余的条件判断

* fix: 使用withresult方法重构代码,添加get方法,提高性能

* fix: 允许get方法获取目录

去除多余的判断

* fix: 允许copy,rename,move进行覆写

* fix: 修复move方法导致的目录被删除

* refactor: 整理关于返回Path的代码

* fix: 修复由于get方法导致的ipfs路径无法访问

* fix: 修复path处理错误的get方法

修复get方法,删除意外加入的目录

* fix: fix path join

use path join instead of filepath join to avoid os problem

* fix: rm filepath ref

---------

Co-authored-by: Andy Hsu <i@nn.ci>
pull/8357/head
jerry 2025-04-12 17:01:30 +08:00 committed by GitHub
parent ddffacf07b
commit a4bfbf8a83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 92 additions and 50 deletions

View File

@ -4,8 +4,7 @@ import (
"context" "context"
"fmt" "fmt"
"net/url" "net/url"
"path/filepath" "path"
"strings"
shell "github.com/ipfs/go-ipfs-api" shell "github.com/ipfs/go-ipfs-api"
@ -43,78 +42,115 @@ func (d *IPFS) Drop(ctx context.Context) error {
} }
func (d *IPFS) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { func (d *IPFS) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
path := dir.GetPath() var ipfsPath string
switch d.Mode { cid := dir.GetID()
case "ipfs": if cid != "" {
path, _ = url.JoinPath("/ipfs", path) ipfsPath = path.Join("/ipfs", cid)
case "ipns": } else {
path, _ = url.JoinPath("/ipns", path) // 可能出现ipns dns解析失败的情况需要重复获取cid其他情况应该不会出错
case "mfs": ipfsPath = dir.GetPath()
fileStat, err := d.sh.FilesStat(ctx, path) switch d.Mode {
if err != nil { case "ipfs":
return nil, err ipfsPath = path.Join("/ipfs", ipfsPath)
case "ipns":
ipfsPath = path.Join("/ipns", ipfsPath)
case "mfs":
fileStat, err := d.sh.FilesStat(ctx, ipfsPath)
if err != nil {
return nil, err
}
ipfsPath = path.Join("/ipfs", fileStat.Hash)
default:
return nil, fmt.Errorf("mode error")
} }
path, _ = url.JoinPath("/ipfs", fileStat.Hash)
default:
return nil, fmt.Errorf("mode error")
} }
dirs, err := d.sh.List(ipfsPath)
dirs, err := d.sh.List(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
objlist := []model.Obj{} objlist := []model.Obj{}
for _, file := range dirs { for _, file := range dirs {
gateurl := *d.gateURL.JoinPath("/ipfs/" + file.Hash) objlist = append(objlist, &model.Object{ID: file.Hash, Name: file.Name, Size: int64(file.Size), IsFolder: file.Type == 1})
gateurl.RawQuery = "filename=" + url.PathEscape(file.Name)
objlist = append(objlist, &model.ObjectURL{
Object: model.Object{ID: "/ipfs/" + file.Hash, Name: file.Name, Size: int64(file.Size), IsFolder: file.Type == 1},
Url: model.Url{Url: gateurl.String()},
})
} }
return objlist, nil return objlist, nil
} }
func (d *IPFS) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { func (d *IPFS) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
gateurl := d.gateURL.JoinPath(file.GetID()) gateurl := d.gateURL.JoinPath("/ipfs/", file.GetID())
gateurl.RawQuery = "filename=" + url.PathEscape(file.GetName()) gateurl.RawQuery = "filename=" + url.QueryEscape(file.GetName())
return &model.Link{URL: gateurl.String()}, nil return &model.Link{URL: gateurl.String()}, nil
} }
func (d *IPFS) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { func (d *IPFS) Get(ctx context.Context, rawPath string) (model.Obj, error) {
if d.Mode != "mfs" { rawPath = path.Join(d.GetRootPath(), rawPath)
return fmt.Errorf("only write in mfs mode") var ipfsPath string
switch d.Mode {
case "ipfs":
ipfsPath = path.Join("/ipfs", rawPath)
case "ipns":
ipfsPath = path.Join("/ipns", rawPath)
case "mfs":
fileStat, err := d.sh.FilesStat(ctx, rawPath)
if err != nil {
return nil, err
}
ipfsPath = path.Join("/ipfs", fileStat.Hash)
default:
return nil, fmt.Errorf("mode error")
} }
path := parentDir.GetPath() file, err := d.sh.FilesStat(ctx, ipfsPath)
if path[len(path):] != "/" { if err != nil {
path += "/" return nil, err
} }
return d.sh.FilesMkdir(ctx, path+dirName) return &model.Object{ID: file.Hash, Name: path.Base(rawPath), Path: rawPath, Size: int64(file.Size), IsFolder: file.Type == "directory"}, nil
} }
func (d *IPFS) Move(ctx context.Context, srcObj, dstDir model.Obj) error { func (d *IPFS) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
if d.Mode != "mfs" { if d.Mode != "mfs" {
return fmt.Errorf("only write in mfs mode") return nil, fmt.Errorf("only write in mfs mode")
} }
return d.sh.FilesMv(ctx, srcObj.GetPath(), dstDir.GetPath()) dirPath := parentDir.GetPath()
err := d.sh.FilesMkdir(ctx, path.Join(dirPath, dirName), shell.FilesMkdir.Parents(true))
if err != nil {
return nil, err
}
file, err := d.sh.FilesStat(ctx, path.Join(dirPath, dirName))
if err != nil {
return nil, err
}
return &model.Object{ID: file.Hash, Name: dirName, Path: path.Join(dirPath, dirName), Size: int64(file.Size), IsFolder: true}, nil
} }
func (d *IPFS) Rename(ctx context.Context, srcObj model.Obj, newName string) error { func (d *IPFS) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
if d.Mode != "mfs" { if d.Mode != "mfs" {
return fmt.Errorf("only write in mfs mode") return nil, fmt.Errorf("only write in mfs mode")
} }
newFileName := filepath.Dir(srcObj.GetPath()) + "/" + newName dstPath := path.Join(dstDir.GetPath(), path.Base(srcObj.GetPath()))
return d.sh.FilesMv(ctx, srcObj.GetPath(), strings.ReplaceAll(newFileName, "\\", "/")) d.sh.FilesRm(ctx, dstPath, true)
return &model.Object{ID: srcObj.GetID(), Name: srcObj.GetName(), Path: dstPath, Size: int64(srcObj.GetSize()), IsFolder: srcObj.IsDir()},
d.sh.FilesMv(ctx, srcObj.GetPath(), dstDir.GetPath())
} }
func (d *IPFS) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { func (d *IPFS) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
if d.Mode != "mfs" { if d.Mode != "mfs" {
return fmt.Errorf("only write in mfs mode") return nil, fmt.Errorf("only write in mfs mode")
} }
newFileName := dstDir.GetPath() + "/" + filepath.Base(srcObj.GetPath()) dstPath := path.Join(path.Dir(srcObj.GetPath()), newName)
return d.sh.FilesCp(ctx, srcObj.GetPath(), strings.ReplaceAll(newFileName, "\\", "/")) d.sh.FilesRm(ctx, dstPath, true)
return &model.Object{ID: srcObj.GetID(), Name: newName, Path: dstPath, Size: int64(srcObj.GetSize()),
IsFolder: srcObj.IsDir()}, d.sh.FilesMv(ctx, srcObj.GetPath(), dstPath)
}
func (d *IPFS) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
if d.Mode != "mfs" {
return nil, fmt.Errorf("only write in mfs mode")
}
dstPath := path.Join(dstDir.GetPath(), path.Base(srcObj.GetPath()))
d.sh.FilesRm(ctx, dstPath, true)
return &model.Object{ID: srcObj.GetID(), Name: srcObj.GetName(), Path: dstPath, Size: int64(srcObj.GetSize()), IsFolder: srcObj.IsDir()},
d.sh.FilesCp(ctx, path.Join("/ipfs/", srcObj.GetID()), dstPath, shell.FilesCp.Parents(true))
} }
func (d *IPFS) Remove(ctx context.Context, obj model.Obj) error { func (d *IPFS) Remove(ctx context.Context, obj model.Obj) error {
@ -124,19 +160,25 @@ func (d *IPFS) Remove(ctx context.Context, obj model.Obj) error {
return d.sh.FilesRm(ctx, obj.GetPath(), true) return d.sh.FilesRm(ctx, obj.GetPath(), true)
} }
func (d *IPFS) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer, up driver.UpdateProgress) error { func (d *IPFS) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
if d.Mode != "mfs" { if d.Mode != "mfs" {
return fmt.Errorf("only write in mfs mode") return nil, fmt.Errorf("only write in mfs mode")
} }
outHash, err := d.sh.Add(driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{ outHash, err := d.sh.Add(driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{
Reader: s, Reader: s,
UpdateProgress: up, UpdateProgress: up,
})) }))
if err != nil { if err != nil {
return err return nil, err
} }
err = d.sh.FilesCp(ctx, "/ipfs/"+outHash, dstDir.GetPath()+"/"+strings.ReplaceAll(s.GetName(), "\\", "/")) dstPath := path.Join(dstDir.GetPath(), s.GetName())
return err if s.GetExist() != nil {
d.sh.FilesRm(ctx, dstPath, true)
}
err = d.sh.FilesCp(ctx, path.Join("/ipfs/", outHash), dstPath, shell.FilesCp.Parents(true))
gateurl := d.gateURL.JoinPath("/ipfs/", outHash)
gateurl.RawQuery = "filename=" + url.QueryEscape(s.GetName())
return &model.Object{ID: outHash, Name: s.GetName(), Path: dstPath, Size: int64(s.GetSize()), IsFolder: s.IsDir()}, err
} }
//func (d *Template) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) { //func (d *Template) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {

View File

@ -9,8 +9,8 @@ type Addition struct {
// Usually one of two // Usually one of two
driver.RootPath driver.RootPath
Mode string `json:"mode" options:"ipfs,ipns,mfs" type:"select" required:"true"` Mode string `json:"mode" options:"ipfs,ipns,mfs" type:"select" required:"true"`
Endpoint string `json:"endpoint" default:"http://127.0.0.1:5001"` Endpoint string `json:"endpoint" default:"http://127.0.0.1:5001" required:"true"`
Gateway string `json:"gateway" default:"http://127.0.0.1:8080"` Gateway string `json:"gateway" default:"http://127.0.0.1:8080" required:"true"`
} }
var config = driver.Config{ var config = driver.Config{