Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/ipfs_api/driver.go
1987 views
1
package ipfs
2
3
import (
4
"context"
5
"fmt"
6
"net/url"
7
"path"
8
9
shell "github.com/ipfs/go-ipfs-api"
10
11
"github.com/alist-org/alist/v3/internal/driver"
12
"github.com/alist-org/alist/v3/internal/model"
13
)
14
15
type IPFS struct {
16
model.Storage
17
Addition
18
sh *shell.Shell
19
gateURL *url.URL
20
}
21
22
func (d *IPFS) Config() driver.Config {
23
return config
24
}
25
26
func (d *IPFS) GetAddition() driver.Additional {
27
return &d.Addition
28
}
29
30
func (d *IPFS) Init(ctx context.Context) error {
31
d.sh = shell.NewShell(d.Endpoint)
32
gateURL, err := url.Parse(d.Gateway)
33
if err != nil {
34
return err
35
}
36
d.gateURL = gateURL
37
return nil
38
}
39
40
func (d *IPFS) Drop(ctx context.Context) error {
41
return nil
42
}
43
44
func (d *IPFS) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
45
var ipfsPath string
46
cid := dir.GetID()
47
if cid != "" {
48
ipfsPath = path.Join("/ipfs", cid)
49
} else {
50
// 可能出现ipns dns解析失败的情况,需要重复获取cid,其他情况应该不会出错
51
ipfsPath = dir.GetPath()
52
switch d.Mode {
53
case "ipfs":
54
ipfsPath = path.Join("/ipfs", ipfsPath)
55
case "ipns":
56
ipfsPath = path.Join("/ipns", ipfsPath)
57
case "mfs":
58
fileStat, err := d.sh.FilesStat(ctx, ipfsPath)
59
if err != nil {
60
return nil, err
61
}
62
ipfsPath = path.Join("/ipfs", fileStat.Hash)
63
default:
64
return nil, fmt.Errorf("mode error")
65
}
66
}
67
dirs, err := d.sh.List(ipfsPath)
68
if err != nil {
69
return nil, err
70
}
71
72
objlist := []model.Obj{}
73
for _, file := range dirs {
74
objlist = append(objlist, &model.Object{ID: file.Hash, Name: file.Name, Size: int64(file.Size), IsFolder: file.Type == 1})
75
}
76
77
return objlist, nil
78
}
79
80
func (d *IPFS) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
81
gateurl := d.gateURL.JoinPath("/ipfs/", file.GetID())
82
gateurl.RawQuery = "filename=" + url.QueryEscape(file.GetName())
83
return &model.Link{URL: gateurl.String()}, nil
84
}
85
86
func (d *IPFS) Get(ctx context.Context, rawPath string) (model.Obj, error) {
87
rawPath = path.Join(d.GetRootPath(), rawPath)
88
var ipfsPath string
89
switch d.Mode {
90
case "ipfs":
91
ipfsPath = path.Join("/ipfs", rawPath)
92
case "ipns":
93
ipfsPath = path.Join("/ipns", rawPath)
94
case "mfs":
95
fileStat, err := d.sh.FilesStat(ctx, rawPath)
96
if err != nil {
97
return nil, err
98
}
99
ipfsPath = path.Join("/ipfs", fileStat.Hash)
100
default:
101
return nil, fmt.Errorf("mode error")
102
}
103
file, err := d.sh.FilesStat(ctx, ipfsPath)
104
if err != nil {
105
return nil, err
106
}
107
return &model.Object{ID: file.Hash, Name: path.Base(rawPath), Path: rawPath, Size: int64(file.Size), IsFolder: file.Type == "directory"}, nil
108
}
109
110
func (d *IPFS) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
111
if d.Mode != "mfs" {
112
return nil, fmt.Errorf("only write in mfs mode")
113
}
114
dirPath := parentDir.GetPath()
115
err := d.sh.FilesMkdir(ctx, path.Join(dirPath, dirName), shell.FilesMkdir.Parents(true))
116
if err != nil {
117
return nil, err
118
}
119
file, err := d.sh.FilesStat(ctx, path.Join(dirPath, dirName))
120
if err != nil {
121
return nil, err
122
}
123
return &model.Object{ID: file.Hash, Name: dirName, Path: path.Join(dirPath, dirName), Size: int64(file.Size), IsFolder: true}, nil
124
}
125
126
func (d *IPFS) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
127
if d.Mode != "mfs" {
128
return nil, fmt.Errorf("only write in mfs mode")
129
}
130
dstPath := path.Join(dstDir.GetPath(), path.Base(srcObj.GetPath()))
131
d.sh.FilesRm(ctx, dstPath, true)
132
return &model.Object{ID: srcObj.GetID(), Name: srcObj.GetName(), Path: dstPath, Size: int64(srcObj.GetSize()), IsFolder: srcObj.IsDir()},
133
d.sh.FilesMv(ctx, srcObj.GetPath(), dstDir.GetPath())
134
}
135
136
func (d *IPFS) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
137
if d.Mode != "mfs" {
138
return nil, fmt.Errorf("only write in mfs mode")
139
}
140
dstPath := path.Join(path.Dir(srcObj.GetPath()), newName)
141
d.sh.FilesRm(ctx, dstPath, true)
142
return &model.Object{ID: srcObj.GetID(), Name: newName, Path: dstPath, Size: int64(srcObj.GetSize()),
143
IsFolder: srcObj.IsDir()}, d.sh.FilesMv(ctx, srcObj.GetPath(), dstPath)
144
}
145
146
func (d *IPFS) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
147
if d.Mode != "mfs" {
148
return nil, fmt.Errorf("only write in mfs mode")
149
}
150
dstPath := path.Join(dstDir.GetPath(), path.Base(srcObj.GetPath()))
151
d.sh.FilesRm(ctx, dstPath, true)
152
return &model.Object{ID: srcObj.GetID(), Name: srcObj.GetName(), Path: dstPath, Size: int64(srcObj.GetSize()), IsFolder: srcObj.IsDir()},
153
d.sh.FilesCp(ctx, path.Join("/ipfs/", srcObj.GetID()), dstPath, shell.FilesCp.Parents(true))
154
}
155
156
func (d *IPFS) Remove(ctx context.Context, obj model.Obj) error {
157
if d.Mode != "mfs" {
158
return fmt.Errorf("only write in mfs mode")
159
}
160
return d.sh.FilesRm(ctx, obj.GetPath(), true)
161
}
162
163
func (d *IPFS) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
164
if d.Mode != "mfs" {
165
return nil, fmt.Errorf("only write in mfs mode")
166
}
167
outHash, err := d.sh.Add(driver.NewLimitedUploadStream(ctx, &driver.ReaderUpdatingProgress{
168
Reader: s,
169
UpdateProgress: up,
170
}))
171
if err != nil {
172
return nil, err
173
}
174
dstPath := path.Join(dstDir.GetPath(), s.GetName())
175
if s.GetExist() != nil {
176
d.sh.FilesRm(ctx, dstPath, true)
177
}
178
err = d.sh.FilesCp(ctx, path.Join("/ipfs/", outHash), dstPath, shell.FilesCp.Parents(true))
179
gateurl := d.gateURL.JoinPath("/ipfs/", outHash)
180
gateurl.RawQuery = "filename=" + url.QueryEscape(s.GetName())
181
return &model.Object{ID: outHash, Name: s.GetName(), Path: dstPath, Size: int64(s.GetSize()), IsFolder: s.IsDir()}, err
182
}
183
184
//func (d *Template) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
185
// return nil, errs.NotSupport
186
//}
187
188
var _ driver.Driver = (*IPFS)(nil)
189
190