-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(123_open): update upload api v2 #976
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,14 @@ | ||
| package _123_open | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "mime/multipart" | ||
| "net/http" | ||
| "strconv" | ||
| "strings" | ||
| "time" | ||
|
|
||
|
|
@@ -17,6 +22,7 @@ import ( | |
| "github.com/go-resty/resty/v2" | ||
| ) | ||
|
|
||
| // 创建文件 V2 | ||
| func (d *Open123) create(parentFileID int64, filename string, etag string, size int64, duplicate int, containDir bool) (*UploadCreateResp, error) { | ||
| var resp UploadCreateResp | ||
| _, err := d.Request(UploadCreate, http.MethodPost, func(req *resty.Request) { | ||
|
|
@@ -35,48 +41,9 @@ func (d *Open123) create(parentFileID int64, filename string, etag string, size | |
| return &resp, nil | ||
| } | ||
|
|
||
| func (d *Open123) url(preuploadID string, sliceNo int64) (string, error) { | ||
| // get upload url | ||
| var resp UploadUrlResp | ||
| _, err := d.Request(UploadUrl, http.MethodPost, func(req *resty.Request) { | ||
| req.SetBody(base.Json{ | ||
| "preuploadId": preuploadID, | ||
| "sliceNo": sliceNo, | ||
| }) | ||
| }, &resp) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| return resp.Data.PresignedURL, nil | ||
| } | ||
|
|
||
| func (d *Open123) complete(preuploadID string) (*UploadCompleteResp, error) { | ||
| var resp UploadCompleteResp | ||
| _, err := d.Request(UploadComplete, http.MethodPost, func(req *resty.Request) { | ||
| req.SetBody(base.Json{ | ||
| "preuploadID": preuploadID, | ||
| }) | ||
| }, &resp) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return &resp, nil | ||
| } | ||
|
|
||
| func (d *Open123) async(preuploadID string) (*UploadAsyncResp, error) { | ||
| var resp UploadAsyncResp | ||
| _, err := d.Request(UploadAsync, http.MethodPost, func(req *resty.Request) { | ||
| req.SetBody(base.Json{ | ||
| "preuploadID": preuploadID, | ||
| }) | ||
| }, &resp) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return &resp, nil | ||
| } | ||
|
|
||
| // 上传分片 V2 | ||
| func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createResp *UploadCreateResp, up driver.UpdateProgress) error { | ||
| uploadDomain := createResp.Data.Servers[0] | ||
| size := file.GetSize() | ||
| chunkSize := createResp.Data.SliceSize | ||
| uploadNums := (size + chunkSize - 1) / chunkSize | ||
|
|
@@ -90,7 +57,7 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes | |
| if err != nil { | ||
| return err | ||
| } | ||
| for partIndex := int64(0); partIndex < uploadNums; partIndex++ { | ||
| for partIndex := range uploadNums { | ||
|
xrgzs marked this conversation as resolved.
|
||
| if utils.IsCanceled(uploadCtx) { | ||
| break | ||
| } | ||
|
|
@@ -100,36 +67,90 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes | |
| size := min(chunkSize, size-offset) | ||
| var reader *stream.SectionReader | ||
| var rateLimitedRd io.Reader | ||
| sliceMD5 := "" | ||
| threadG.GoWithLifecycle(errgroup.Lifecycle{ | ||
| Before: func(ctx context.Context) error { | ||
| if reader == nil { | ||
| var err error | ||
| // 每个分片一个reader | ||
| reader, err = ss.GetSectionReader(offset, size) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // 计算当前分片的MD5 | ||
| sliceMD5, err = utils.HashReader(utils.MD5, reader) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| rateLimitedRd = driver.NewLimitedUploadStream(ctx, reader) | ||
| } | ||
| return nil | ||
| }, | ||
| Do: func(ctx context.Context) error { | ||
| // 重置分片reader位置,因为HashReader、上一次失败已经读取到分片EOF | ||
| reader.Seek(0, io.SeekStart) | ||
| uploadPartUrl, err := d.url(createResp.Data.PreuploadID, partNumber) | ||
|
|
||
| // 创建表单数据 | ||
| var b bytes.Buffer | ||
| w := multipart.NewWriter(&b) | ||
| // 添加表单字段 | ||
| err = w.WriteField("preuploadID", createResp.Data.PreuploadID) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = w.WriteField("sliceNo", strconv.FormatInt(partNumber, 10)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = w.WriteField("sliceMD5", sliceMD5) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // 写入文件内容 | ||
| fw, err := w.CreateFormFile("slice", fmt.Sprintf("%s.part%d", file.GetName(), partNumber)) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| _, err = utils.CopyWithBuffer(fw, rateLimitedRd) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 为什么要用v2?v2支有表单吗?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. V2 只有表单 用
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| if err != nil { | ||
| return err | ||
| } | ||
| err = w.Close() | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| req, err := http.NewRequestWithContext(ctx, http.MethodPut, uploadPartUrl, rateLimitedRd) | ||
| // 创建请求并设置header | ||
| req, err := http.NewRequestWithContext(ctx, http.MethodPost, uploadDomain+"/upload/v2/file/slice", &b) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| req.ContentLength = size | ||
|
|
||
| // 设置请求头 | ||
| req.Header.Add("Authorization", "Bearer "+d.AccessToken) | ||
| req.Header.Add("Content-Type", w.FormDataContentType()) | ||
| req.Header.Add("Platform", "open_platform") | ||
|
|
||
| res, err := base.HttpClient.Do(req) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| _ = res.Body.Close() | ||
| defer res.Body.Close() | ||
| if res.StatusCode != 200 { | ||
| return fmt.Errorf("slice %d upload failed, status code: %d", partNumber, res.StatusCode) | ||
| } | ||
| var resp BaseResp | ||
| respBody, err := io.ReadAll(res.Body) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| err = json.Unmarshal(respBody, &resp) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if resp.Code != 0 { | ||
| return fmt.Errorf("slice %d upload failed: %s", partNumber, resp.Message) | ||
| } | ||
|
|
||
| progress := 10.0 + 85.0*float64(threadG.Success())/float64(uploadNums) | ||
| up(progress) | ||
|
|
@@ -145,23 +166,19 @@ func (d *Open123) Upload(ctx context.Context, file model.FileStreamer, createRes | |
| return err | ||
| } | ||
|
|
||
| uploadCompleteResp, err := d.complete(createResp.Data.PreuploadID) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if uploadCompleteResp.Data.Async == false || uploadCompleteResp.Data.Completed { | ||
| return nil | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| for { | ||
| uploadAsyncResp, err := d.async(createResp.Data.PreuploadID) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if uploadAsyncResp.Data.Completed { | ||
| break | ||
| } | ||
| // 上传完毕 | ||
| func (d *Open123) complete(preuploadID string) (*UploadCompleteResp, error) { | ||
| var resp UploadCompleteResp | ||
| _, err := d.Request(UploadComplete, http.MethodPost, func(req *resty.Request) { | ||
| req.SetBody(base.Json{ | ||
| "preuploadID": preuploadID, | ||
| }) | ||
| }, &resp) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| up(100) | ||
| return nil | ||
| return &resp, nil | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.