Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/alias/driver.go
1987 views
1
package alias
2
3
import (
4
"context"
5
"errors"
6
stdpath "path"
7
"strings"
8
9
"github.com/alist-org/alist/v3/internal/driver"
10
"github.com/alist-org/alist/v3/internal/errs"
11
"github.com/alist-org/alist/v3/internal/fs"
12
"github.com/alist-org/alist/v3/internal/model"
13
"github.com/alist-org/alist/v3/pkg/utils"
14
)
15
16
type Alias struct {
17
model.Storage
18
Addition
19
pathMap map[string][]string
20
autoFlatten bool
21
oneKey string
22
}
23
24
func (d *Alias) Config() driver.Config {
25
return config
26
}
27
28
func (d *Alias) GetAddition() driver.Additional {
29
return &d.Addition
30
}
31
32
func (d *Alias) Init(ctx context.Context) error {
33
if d.Paths == "" {
34
return errors.New("paths is required")
35
}
36
d.pathMap = make(map[string][]string)
37
for _, path := range strings.Split(d.Paths, "\n") {
38
path = strings.TrimSpace(path)
39
if path == "" {
40
continue
41
}
42
k, v := getPair(path)
43
d.pathMap[k] = append(d.pathMap[k], v)
44
}
45
if len(d.pathMap) == 1 {
46
for k := range d.pathMap {
47
d.oneKey = k
48
}
49
d.autoFlatten = true
50
} else {
51
d.oneKey = ""
52
d.autoFlatten = false
53
}
54
return nil
55
}
56
57
func (d *Alias) Drop(ctx context.Context) error {
58
d.pathMap = nil
59
return nil
60
}
61
62
func (d *Alias) Get(ctx context.Context, path string) (model.Obj, error) {
63
if utils.PathEqual(path, "/") {
64
return &model.Object{
65
Name: "Root",
66
IsFolder: true,
67
Path: "/",
68
}, nil
69
}
70
root, sub := d.getRootAndPath(path)
71
dsts, ok := d.pathMap[root]
72
if !ok {
73
return nil, errs.ObjectNotFound
74
}
75
for _, dst := range dsts {
76
obj, err := d.get(ctx, path, dst, sub)
77
if err == nil {
78
return obj, nil
79
}
80
}
81
return nil, errs.ObjectNotFound
82
}
83
84
func (d *Alias) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
85
path := dir.GetPath()
86
if utils.PathEqual(path, "/") && !d.autoFlatten {
87
return d.listRoot(), nil
88
}
89
root, sub := d.getRootAndPath(path)
90
dsts, ok := d.pathMap[root]
91
if !ok {
92
return nil, errs.ObjectNotFound
93
}
94
var objs []model.Obj
95
fsArgs := &fs.ListArgs{NoLog: true, Refresh: args.Refresh}
96
for _, dst := range dsts {
97
tmp, err := d.list(ctx, dst, sub, fsArgs)
98
if err == nil {
99
objs = append(objs, tmp...)
100
}
101
}
102
return objs, nil
103
}
104
105
func (d *Alias) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
106
root, sub := d.getRootAndPath(file.GetPath())
107
dsts, ok := d.pathMap[root]
108
if !ok {
109
return nil, errs.ObjectNotFound
110
}
111
for _, dst := range dsts {
112
link, err := d.link(ctx, dst, sub, args)
113
if err == nil {
114
if !args.Redirect && len(link.URL) > 0 {
115
// 正常情况下 多并发 仅支持返回URL的驱动
116
// alias套娃alias 可以让crypt、mega等驱动(不返回URL的) 支持并发
117
if d.DownloadConcurrency > 0 {
118
link.Concurrency = d.DownloadConcurrency
119
}
120
if d.DownloadPartSize > 0 {
121
link.PartSize = d.DownloadPartSize * utils.KB
122
}
123
}
124
return link, nil
125
}
126
}
127
return nil, errs.ObjectNotFound
128
}
129
130
func (d *Alias) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
131
if !d.Writable {
132
return errs.PermissionDenied
133
}
134
reqPath, err := d.getReqPath(ctx, parentDir, true)
135
if err == nil {
136
return fs.MakeDir(ctx, stdpath.Join(*reqPath, dirName))
137
}
138
if errs.IsNotImplement(err) {
139
return errors.New("same-name dirs cannot make sub-dir")
140
}
141
return err
142
}
143
144
func (d *Alias) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
145
if !d.Writable {
146
return errs.PermissionDenied
147
}
148
srcPath, err := d.getReqPath(ctx, srcObj, false)
149
if errs.IsNotImplement(err) {
150
return errors.New("same-name files cannot be moved")
151
}
152
if err != nil {
153
return err
154
}
155
dstPath, err := d.getReqPath(ctx, dstDir, true)
156
if errs.IsNotImplement(err) {
157
return errors.New("same-name dirs cannot be moved to")
158
}
159
if err != nil {
160
return err
161
}
162
return fs.Move(ctx, *srcPath, *dstPath)
163
}
164
165
func (d *Alias) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
166
if !d.Writable {
167
return errs.PermissionDenied
168
}
169
reqPath, err := d.getReqPath(ctx, srcObj, false)
170
if err == nil {
171
return fs.Rename(ctx, *reqPath, newName)
172
}
173
if errs.IsNotImplement(err) {
174
return errors.New("same-name files cannot be Rename")
175
}
176
return err
177
}
178
179
func (d *Alias) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
180
if !d.Writable {
181
return errs.PermissionDenied
182
}
183
srcPath, err := d.getReqPath(ctx, srcObj, false)
184
if errs.IsNotImplement(err) {
185
return errors.New("same-name files cannot be copied")
186
}
187
if err != nil {
188
return err
189
}
190
dstPath, err := d.getReqPath(ctx, dstDir, true)
191
if errs.IsNotImplement(err) {
192
return errors.New("same-name dirs cannot be copied to")
193
}
194
if err != nil {
195
return err
196
}
197
_, err = fs.Copy(ctx, *srcPath, *dstPath)
198
return err
199
}
200
201
func (d *Alias) Remove(ctx context.Context, obj model.Obj) error {
202
if !d.Writable {
203
return errs.PermissionDenied
204
}
205
reqPath, err := d.getReqPath(ctx, obj, false)
206
if err == nil {
207
return fs.Remove(ctx, *reqPath)
208
}
209
if errs.IsNotImplement(err) {
210
return errors.New("same-name files cannot be Delete")
211
}
212
return err
213
}
214
215
func (d *Alias) Put(ctx context.Context, dstDir model.Obj, s model.FileStreamer, up driver.UpdateProgress) error {
216
if !d.Writable {
217
return errs.PermissionDenied
218
}
219
reqPath, err := d.getReqPath(ctx, dstDir, true)
220
if err == nil {
221
return fs.PutDirectly(ctx, *reqPath, s)
222
}
223
if errs.IsNotImplement(err) {
224
return errors.New("same-name dirs cannot be Put")
225
}
226
return err
227
}
228
229
func (d *Alias) PutURL(ctx context.Context, dstDir model.Obj, name, url string) error {
230
if !d.Writable {
231
return errs.PermissionDenied
232
}
233
reqPath, err := d.getReqPath(ctx, dstDir, true)
234
if err == nil {
235
return fs.PutURL(ctx, *reqPath, name, url)
236
}
237
if errs.IsNotImplement(err) {
238
return errors.New("same-name files cannot offline download")
239
}
240
return err
241
}
242
243
func (d *Alias) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {
244
root, sub := d.getRootAndPath(obj.GetPath())
245
dsts, ok := d.pathMap[root]
246
if !ok {
247
return nil, errs.ObjectNotFound
248
}
249
for _, dst := range dsts {
250
meta, err := d.getArchiveMeta(ctx, dst, sub, args)
251
if err == nil {
252
return meta, nil
253
}
254
}
255
return nil, errs.NotImplement
256
}
257
258
func (d *Alias) ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error) {
259
root, sub := d.getRootAndPath(obj.GetPath())
260
dsts, ok := d.pathMap[root]
261
if !ok {
262
return nil, errs.ObjectNotFound
263
}
264
for _, dst := range dsts {
265
l, err := d.listArchive(ctx, dst, sub, args)
266
if err == nil {
267
return l, nil
268
}
269
}
270
return nil, errs.NotImplement
271
}
272
273
func (d *Alias) Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error) {
274
// alias的两个驱动,一个支持驱动提取,一个不支持,如何兼容?
275
// 如果访问的是不支持驱动提取的驱动内的压缩文件,GetArchiveMeta就会返回errs.NotImplement,提取URL前缀就会是/ae,Extract就不会被调用
276
// 如果访问的是支持驱动提取的驱动内的压缩文件,GetArchiveMeta就会返回有效值,提取URL前缀就会是/ad,Extract就会被调用
277
root, sub := d.getRootAndPath(obj.GetPath())
278
dsts, ok := d.pathMap[root]
279
if !ok {
280
return nil, errs.ObjectNotFound
281
}
282
for _, dst := range dsts {
283
link, err := d.extract(ctx, dst, sub, args)
284
if err == nil {
285
if !args.Redirect && len(link.URL) > 0 {
286
if d.DownloadConcurrency > 0 {
287
link.Concurrency = d.DownloadConcurrency
288
}
289
if d.DownloadPartSize > 0 {
290
link.PartSize = d.DownloadPartSize * utils.KB
291
}
292
}
293
return link, nil
294
}
295
}
296
return nil, errs.NotImplement
297
}
298
299
func (d *Alias) ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) error {
300
if !d.Writable {
301
return errs.PermissionDenied
302
}
303
srcPath, err := d.getReqPath(ctx, srcObj, false)
304
if errs.IsNotImplement(err) {
305
return errors.New("same-name files cannot be decompressed")
306
}
307
if err != nil {
308
return err
309
}
310
dstPath, err := d.getReqPath(ctx, dstDir, true)
311
if errs.IsNotImplement(err) {
312
return errors.New("same-name dirs cannot be decompressed to")
313
}
314
if err != nil {
315
return err
316
}
317
_, err = fs.ArchiveDecompress(ctx, *srcPath, *dstPath, args)
318
return err
319
}
320
321
var _ driver.Driver = (*Alias)(nil)
322
323