Skip to content

Commit a1ccfd9

Browse files
author
cyk
committed
feat(token): 更新_refreshToken方法以支持从在线API获取AppID和SignKey
1 parent 201d49f commit a1ccfd9

File tree

3 files changed

+131
-38
lines changed

3 files changed

+131
-38
lines changed

drivers/quark_open/driver.go

Lines changed: 103 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"hash"
99
"io"
1010
"net/http"
11+
"strings"
1112
"time"
1213

1314
"github.com/OpenListTeam/OpenList/v4/drivers/base"
@@ -18,6 +19,7 @@ import (
1819
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
1920
"github.com/avast/retry-go"
2021
"github.com/go-resty/resty/v2"
22+
log "github.com/sirupsen/logrus"
2123
)
2224

2325
type QuarkOpen struct {
@@ -144,30 +146,84 @@ func (d *QuarkOpen) Remove(ctx context.Context, obj model.Obj) error {
144146

145147
func (d *QuarkOpen) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
146148
md5Str, sha1Str := stream.GetHash().GetHash(utils.MD5), stream.GetHash().GetHash(utils.SHA1)
147-
var (
148-
md5 hash.Hash
149-
sha1 hash.Hash
150-
)
151-
writers := []io.Writer{}
152-
if len(md5Str) != utils.MD5.Width {
153-
md5 = utils.MD5.NewFunc()
154-
writers = append(writers, md5)
155-
}
156-
if len(sha1Str) != utils.SHA1.Width {
157-
sha1 = utils.SHA1.NewFunc()
158-
writers = append(writers, sha1)
159-
}
160149

161-
if len(writers) > 0 {
162-
_, err := stream.CacheFullAndWriter(&up, io.MultiWriter(writers...))
163-
if err != nil {
164-
return err
165-
}
166-
if md5 != nil {
167-
md5Str = hex.EncodeToString(md5.Sum(nil))
168-
}
169-
if sha1 != nil {
170-
sha1Str = hex.EncodeToString(sha1.Sum(nil))
150+
// 检查是否需要计算hash
151+
needMD5 := len(md5Str) != utils.MD5.Width
152+
needSHA1 := len(sha1Str) != utils.SHA1.Width
153+
154+
if needMD5 || needSHA1 {
155+
// 检查是否为可重复读取的流
156+
_, isSeekable := stream.(*streamPkg.SeekableStream)
157+
158+
if isSeekable {
159+
// 可重复读取的流,使用 RangeRead 一次性计算所有hash,避免重复读取
160+
var md5 hash.Hash
161+
var sha1 hash.Hash
162+
writers := []io.Writer{}
163+
164+
if needMD5 {
165+
md5 = utils.MD5.NewFunc()
166+
writers = append(writers, md5)
167+
}
168+
if needSHA1 {
169+
sha1 = utils.SHA1.NewFunc()
170+
writers = append(writers, sha1)
171+
}
172+
173+
// 使用 RangeRead 分块读取文件,同时计算多个hash
174+
multiWriter := io.MultiWriter(writers...)
175+
size := stream.GetSize()
176+
chunkSize := int64(10 * utils.MB) // 10MB per chunk
177+
buf := make([]byte, chunkSize)
178+
var offset int64 = 0
179+
180+
for offset < size {
181+
readSize := min(chunkSize, size-offset)
182+
183+
n, err := streamPkg.ReadFullWithRangeRead(stream, buf[:readSize], offset)
184+
if err != nil {
185+
return fmt.Errorf("calculate hash failed at offset %d: %w", offset, err)
186+
}
187+
188+
multiWriter.Write(buf[:n])
189+
offset += int64(n)
190+
191+
// 更新进度(hash计算占用40%的进度)
192+
up(40 * float64(offset) / float64(size))
193+
}
194+
195+
if md5 != nil {
196+
md5Str = hex.EncodeToString(md5.Sum(nil))
197+
}
198+
if sha1 != nil {
199+
sha1Str = hex.EncodeToString(sha1.Sum(nil))
200+
}
201+
} else {
202+
// 不可重复读取的流(如网络流),需要缓存并计算hash
203+
var md5 hash.Hash
204+
var sha1 hash.Hash
205+
writers := []io.Writer{}
206+
207+
if needMD5 {
208+
md5 = utils.MD5.NewFunc()
209+
writers = append(writers, md5)
210+
}
211+
if needSHA1 {
212+
sha1 = utils.SHA1.NewFunc()
213+
writers = append(writers, sha1)
214+
}
215+
216+
_, err := stream.CacheFullAndWriter(&up, io.MultiWriter(writers...))
217+
if err != nil {
218+
return err
219+
}
220+
221+
if md5 != nil {
222+
md5Str = hex.EncodeToString(md5.Sum(nil))
223+
}
224+
if sha1 != nil {
225+
sha1Str = hex.EncodeToString(sha1.Sum(nil))
226+
}
171227
}
172228
}
173229
// pre
@@ -210,24 +266,43 @@ func (d *QuarkOpen) Put(ctx context.Context, dstDir model.Obj, stream model.File
210266
if err != nil {
211267
return err
212268
}
269+
270+
// 上传重试逻辑,包含URL刷新
271+
var etag string
213272
err = retry.Do(func() error {
214273
rd.Seek(0, io.SeekStart)
215-
etag, err := d.upPart(ctx, upUrlInfo, i, driver.NewLimitedUploadStream(ctx, rd))
216-
if err != nil {
217-
return err
274+
var uploadErr error
275+
etag, uploadErr = d.upPart(ctx, upUrlInfo, i, driver.NewLimitedUploadStream(ctx, rd))
276+
277+
// 检查是否为URL过期错误
278+
if uploadErr != nil && strings.Contains(uploadErr.Error(), "expire") {
279+
log.Warnf("[quark_open] Upload URL expired for part %d, refreshing...", i)
280+
// 刷新上传URL
281+
newUpUrlInfo, refreshErr := d.upUrl(ctx, pre, partInfo)
282+
if refreshErr != nil {
283+
return fmt.Errorf("failed to refresh upload url: %w", refreshErr)
284+
}
285+
upUrlInfo = newUpUrlInfo
286+
log.Infof("[quark_open] Upload URL refreshed successfully")
287+
288+
// 使用新URL重试上传
289+
rd.Seek(0, io.SeekStart)
290+
etag, uploadErr = d.upPart(ctx, upUrlInfo, i, driver.NewLimitedUploadStream(ctx, rd))
218291
}
219-
etags = append(etags, etag)
220-
return nil
292+
293+
return uploadErr
221294
},
222295
retry.Context(ctx),
223296
retry.Attempts(3),
224297
retry.DelayType(retry.BackOffDelay),
225298
retry.Delay(time.Second))
299+
226300
ss.FreeSectionReader(rd)
227301
if err != nil {
228302
return fmt.Errorf("failed to upload part %d: %w", i, err)
229303
}
230304

305+
etags = append(etags, etag)
231306
up(95 * float64(offset+size) / float64(total))
232307
}
233308

drivers/quark_open/meta.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ type Addition struct {
1313
APIAddress string `json:"api_url_address" default:"https://api.oplist.org/quarkyun/renewapi"`
1414
AccessToken string `json:"access_token" required:"false" default:""`
1515
RefreshToken string `json:"refresh_token" required:"true"`
16-
AppID string `json:"app_id" required:"true" help:"Keep it empty if you don't have one"`
17-
SignKey string `json:"sign_key" required:"true" help:"Keep it empty if you don't have one"`
16+
AppID string `json:"app_id" required:"false" default:"" help:"Optional - Auto-filled from online API, or use your own"`
17+
SignKey string `json:"sign_key" required:"false" default:"" help:"Optional - Auto-filled from online API, or use your own"`
1818
}
1919

2020
type Conf struct {

drivers/quark_open/util.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,12 @@ func (d *QuarkOpen) upPart(ctx context.Context, upUrlInfo UpUrlInfo, partNumber
347347
}
348348
defer resp.Body.Close()
349349

350+
// 检查是否为URL过期错误(403, 410等状态码)
351+
if resp.StatusCode == 403 || resp.StatusCode == 410 {
352+
body, _ := io.ReadAll(resp.Body)
353+
return "", fmt.Errorf("upload url expired (status: %d): %s", resp.StatusCode, string(body))
354+
}
355+
350356
if resp.StatusCode != 200 {
351357
body, _ := io.ReadAll(resp.Body)
352358
return "", fmt.Errorf("up status: %d, error: %s", resp.StatusCode, string(body))
@@ -417,25 +423,36 @@ func (d *QuarkOpen) generateReqSign(method string, pathname string, signKey stri
417423
}
418424

419425
func (d *QuarkOpen) refreshToken() error {
420-
refresh, access, err := d._refreshToken()
426+
refresh, access, appID, signKey, err := d._refreshToken()
421427
for i := 0; i < 3; i++ {
422428
if err == nil {
423429
break
424430
} else {
425431
log.Errorf("[quark_open] failed to refresh token: %s", err)
426432
}
427-
refresh, access, err = d._refreshToken()
433+
refresh, access, appID, signKey, err = d._refreshToken()
428434
}
429435
if err != nil {
430436
return err
431437
}
432438
log.Infof("[quark_open] token exchange: %s -> %s", d.RefreshToken, refresh)
433439
d.RefreshToken, d.AccessToken = refresh, access
440+
441+
// 如果在线API返回了AppID和SignKey,保存它们(不为空时才更新)
442+
if appID != "" && appID != d.AppID {
443+
d.AppID = appID
444+
log.Infof("[quark_open] AppID updated from online API: %s", appID)
445+
}
446+
if signKey != "" && signKey != d.SignKey {
447+
d.SignKey = signKey
448+
log.Infof("[quark_open] SignKey updated from online API")
449+
}
450+
434451
op.MustSaveDriverStorage(d)
435452
return nil
436453
}
437454

438-
func (d *QuarkOpen) _refreshToken() (string, string, error) {
455+
func (d *QuarkOpen) _refreshToken() (string, string, string, string, error) {
439456
if d.UseOnlineAPI && d.APIAddress != "" {
440457
u := d.APIAddress
441458
var resp RefreshTokenOnlineAPIResp
@@ -448,19 +465,20 @@ func (d *QuarkOpen) _refreshToken() (string, string, error) {
448465
}).
449466
Get(u)
450467
if err != nil {
451-
return "", "", err
468+
return "", "", "", "", err
452469
}
453470
if resp.RefreshToken == "" || resp.AccessToken == "" {
454471
if resp.ErrorMessage != "" {
455-
return "", "", fmt.Errorf("failed to refresh token: %s", resp.ErrorMessage)
472+
return "", "", "", "", fmt.Errorf("failed to refresh token: %s", resp.ErrorMessage)
456473
}
457-
return "", "", fmt.Errorf("empty token returned from official API, a wrong refresh token may have been used")
474+
return "", "", "", "", fmt.Errorf("empty token returned from official API, a wrong refresh token may have been used")
458475
}
459-
return resp.RefreshToken, resp.AccessToken, nil
476+
// 返回所有字段,包括AppID和SignKey
477+
return resp.RefreshToken, resp.AccessToken, resp.AppID, resp.SignKey, nil
460478
}
461479

462480
// TODO 本地刷新逻辑
463-
return "", "", fmt.Errorf("local refresh token logic is not implemented yet, please use online API or contact the developer")
481+
return "", "", "", "", fmt.Errorf("local refresh token logic is not implemented yet, please use online API or contact the developer")
464482
}
465483

466484
// 生成认证 Cookie

0 commit comments

Comments
 (0)