Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/123_open/driver.go
1986 views
1
package _123Open
2
3
import (
4
"context"
5
"fmt"
6
"github.com/alist-org/alist/v3/internal/driver"
7
"github.com/alist-org/alist/v3/internal/errs"
8
"github.com/alist-org/alist/v3/internal/model"
9
"github.com/alist-org/alist/v3/internal/stream"
10
"github.com/alist-org/alist/v3/pkg/utils"
11
"github.com/go-resty/resty/v2"
12
"net/http"
13
"strconv"
14
"time"
15
)
16
17
type Open123 struct {
18
model.Storage
19
Addition
20
21
UploadThread int
22
tm *tokenManager
23
}
24
25
func (d *Open123) Config() driver.Config {
26
return config
27
}
28
29
func (d *Open123) GetAddition() driver.Additional {
30
return &d.Addition
31
}
32
33
func (d *Open123) Init(ctx context.Context) error {
34
d.tm = newTokenManager(d.ClientID, d.ClientSecret)
35
36
if _, err := d.tm.getToken(); err != nil {
37
return fmt.Errorf("token 初始化失败: %w", err)
38
}
39
40
return nil
41
}
42
43
func (d *Open123) Drop(ctx context.Context) error {
44
return nil
45
}
46
47
func (d *Open123) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
48
parentFileId, err := strconv.ParseInt(dir.GetID(), 10, 64)
49
if err != nil {
50
return nil, err
51
}
52
53
fileLastId := int64(0)
54
var results []File
55
56
for fileLastId != -1 {
57
files, err := d.getFiles(parentFileId, 100, fileLastId)
58
if err != nil {
59
return nil, err
60
}
61
for _, f := range files.Data.FileList {
62
if f.Trashed == 0 {
63
results = append(results, f)
64
}
65
}
66
fileLastId = files.Data.LastFileId
67
}
68
69
objs := make([]model.Obj, 0, len(results))
70
for _, f := range results {
71
objs = append(objs, f)
72
}
73
return objs, nil
74
}
75
76
func (d *Open123) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
77
if file.IsDir() {
78
return nil, errs.LinkIsDir
79
}
80
81
fileID := file.GetID()
82
83
var result DirectLinkResp
84
url := fmt.Sprintf("%s?fileID=%s", ApiGetDirectLink, fileID)
85
_, err := d.Request(url, http.MethodGet, nil, &result)
86
if err != nil {
87
return nil, err
88
}
89
if result.Code != 0 {
90
return nil, fmt.Errorf("get link failed: %s", result.Message)
91
}
92
93
linkURL := result.Data.URL
94
if d.PrivateKey != "" {
95
if d.UID == 0 {
96
return nil, fmt.Errorf("uid is required when private key is set")
97
}
98
duration := time.Duration(d.ValidDuration)
99
if duration <= 0 {
100
duration = 30
101
}
102
signedURL, err := SignURL(linkURL, d.PrivateKey, d.UID, duration*time.Minute)
103
if err != nil {
104
return nil, err
105
}
106
linkURL = signedURL
107
}
108
109
return &model.Link{
110
URL: linkURL,
111
}, nil
112
}
113
114
func (d *Open123) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
115
parentID, err := strconv.ParseInt(parentDir.GetID(), 10, 64)
116
if err != nil {
117
return nil, fmt.Errorf("invalid parent ID: %w", err)
118
}
119
120
var result MakeDirResp
121
reqBody := MakeDirRequest{
122
Name: dirName,
123
ParentID: parentID,
124
}
125
126
_, err = d.Request(ApiMakeDir, http.MethodPost, func(r *resty.Request) {
127
r.SetBody(reqBody)
128
}, &result)
129
if err != nil {
130
return nil, err
131
}
132
if result.Code != 0 {
133
return nil, fmt.Errorf("mkdir failed: %s", result.Message)
134
}
135
136
newDir := File{
137
FileId: result.Data.DirID,
138
FileName: dirName,
139
Type: 1,
140
ParentFileId: int(parentID),
141
Size: 0,
142
Trashed: 0,
143
}
144
return newDir, nil
145
}
146
147
func (d *Open123) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
148
srcID, err := strconv.ParseInt(srcObj.GetID(), 10, 64)
149
if err != nil {
150
return nil, fmt.Errorf("invalid src file ID: %w", err)
151
}
152
dstID, err := strconv.ParseInt(dstDir.GetID(), 10, 64)
153
if err != nil {
154
return nil, fmt.Errorf("invalid dest dir ID: %w", err)
155
}
156
157
var result Response[any]
158
reqBody := map[string]interface{}{
159
"fileIDs": []int64{srcID},
160
"toParentFileID": dstID,
161
}
162
163
_, err = d.Request(ApiMove, http.MethodPost, func(r *resty.Request) {
164
r.SetBody(reqBody)
165
}, &result)
166
if err != nil {
167
return nil, err
168
}
169
if result.Code != 0 {
170
return nil, fmt.Errorf("move failed: %s", result.Message)
171
}
172
173
files, err := d.getFiles(dstID, 100, 0)
174
if err != nil {
175
return nil, fmt.Errorf("move succeed but failed to get target dir: %w", err)
176
}
177
for _, f := range files.Data.FileList {
178
if f.FileId == srcID {
179
return f, nil
180
}
181
}
182
return nil, fmt.Errorf("move succeed but file not found in target dir")
183
}
184
185
func (d *Open123) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
186
srcID, err := strconv.ParseInt(srcObj.GetID(), 10, 64)
187
if err != nil {
188
return nil, fmt.Errorf("invalid file ID: %w", err)
189
}
190
191
var result Response[any]
192
reqBody := map[string]interface{}{
193
"fileId": srcID,
194
"fileName": newName,
195
}
196
197
_, err = d.Request(ApiRename, http.MethodPut, func(r *resty.Request) {
198
r.SetBody(reqBody)
199
}, &result)
200
if err != nil {
201
return nil, err
202
}
203
if result.Code != 0 {
204
return nil, fmt.Errorf("rename failed: %s", result.Message)
205
}
206
207
parentID := 0
208
if file, ok := srcObj.(File); ok {
209
parentID = file.ParentFileId
210
}
211
files, err := d.getFiles(int64(parentID), 100, 0)
212
if err != nil {
213
return nil, fmt.Errorf("rename succeed but failed to get parent dir: %w", err)
214
}
215
for _, f := range files.Data.FileList {
216
if f.FileId == srcID {
217
return f, nil
218
}
219
}
220
return nil, fmt.Errorf("rename succeed but file not found in parent dir")
221
}
222
223
func (d *Open123) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
224
return nil, errs.NotSupport
225
}
226
227
func (d *Open123) Remove(ctx context.Context, obj model.Obj) error {
228
idStr := obj.GetID()
229
id, err := strconv.ParseInt(idStr, 10, 64)
230
if err != nil {
231
return fmt.Errorf("invalid file ID: %w", err)
232
}
233
234
var result Response[any]
235
reqBody := RemoveRequest{
236
FileIDs: []int64{id},
237
}
238
239
_, err = d.Request(ApiRemove, http.MethodPost, func(r *resty.Request) {
240
r.SetBody(reqBody)
241
}, &result)
242
if err != nil {
243
return err
244
}
245
if result.Code != 0 {
246
return fmt.Errorf("remove failed: %s", result.Message)
247
}
248
249
return nil
250
}
251
252
func (d *Open123) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) error {
253
parentFileId, err := strconv.ParseInt(dstDir.GetID(), 10, 64)
254
etag := file.GetHash().GetHash(utils.MD5)
255
256
if len(etag) < utils.MD5.Width {
257
up = model.UpdateProgressWithRange(up, 50, 100)
258
_, etag, err = stream.CacheFullInTempFileAndHash(file, utils.MD5)
259
if err != nil {
260
return err
261
}
262
}
263
createResp, err := d.create(parentFileId, file.GetName(), etag, file.GetSize(), 2, false)
264
if err != nil {
265
return err
266
}
267
if createResp.Data.Reuse {
268
return nil
269
}
270
271
return d.Upload(ctx, file, parentFileId, createResp, up)
272
}
273
274
func (d *Open123) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {
275
return nil, errs.NotSupport
276
}
277
278
func (d *Open123) ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error) {
279
return nil, errs.NotSupport
280
}
281
282
func (d *Open123) Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error) {
283
return nil, errs.NotSupport
284
}
285
286
func (d *Open123) ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error) {
287
return nil, errs.NotSupport
288
}
289
290
//func (d *Open123) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
291
// return nil, errs.NotSupport
292
//}
293
294
var _ driver.Driver = (*Open123)(nil)
295
296