From 19b2ce68dab741a6277ec804785848b632152094 Mon Sep 17 00:00:00 2001 From: "xiaobo.chen" Date: Mon, 19 Jun 2023 18:15:34 +0800 Subject: [PATCH] [feature]add UploadPartCopy --- file_mutipart_upload.go | 42 +++++++++++++++++++++++++++++++++++++++++ utils.go | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/file_mutipart_upload.go b/file_mutipart_upload.go index 4190dac..7c46cfd 100644 --- a/file_mutipart_upload.go +++ b/file_mutipart_upload.go @@ -266,6 +266,48 @@ func (u *UFileRequest) UploadPart(buf *bytes.Buffer, state *MultipartState, part return nil } +//UploadPartCopy 实现从一个已存在的Object中拷贝数据来上传一个Part。 +func (u *UFileRequest) UploadPartCopy(state *MultipartState, partNumber int, sourceBucketName, sourceObject string, offset, size int64) error { + query := &url.Values{} + query.Add("uploadId", state.uploadID) + query.Add("partNumber", strconv.Itoa(partNumber)) + + reqURL := u.genFileURL(state.keyName) + "?" + query.Encode() + req, err := http.NewRequest("PUT", reqURL, nil) + if err != nil { + return err + } + req.Header.Add("X-Ufile-Copy-Source", fmt.Sprintf("/%s/%s", sourceBucketName, sourceObject)) + req.Header.Add("X-Ufile-Copy-Source-Range", fmt.Sprintf("bytes=%d-%d", offset, offset+size-1)) + req.Header.Add("Content-Type", state.mimeType) + authorization := u.Auth.Authorization("PUT", u.BucketName, state.keyName, req.Header) + req.Header.Add("Authorization", authorization) + + resp, err := u.requestWithResp(req) + if err != nil { + return err + } + + if !VerifyHTTPCode(resp.StatusCode) { + err = u.responseParse(resp) + if err != nil { + return err + } + return fmt.Errorf("Remote response code is %d - %s not 2xx call DumpResponse(true) show details", + resp.StatusCode, http.StatusText(resp.StatusCode)) + } + defer resp.Body.Close() + + etag := strings.Trim(resp.Header.Get("Etag"), "\"") //为保证线程安全,这里就不保留 lastResponse + if etag == "" { + etag = strings.Trim(resp.Header.Get("ETag"), "\"") //为保证线程安全,这里就不保留 lastResponse + } + state.mux.Lock() + state.etags[partNumber] = etag + state.mux.Unlock() + return nil +} + //FinishMultipartUpload 完成分片上传。分片上传必须要调用的接口。 //state 参数是 InitiateMultipartUpload 返回的 func (u *UFileRequest) FinishMultipartUpload(state *MultipartState) error { diff --git a/utils.go b/utils.go index ee3a90b..52034da 100644 --- a/utils.go +++ b/utils.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "encoding/binary" "encoding/json" + "errors" "fmt" "io" "io/ioutil" @@ -188,3 +189,37 @@ func structPrettyStr(data interface{}) string { } return "" } + +// FilePart is the file part definition +type FilePart struct { + Number int // Part number + Offset int64 // Part offset + Size int64 // Part size +} + +// SplitFileByPartSize splits big file into parts by the size of parts. +// Splits the file by the part size. Returns the FilePart when error is nil. +func SplitFileByPartSize(fileSize, partSize int64) ([]FilePart, error) { + if fileSize <= 0 || partSize <= 0 { + return nil, errors.New("fileSize or partSize invalid") + } + + var partN = fileSize / partSize + var parts []FilePart + var part = FilePart{} + for i := int64(0); i < partN; i++ { + part.Number = int(i + 1) + part.Offset = i * partSize + part.Size = partSize + parts = append(parts, part) + } + + if fileSize%partSize > 0 { + part.Number = len(parts) + 1 + part.Offset = int64(len(parts)) * partSize + part.Size = fileSize % partSize + parts = append(parts, part) + } + + return parts, nil +}