Skip to content

Commit 319502b

Browse files
committed
doubao
1 parent 139900d commit 319502b

4 files changed

Lines changed: 92 additions & 43 deletions

File tree

drivers/123/upload.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func (d *Pan123) newUpload(ctx context.Context, upReq *UploadResp, file model.Fi
122122
if cur == chunkCount {
123123
curSize = lastChunkSize
124124
}
125-
var reader io.ReadSeeker
125+
var reader *stream.SectionReader
126126
var rateLimitedRd io.Reader
127127
threadG.GoWithResult(func(ctx context.Context) error {
128128
if reader == nil {

drivers/123_open/upload.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
9898
partNumber := partIndex + 1 // 分片号从1开始
9999
offset := partIndex * chunkSize
100100
size := min(chunkSize, size-offset)
101-
var reader io.ReadSeeker
101+
var reader *stream.SectionReader
102102
var rateLimitedRd io.Reader
103103
threadG.GoWithResult(func(ctx context.Context) error {
104104
if reader == nil {
@@ -132,9 +132,7 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes
132132
up(progress)
133133
return nil
134134
}, func(err error) {
135-
if reader != nil {
136-
ss.RecycleSectionReader(reader)
137-
}
135+
ss.RecycleSectionReader(reader)
138136
})
139137
}
140138

drivers/doubao/util.go

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/OpenListTeam/OpenList/v4/drivers/base"
2525
"github.com/OpenListTeam/OpenList/v4/internal/driver"
2626
"github.com/OpenListTeam/OpenList/v4/internal/model"
27+
"github.com/OpenListTeam/OpenList/v4/internal/stream"
2728
"github.com/OpenListTeam/OpenList/v4/pkg/errgroup"
2829
"github.com/OpenListTeam/OpenList/v4/pkg/utils"
2930
"github.com/avast/retry-go"
@@ -519,57 +520,84 @@ func (d *Doubao) UploadByMultipart(ctx context.Context, config *UploadConfig, fi
519520
totalParts := (fileSize + chunkSize - 1) / chunkSize
520521
// 创建分片信息组
521522
parts := make([]UploadPart, totalParts)
522-
// 缓存文件
523-
tempFile, err := file.CacheFullInTempFile()
523+
524+
// 用 stream.NewStreamSectionReader 替代缓存临时文件
525+
ss, err := stream.NewStreamSectionReader(file, int(chunkSize))
524526
if err != nil {
525-
return nil, fmt.Errorf("failed to cache file: %w", err)
527+
return nil, fmt.Errorf("failed to create section reader: %w", err)
526528
}
527529
up(10.0) // 更新进度
528530
// 设置并行上传
529-
threadG, uploadCtx := errgroup.NewGroupWithContext(ctx, d.uploadThread,
530-
retry.Attempts(1),
531+
thread := min(int(totalParts), d.uploadThread)
532+
threadG, uploadCtx := errgroup.NewGroupWithContext(ctx, thread,
533+
retry.Attempts(3),
531534
retry.Delay(time.Second),
532535
retry.DelayType(retry.BackOffDelay))
533536

534537
var partsMutex sync.Mutex
535538
// 并行上传所有分片
536-
for partIndex := int64(0); partIndex < totalParts; partIndex++ {
539+
for partIndex := range totalParts {
537540
if utils.IsCanceled(uploadCtx) {
538541
break
539542
}
540-
partIndex := partIndex
541543
partNumber := partIndex + 1 // 分片编号从1开始
542544

543-
threadG.Go(func(ctx context.Context) error {
544-
// 计算此分片的大小和偏移
545-
offset := partIndex * chunkSize
546-
size := chunkSize
547-
if partIndex == totalParts-1 {
548-
size = fileSize - offset
549-
}
545+
// 计算此分片的大小和偏移
546+
offset := partIndex * chunkSize
547+
size := chunkSize
548+
if partIndex == totalParts-1 {
549+
size = fileSize - offset
550+
}
550551

551-
limitedReader := driver.NewLimitedUploadStream(ctx, io.NewSectionReader(tempFile, offset, size))
552-
// 读取数据到内存
553-
data, err := io.ReadAll(limitedReader)
554-
if err != nil {
555-
return fmt.Errorf("failed to read part %d: %w", partNumber, err)
552+
var reader *stream.SectionReader
553+
var rateLimitedRd io.Reader
554+
threadG.GoWithResult(func(ctx context.Context) error {
555+
if reader == nil {
556+
var err error
557+
reader, err = ss.GetSectionReader(offset, size)
558+
if err != nil {
559+
return err
560+
}
561+
rateLimitedRd = driver.NewLimitedUploadStream(ctx, reader)
556562
}
563+
reader.Seek(0, io.SeekStart)
557564
// 计算CRC32
558-
crc32Value := calculateCRC32(data)
565+
crc32Value := calculateCRC32(reader)
559566
// 使用_retryOperation上传分片
560-
var uploadPart UploadPart
561-
if err = d._retryOperation(fmt.Sprintf("Upload part %d", partNumber), func() error {
562-
var err error
563-
uploadPart, err = d.uploadPart(config, uploadUrl, uploadID, partNumber, data, crc32Value)
567+
reader.Seek(0, io.SeekStart)
568+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, fmt.Sprintf("%s?uploadid=%s&part_number=%d&phase=transfer", uploadUrl, uploadID, partNumber), rateLimitedRd)
569+
if err != nil {
570+
return err
571+
}
572+
req.Header = map[string][]string{
573+
"Referer": {BaseURL + "/"},
574+
"Origin": {BaseURL},
575+
"User-Agent": {UserAgent},
576+
"X-Storage-U": {d.UserId},
577+
"Authorization": {storeInfo.Auth},
578+
"Content-Type": {"application/octet-stream"},
579+
"Content-Crc32": {crc32Value},
580+
"Content-Length": {fmt.Sprintf("%d", size)},
581+
"Content-Disposition": {fmt.Sprintf("attachment; filename=%s", url.QueryEscape(storeInfo.StoreURI))},
582+
}
583+
res, err := base.HttpClient.Do(req)
584+
if err != nil {
564585
return err
565-
}); err != nil {
566-
return fmt.Errorf("part %d upload failed: %w", partNumber, err)
586+
}
587+
defer res.Body.Close()
588+
bytes, _ := io.ReadAll(res.Body)
589+
uploadResp := UploadResp{}
590+
utils.Json.Unmarshal(bytes, &uploadResp)
591+
if uploadResp.Code != 2000 {
592+
return fmt.Errorf("upload part failed: %s", uploadResp.Message)
593+
} else if uploadResp.Data.Crc32 != crc32Value {
594+
return fmt.Errorf("upload part failed: crc32 mismatch, expected %s, got %s", crc32Value, uploadResp.Data.Crc32)
567595
}
568596
// 记录成功上传的分片
569597
partsMutex.Lock()
570598
parts[partIndex] = UploadPart{
571599
PartNumber: strconv.FormatInt(partNumber, 10),
572-
Etag: uploadPart.Etag,
600+
Etag: uploadResp.Data.Etag,
573601
Crc32: crc32Value,
574602
}
575603
partsMutex.Unlock()
@@ -578,6 +606,8 @@ func (d *Doubao) UploadByMultipart(ctx context.Context, config *UploadConfig, fi
578606
up(math.Min(progress, 95.0))
579607

580608
return nil
609+
}, func(err error) {
610+
ss.RecycleSectionReader(reader)
581611
})
582612
}
583613

@@ -785,9 +815,9 @@ func (d *Doubao) commitMultipartUpload(uploadConfig *UploadConfig) error {
785815
}
786816

787817
// 计算CRC32
788-
func calculateCRC32(data []byte) string {
818+
func calculateCRC32(rs io.Reader) string {
789819
hash := crc32.NewIEEE()
790-
hash.Write(data)
820+
utils.CopyWithBuffer(hash, rs)
791821
return hex.EncodeToString(hash.Sum(nil))
792822
}
793823

internal/stream/util.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func CacheFullInTempFileAndHash(stream model.FileStreamer, hashType *utils.HashT
146146
type StreamSectionReader struct {
147147
file model.FileStreamer
148148
off int64
149-
m sync.Mutex
149+
mu sync.Mutex
150150
bufPool *sync.Pool
151151
}
152152

@@ -169,9 +169,9 @@ func NewStreamSectionReader(file model.FileStreamer, bufMaxLen int) (*StreamSect
169169
return ss, nil
170170
}
171171

172-
func (ss *StreamSectionReader) GetSectionReader(off, length int64) (io.ReadSeeker, error) {
173-
ss.m.Lock()
174-
defer ss.m.Unlock()
172+
func (ss *StreamSectionReader) GetSectionReader(off, length int64) (*SectionReader, error) {
173+
ss.mu.Lock()
174+
defer ss.mu.Unlock()
175175
var cache io.ReaderAt = ss.file.GetFile()
176176
var buf []byte
177177
if cache == nil {
@@ -194,18 +194,39 @@ func (ss *StreamSectionReader) GetSectionReader(off, length int64) (io.ReadSeeke
194194
return &SectionReader{io.NewSectionReader(cache, off, length), buf}, nil
195195
}
196196

197-
func (ss *StreamSectionReader) RecycleSectionReader(rs io.ReadSeeker) {
198-
ss.m.Lock()
199-
defer ss.m.Unlock()
200-
if sr, ok := rs.(*SectionReader); ok {
197+
func (ss *StreamSectionReader) RecycleSectionReader(sr *SectionReader) {
198+
if sr != nil {
199+
ss.mu.Lock()
200+
defer ss.mu.Unlock()
201201
if sr.buf != nil {
202-
ss.bufPool.Put(sr.buf)
202+
ss.bufPool.Put(sr.buf[0:cap(sr.buf)])
203203
sr.buf = nil
204204
}
205205
sr.ReadSeeker = nil
206206
}
207207
}
208208

209+
// func (ss *StreamSectionReader) GetBytes(sr *SectionReader) ([]byte, error) {
210+
// if sr != nil && ss.bufPool != nil {
211+
// ss.mu.Lock()
212+
// defer ss.mu.Unlock()
213+
// buf := sr.buf
214+
// if buf == nil {
215+
// buf := ss.bufPool.Get().([]byte)
216+
// n, err := io.ReadFull(sr, buf)
217+
// if err == io.EOF && n > 0 {
218+
// err = nil
219+
// }
220+
// if err != nil {
221+
// return nil, err
222+
// }
223+
// sr.buf = buf[:n]
224+
// }
225+
// return sr.buf, nil
226+
// }
227+
// return nil, errors.New("SectionReader is nil")
228+
// }
229+
209230
type SectionReader struct {
210231
io.ReadSeeker
211232
buf []byte

0 commit comments

Comments
 (0)