Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/cloudreve/driver.go
1986 views
1
package cloudreve
2
3
import (
4
"context"
5
"io"
6
"net/http"
7
"path"
8
"strings"
9
10
"github.com/alist-org/alist/v3/drivers/base"
11
"github.com/alist-org/alist/v3/internal/driver"
12
"github.com/alist-org/alist/v3/internal/errs"
13
"github.com/alist-org/alist/v3/internal/model"
14
"github.com/alist-org/alist/v3/pkg/utils"
15
"github.com/go-resty/resty/v2"
16
)
17
18
type Cloudreve struct {
19
model.Storage
20
Addition
21
ref *Cloudreve
22
}
23
24
func (d *Cloudreve) Config() driver.Config {
25
return config
26
}
27
28
func (d *Cloudreve) GetAddition() driver.Additional {
29
return &d.Addition
30
}
31
32
func (d *Cloudreve) Init(ctx context.Context) error {
33
if d.Cookie != "" {
34
return nil
35
}
36
// removing trailing slash
37
d.Address = strings.TrimSuffix(d.Address, "/")
38
return d.login()
39
}
40
41
func (d *Cloudreve) InitReference(storage driver.Driver) error {
42
refStorage, ok := storage.(*Cloudreve)
43
if ok {
44
d.ref = refStorage
45
return nil
46
}
47
return errs.NotSupport
48
}
49
50
func (d *Cloudreve) Drop(ctx context.Context) error {
51
d.Cookie = ""
52
d.ref = nil
53
return nil
54
}
55
56
func (d *Cloudreve) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
57
var r DirectoryResp
58
err := d.request(http.MethodGet, "/directory"+dir.GetPath(), nil, &r)
59
if err != nil {
60
return nil, err
61
}
62
63
return utils.SliceConvert(r.Objects, func(src Object) (model.Obj, error) {
64
thumb, err := d.GetThumb(src)
65
if err != nil {
66
return nil, err
67
}
68
if src.Type == "dir" && d.EnableThumbAndFolderSize {
69
var dprop DirectoryProp
70
err = d.request(http.MethodGet, "/object/property/"+src.Id+"?is_folder=true", nil, &dprop)
71
if err != nil {
72
return nil, err
73
}
74
src.Size = dprop.Size
75
}
76
return objectToObj(src, thumb), nil
77
})
78
}
79
80
func (d *Cloudreve) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
81
var dUrl string
82
err := d.request(http.MethodPut, "/file/download/"+file.GetID(), nil, &dUrl)
83
if err != nil {
84
return nil, err
85
}
86
if strings.HasPrefix(dUrl, "/api") {
87
dUrl = d.Address + dUrl
88
}
89
return &model.Link{
90
URL: dUrl,
91
}, nil
92
}
93
94
func (d *Cloudreve) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
95
return d.request(http.MethodPut, "/directory", func(req *resty.Request) {
96
req.SetBody(base.Json{
97
"path": parentDir.GetPath() + "/" + dirName,
98
})
99
}, nil)
100
}
101
102
func (d *Cloudreve) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
103
body := base.Json{
104
"action": "move",
105
"src_dir": path.Dir(srcObj.GetPath()),
106
"dst": dstDir.GetPath(),
107
"src": convertSrc(srcObj),
108
}
109
return d.request(http.MethodPatch, "/object", func(req *resty.Request) {
110
req.SetBody(body)
111
}, nil)
112
}
113
114
func (d *Cloudreve) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
115
body := base.Json{
116
"action": "rename",
117
"new_name": newName,
118
"src": convertSrc(srcObj),
119
}
120
return d.request(http.MethodPatch, "/object/rename", func(req *resty.Request) {
121
req.SetBody(body)
122
}, nil)
123
}
124
125
func (d *Cloudreve) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
126
body := base.Json{
127
"src_dir": path.Dir(srcObj.GetPath()),
128
"dst": dstDir.GetPath(),
129
"src": convertSrc(srcObj),
130
}
131
return d.request(http.MethodPost, "/object/copy", func(req *resty.Request) {
132
req.SetBody(body)
133
}, nil)
134
}
135
136
func (d *Cloudreve) Remove(ctx context.Context, obj model.Obj) error {
137
body := convertSrc(obj)
138
err := d.request(http.MethodDelete, "/object", func(req *resty.Request) {
139
req.SetBody(body)
140
}, nil)
141
return err
142
}
143
144
func (d *Cloudreve) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
145
if io.ReadCloser(stream) == http.NoBody {
146
return d.create(ctx, dstDir, stream)
147
}
148
149
// 获取存储策略
150
var r DirectoryResp
151
err := d.request(http.MethodGet, "/directory"+dstDir.GetPath(), nil, &r)
152
if err != nil {
153
return err
154
}
155
uploadBody := base.Json{
156
"path": dstDir.GetPath(),
157
"size": stream.GetSize(),
158
"name": stream.GetName(),
159
"policy_id": r.Policy.Id,
160
"last_modified": stream.ModTime().UnixMilli(),
161
}
162
163
// 获取上传会话信息
164
var u UploadInfo
165
err = d.request(http.MethodPut, "/file/upload", func(req *resty.Request) {
166
req.SetBody(uploadBody)
167
}, &u)
168
if err != nil {
169
return err
170
}
171
172
// 根据存储方式选择分片上传的方法
173
switch r.Policy.Type {
174
case "onedrive":
175
err = d.upOneDrive(ctx, stream, u, up)
176
case "s3":
177
err = d.upS3(ctx, stream, u, up)
178
case "remote": // 从机存储
179
err = d.upRemote(ctx, stream, u, up)
180
case "local": // 本机存储
181
err = d.upLocal(ctx, stream, u, up)
182
default:
183
err = errs.NotImplement
184
}
185
if err != nil {
186
// 删除失败的会话
187
_ = d.request(http.MethodDelete, "/file/upload/"+u.SessionID, nil, nil)
188
return err
189
}
190
return nil
191
}
192
193
func (d *Cloudreve) create(ctx context.Context, dir model.Obj, file model.Obj) error {
194
body := base.Json{"path": dir.GetPath() + "/" + file.GetName()}
195
if file.IsDir() {
196
err := d.request(http.MethodPut, "directory", func(req *resty.Request) {
197
req.SetBody(body)
198
}, nil)
199
return err
200
}
201
return d.request(http.MethodPost, "/file/create", func(req *resty.Request) {
202
req.SetBody(body)
203
}, nil)
204
}
205
206
//func (d *Cloudreve) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
207
// return nil, errs.NotSupport
208
//}
209
210
var _ driver.Driver = (*Cloudreve)(nil)
211
212