Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alist-org
GitHub Repository: alist-org/alist
Path: blob/main/drivers/115_open/driver.go
1986 views
1
package _115_open
2
3
import (
4
"context"
5
"fmt"
6
"io"
7
"net/http"
8
"strconv"
9
"strings"
10
"time"
11
12
"github.com/alist-org/alist/v3/cmd/flags"
13
"github.com/alist-org/alist/v3/drivers/base"
14
"github.com/alist-org/alist/v3/internal/driver"
15
"github.com/alist-org/alist/v3/internal/model"
16
"github.com/alist-org/alist/v3/internal/op"
17
"github.com/alist-org/alist/v3/pkg/utils"
18
sdk "github.com/xhofe/115-sdk-go"
19
"golang.org/x/time/rate"
20
)
21
22
type Open115 struct {
23
model.Storage
24
Addition
25
client *sdk.Client
26
limiter *rate.Limiter
27
}
28
29
func (d *Open115) Config() driver.Config {
30
return config
31
}
32
33
func (d *Open115) GetAddition() driver.Additional {
34
return &d.Addition
35
}
36
37
func (d *Open115) Init(ctx context.Context) error {
38
d.client = sdk.New(sdk.WithRefreshToken(d.Addition.RefreshToken),
39
sdk.WithAccessToken(d.Addition.AccessToken),
40
sdk.WithOnRefreshToken(func(s1, s2 string) {
41
d.Addition.AccessToken = s1
42
d.Addition.RefreshToken = s2
43
op.MustSaveDriverStorage(d)
44
}))
45
if flags.Debug || flags.Dev {
46
d.client.SetDebug(true)
47
}
48
_, err := d.client.UserInfo(ctx)
49
if err != nil {
50
return err
51
}
52
if d.Addition.LimitRate > 0 {
53
d.limiter = rate.NewLimiter(rate.Limit(d.Addition.LimitRate), 1)
54
}
55
return nil
56
}
57
58
func (d *Open115) WaitLimit(ctx context.Context) error {
59
if d.limiter != nil {
60
return d.limiter.Wait(ctx)
61
}
62
return nil
63
}
64
65
func (d *Open115) Drop(ctx context.Context) error {
66
return nil
67
}
68
69
func (d *Open115) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) {
70
var res []model.Obj
71
pageSize := int64(200)
72
offset := int64(0)
73
for {
74
if err := d.WaitLimit(ctx); err != nil {
75
return nil, err
76
}
77
resp, err := d.client.GetFiles(ctx, &sdk.GetFilesReq{
78
CID: dir.GetID(),
79
Limit: pageSize,
80
Offset: offset,
81
ASC: d.Addition.OrderDirection == "asc",
82
O: d.Addition.OrderBy,
83
// Cur: 1,
84
ShowDir: true,
85
})
86
if err != nil {
87
return nil, err
88
}
89
res = append(res, utils.MustSliceConvert(resp.Data, func(src sdk.GetFilesResp_File) model.Obj {
90
obj := Obj(src)
91
return &obj
92
})...)
93
if len(res) >= int(resp.Count) {
94
break
95
}
96
offset += pageSize
97
}
98
return res, nil
99
}
100
101
func (d *Open115) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) {
102
if err := d.WaitLimit(ctx); err != nil {
103
return nil, err
104
}
105
var ua string
106
if args.Header != nil {
107
ua = args.Header.Get("User-Agent")
108
}
109
if ua == "" {
110
ua = base.UserAgent
111
}
112
obj, ok := file.(*Obj)
113
if !ok {
114
return nil, fmt.Errorf("can't convert obj")
115
}
116
pc := obj.Pc
117
resp, err := d.client.DownURL(ctx, pc, ua)
118
if err != nil {
119
return nil, err
120
}
121
u, ok := resp[obj.GetID()]
122
if !ok {
123
return nil, fmt.Errorf("can't get link")
124
}
125
return &model.Link{
126
URL: u.URL.URL,
127
Header: http.Header{
128
"User-Agent": []string{ua},
129
},
130
}, nil
131
}
132
133
func (d *Open115) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
134
if err := d.WaitLimit(ctx); err != nil {
135
return nil, err
136
}
137
resp, err := d.client.Mkdir(ctx, parentDir.GetID(), dirName)
138
if err != nil {
139
return nil, err
140
}
141
return &Obj{
142
Fid: resp.FileID,
143
Pid: parentDir.GetID(),
144
Fn: dirName,
145
Fc: "0",
146
Upt: time.Now().Unix(),
147
Uet: time.Now().Unix(),
148
UpPt: time.Now().Unix(),
149
}, nil
150
}
151
152
func (d *Open115) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
153
if err := d.WaitLimit(ctx); err != nil {
154
return nil, err
155
}
156
_, err := d.client.Move(ctx, &sdk.MoveReq{
157
FileIDs: srcObj.GetID(),
158
ToCid: dstDir.GetID(),
159
})
160
if err != nil {
161
return nil, err
162
}
163
return srcObj, nil
164
}
165
166
func (d *Open115) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
167
if err := d.WaitLimit(ctx); err != nil {
168
return nil, err
169
}
170
_, err := d.client.UpdateFile(ctx, &sdk.UpdateFileReq{
171
FileID: srcObj.GetID(),
172
FileNma: newName,
173
})
174
if err != nil {
175
return nil, err
176
}
177
obj, ok := srcObj.(*Obj)
178
if ok {
179
obj.Fn = newName
180
}
181
return srcObj, nil
182
}
183
184
func (d *Open115) Copy(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
185
if err := d.WaitLimit(ctx); err != nil {
186
return nil, err
187
}
188
_, err := d.client.Copy(ctx, &sdk.CopyReq{
189
PID: dstDir.GetID(),
190
FileID: srcObj.GetID(),
191
NoDupli: "1",
192
})
193
if err != nil {
194
return nil, err
195
}
196
return srcObj, nil
197
}
198
199
func (d *Open115) Remove(ctx context.Context, obj model.Obj) error {
200
if err := d.WaitLimit(ctx); err != nil {
201
return err
202
}
203
_obj, ok := obj.(*Obj)
204
if !ok {
205
return fmt.Errorf("can't convert obj")
206
}
207
_, err := d.client.DelFile(ctx, &sdk.DelFileReq{
208
FileIDs: _obj.GetID(),
209
ParentID: _obj.Pid,
210
})
211
if err != nil {
212
return err
213
}
214
return nil
215
}
216
217
func (d *Open115) Put(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) error {
218
if err := d.WaitLimit(ctx); err != nil {
219
return err
220
}
221
tempF, err := file.CacheFullInTempFile()
222
if err != nil {
223
return err
224
}
225
// cal full sha1
226
sha1, err := utils.HashReader(utils.SHA1, tempF)
227
if err != nil {
228
return err
229
}
230
_, err = tempF.Seek(0, io.SeekStart)
231
if err != nil {
232
return err
233
}
234
// pre 128k sha1
235
sha1128k, err := utils.HashReader(utils.SHA1, io.LimitReader(tempF, 128*1024))
236
if err != nil {
237
return err
238
}
239
_, err = tempF.Seek(0, io.SeekStart)
240
if err != nil {
241
return err
242
}
243
// 1. Init
244
resp, err := d.client.UploadInit(ctx, &sdk.UploadInitReq{
245
FileName: file.GetName(),
246
FileSize: file.GetSize(),
247
Target: dstDir.GetID(),
248
FileID: strings.ToUpper(sha1),
249
PreID: strings.ToUpper(sha1128k),
250
})
251
if err != nil {
252
return err
253
}
254
if resp.Status == 2 {
255
return nil
256
}
257
// 2. two way verify
258
if utils.SliceContains([]int{6, 7, 8}, resp.Status) {
259
signCheck := strings.Split(resp.SignCheck, "-") //"sign_check": "2392148-2392298" 取2392148-2392298之间的内容(包含2392148、2392298)的sha1
260
start, err := strconv.ParseInt(signCheck[0], 10, 64)
261
if err != nil {
262
return err
263
}
264
end, err := strconv.ParseInt(signCheck[1], 10, 64)
265
if err != nil {
266
return err
267
}
268
_, err = tempF.Seek(start, io.SeekStart)
269
if err != nil {
270
return err
271
}
272
signVal, err := utils.HashReader(utils.SHA1, io.LimitReader(tempF, end-start+1))
273
if err != nil {
274
return err
275
}
276
_, err = tempF.Seek(0, io.SeekStart)
277
if err != nil {
278
return err
279
}
280
resp, err = d.client.UploadInit(ctx, &sdk.UploadInitReq{
281
FileName: file.GetName(),
282
FileSize: file.GetSize(),
283
Target: dstDir.GetID(),
284
FileID: strings.ToUpper(sha1),
285
PreID: strings.ToUpper(sha1128k),
286
SignKey: resp.SignKey,
287
SignVal: strings.ToUpper(signVal),
288
})
289
if err != nil {
290
return err
291
}
292
if resp.Status == 2 {
293
return nil
294
}
295
}
296
// 3. get upload token
297
tokenResp, err := d.client.UploadGetToken(ctx)
298
if err != nil {
299
return err
300
}
301
// 4. upload
302
err = d.multpartUpload(ctx, tempF, file, up, tokenResp, resp)
303
if err != nil {
304
return err
305
}
306
return nil
307
}
308
309
// func (d *Open115) GetArchiveMeta(ctx context.Context, obj model.Obj, args model.ArchiveArgs) (model.ArchiveMeta, error) {
310
// // TODO get archive file meta-info, return errs.NotImplement to use an internal archive tool, optional
311
// return nil, errs.NotImplement
312
// }
313
314
// func (d *Open115) ListArchive(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) ([]model.Obj, error) {
315
// // TODO list args.InnerPath in the archive obj, return errs.NotImplement to use an internal archive tool, optional
316
// return nil, errs.NotImplement
317
// }
318
319
// func (d *Open115) Extract(ctx context.Context, obj model.Obj, args model.ArchiveInnerArgs) (*model.Link, error) {
320
// // TODO return link of file args.InnerPath in the archive obj, return errs.NotImplement to use an internal archive tool, optional
321
// return nil, errs.NotImplement
322
// }
323
324
// func (d *Open115) ArchiveDecompress(ctx context.Context, srcObj, dstDir model.Obj, args model.ArchiveDecompressArgs) ([]model.Obj, error) {
325
// // TODO extract args.InnerPath path in the archive srcObj to the dstDir location, optional
326
// // a folder with the same name as the archive file needs to be created to store the extracted results if args.PutIntoNewDir
327
// // return errs.NotImplement to use an internal archive tool
328
// return nil, errs.NotImplement
329
// }
330
331
//func (d *Template) Other(ctx context.Context, args model.OtherArgs) (interface{}, error) {
332
// return nil, errs.NotSupport
333
//}
334
335
var _ driver.Driver = (*Open115)(nil)
336
337