mirror of https://github.com/Xhofe/alist
perf(189pc): empty file upload and cache optimization (#4913)
- login captcha error - cache optimization - upload empty filepull/4930/head
parent
3e285aaec4
commit
49bde82426
|
@ -4,9 +4,11 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/alist-org/alist/v3/drivers/base"
|
||||
"github.com/alist-org/alist/v3/internal/driver"
|
||||
"github.com/alist-org/alist/v3/internal/errs"
|
||||
"github.com/alist-org/alist/v3/internal/model"
|
||||
"github.com/alist-org/alist/v3/pkg/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
@ -135,13 +137,14 @@ func (y *Cloud189PC) Link(ctx context.Context, file model.Obj, args model.LinkAr
|
|||
return like, nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error {
|
||||
func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) (model.Obj, error) {
|
||||
fullUrl := API_URL
|
||||
if y.isFamily() {
|
||||
fullUrl += "/family/file"
|
||||
}
|
||||
fullUrl += "/createFolder.action"
|
||||
|
||||
var newFolder Cloud189Folder
|
||||
_, err := y.post(fullUrl, func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetQueryParams(map[string]string{
|
||||
|
@ -158,11 +161,15 @@ func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName s
|
|||
"parentFolderId": parentDir.GetID(),
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
return err
|
||||
}, &newFolder)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &newFolder, nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
func (y *Cloud189PC) Move(ctx context.Context, srcObj, dstDir model.Obj) (model.Obj, error) {
|
||||
var resp CreateBatchTaskResp
|
||||
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetFormData(map[string]string{
|
||||
|
@ -182,11 +189,17 @@ func (y *Cloud189PC) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
|||
"familyId": y.FamilyID,
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
return err
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = y.WaitBatchTask("MOVE", resp.TaskID, time.Millisecond*400); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return srcObj, nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
|
||||
func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName string) (model.Obj, error) {
|
||||
queryParam := make(map[string]string)
|
||||
fullUrl := API_URL
|
||||
method := http.MethodPost
|
||||
|
@ -195,23 +208,34 @@ func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName strin
|
|||
method = http.MethodGet
|
||||
queryParam["familyId"] = y.FamilyID
|
||||
}
|
||||
if srcObj.IsDir() {
|
||||
fullUrl += "/renameFolder.action"
|
||||
queryParam["folderId"] = srcObj.GetID()
|
||||
queryParam["destFolderName"] = newName
|
||||
} else {
|
||||
|
||||
var newObj model.Obj
|
||||
switch f := srcObj.(type) {
|
||||
case *Cloud189File:
|
||||
fullUrl += "/renameFile.action"
|
||||
queryParam["fileId"] = srcObj.GetID()
|
||||
queryParam["destFileName"] = newName
|
||||
newObj = &Cloud189File{Icon: f.Icon} // 复用预览
|
||||
case *Cloud189Folder:
|
||||
fullUrl += "/renameFolder.action"
|
||||
queryParam["folderId"] = srcObj.GetID()
|
||||
queryParam["destFolderName"] = newName
|
||||
newObj = &Cloud189Folder{}
|
||||
default:
|
||||
return nil, errs.NotSupport
|
||||
}
|
||||
|
||||
_, err := y.request(fullUrl, method, func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetQueryParams(queryParam)
|
||||
}, nil, nil)
|
||||
return err
|
||||
req.SetContext(ctx).SetQueryParams(queryParam)
|
||||
}, nil, newObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newObj, nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||
var resp CreateBatchTaskResp
|
||||
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetFormData(map[string]string{
|
||||
|
@ -232,11 +256,15 @@ func (y *Cloud189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
|||
"familyId": y.FamilyID,
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
return err
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return y.WaitBatchTask("COPY", resp.TaskID, time.Second)
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) Remove(ctx context.Context, obj model.Obj) error {
|
||||
var resp CreateBatchTaskResp
|
||||
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
req.SetFormData(map[string]string{
|
||||
|
@ -256,19 +284,26 @@ func (y *Cloud189PC) Remove(ctx context.Context, obj model.Obj) error {
|
|||
"familyId": y.FamilyID,
|
||||
})
|
||||
}
|
||||
}, nil)
|
||||
return err
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 批量任务数量限制,过快会导致无法删除
|
||||
return y.WaitBatchTask("DELETE", resp.TaskID, time.Millisecond*200)
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error {
|
||||
func (y *Cloud189PC) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||
switch y.UploadMethod {
|
||||
case "stream":
|
||||
return y.CommonUpload(ctx, dstDir, stream, up)
|
||||
case "old":
|
||||
return y.OldUpload(ctx, dstDir, stream, up)
|
||||
case "rapid":
|
||||
return y.FastUpload(ctx, dstDir, stream, up)
|
||||
case "stream":
|
||||
if stream.GetSize() == 0 {
|
||||
return y.FastUpload(ctx, dstDir, stream, up)
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
return y.CommonUpload(ctx, dstDir, stream, up)
|
||||
return y.StreamUpload(ctx, dstDir, stream, up)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
|
@ -83,6 +84,55 @@ func MustParseTime(str string) *time.Time {
|
|||
return &lastOpTime
|
||||
}
|
||||
|
||||
type Time time.Time
|
||||
|
||||
func (t *Time) UnmarshalJSON(b []byte) error { return t.Unmarshal(b) }
|
||||
func (t *Time) UnmarshalXML(e *xml.Decoder, ee xml.StartElement) error {
|
||||
b, err := e.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b, ok := b.(xml.CharData); ok {
|
||||
if err = t.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.Skip()
|
||||
}
|
||||
func (t *Time) Unmarshal(b []byte) error {
|
||||
bs := strings.Trim(string(b), "\"")
|
||||
var v time.Time
|
||||
var err error
|
||||
for _, f := range []string{"2006-01-02 15:04:05 -07", "Jan 2, 2006 15:04:05 PM -07"} {
|
||||
v, err = time.ParseInLocation(f, bs+" +08", time.Local)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
*t = Time(v)
|
||||
return err
|
||||
}
|
||||
|
||||
type String string
|
||||
|
||||
func (t *String) UnmarshalJSON(b []byte) error { return t.Unmarshal(b) }
|
||||
func (t *String) UnmarshalXML(e *xml.Decoder, ee xml.StartElement) error {
|
||||
b, err := e.Token()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b, ok := b.(xml.CharData); ok {
|
||||
if err = t.Unmarshal(b); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return e.Skip()
|
||||
}
|
||||
func (s *String) Unmarshal(b []byte) error {
|
||||
*s = String(bytes.Trim(b, "\""))
|
||||
return nil
|
||||
}
|
||||
|
||||
func toFamilyOrderBy(o string) string {
|
||||
switch o {
|
||||
case "filename":
|
||||
|
@ -122,10 +172,6 @@ func MustString(str string, err error) string {
|
|||
return str
|
||||
}
|
||||
|
||||
func MustToBytes(b []byte, err error) []byte {
|
||||
return b
|
||||
}
|
||||
|
||||
func BoolToNumber(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
|
|
|
@ -151,8 +151,13 @@ type FamilyInfoResp struct {
|
|||
/*文件部分*/
|
||||
// 文件
|
||||
type Cloud189File struct {
|
||||
CreateDate string `json:"createDate"`
|
||||
FileCata int64 `json:"fileCata"`
|
||||
ID String `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Size int64 `json:"size"`
|
||||
Md5 string `json:"md5"`
|
||||
|
||||
LastOpTime Time `json:"lastOpTime"`
|
||||
CreateDate Time `json:"createDate"`
|
||||
Icon struct {
|
||||
//iconOption 5
|
||||
SmallUrl string `json:"smallUrl"`
|
||||
|
@ -162,62 +167,44 @@ type Cloud189File struct {
|
|||
Max600 string `json:"max600"`
|
||||
MediumURL string `json:"mediumUrl"`
|
||||
} `json:"icon"`
|
||||
ID int64 `json:"id"`
|
||||
LastOpTime string `json:"lastOpTime"`
|
||||
Md5 string `json:"md5"`
|
||||
MediaType int `json:"mediaType"`
|
||||
Name string `json:"name"`
|
||||
Orientation int64 `json:"orientation"`
|
||||
Rev string `json:"rev"`
|
||||
Size int64 `json:"size"`
|
||||
StarLabel int64 `json:"starLabel"`
|
||||
|
||||
parseTime *time.Time
|
||||
// Orientation int64 `json:"orientation"`
|
||||
// FileCata int64 `json:"fileCata"`
|
||||
// MediaType int `json:"mediaType"`
|
||||
// Rev string `json:"rev"`
|
||||
// StarLabel int64 `json:"starLabel"`
|
||||
}
|
||||
|
||||
func (c *Cloud189File) GetSize() int64 { return c.Size }
|
||||
func (c *Cloud189File) GetName() string { return c.Name }
|
||||
func (c *Cloud189File) ModTime() time.Time {
|
||||
if c.parseTime == nil {
|
||||
c.parseTime = MustParseTime(c.LastOpTime)
|
||||
}
|
||||
return *c.parseTime
|
||||
}
|
||||
func (c *Cloud189File) IsDir() bool { return false }
|
||||
func (c *Cloud189File) GetID() string { return fmt.Sprint(c.ID) }
|
||||
func (c *Cloud189File) GetPath() string { return "" }
|
||||
func (c *Cloud189File) Thumb() string { return c.Icon.SmallUrl }
|
||||
func (c *Cloud189File) GetSize() int64 { return c.Size }
|
||||
func (c *Cloud189File) GetName() string { return c.Name }
|
||||
func (c *Cloud189File) ModTime() time.Time { return time.Time(c.LastOpTime) }
|
||||
func (c *Cloud189File) IsDir() bool { return false }
|
||||
func (c *Cloud189File) GetID() string { return string(c.ID) }
|
||||
func (c *Cloud189File) GetPath() string { return "" }
|
||||
func (c *Cloud189File) Thumb() string { return c.Icon.SmallUrl }
|
||||
|
||||
// 文件夹
|
||||
type Cloud189Folder struct {
|
||||
ID int64 `json:"id"`
|
||||
ID String `json:"id"`
|
||||
ParentID int64 `json:"parentId"`
|
||||
Name string `json:"name"`
|
||||
|
||||
FileCata int64 `json:"fileCata"`
|
||||
FileCount int64 `json:"fileCount"`
|
||||
LastOpTime Time `json:"lastOpTime"`
|
||||
CreateDate Time `json:"createDate"`
|
||||
|
||||
LastOpTime string `json:"lastOpTime"`
|
||||
CreateDate string `json:"createDate"`
|
||||
|
||||
FileListSize int64 `json:"fileListSize"`
|
||||
Rev string `json:"rev"`
|
||||
StarLabel int64 `json:"starLabel"`
|
||||
|
||||
parseTime *time.Time
|
||||
// FileListSize int64 `json:"fileListSize"`
|
||||
// FileCount int64 `json:"fileCount"`
|
||||
// FileCata int64 `json:"fileCata"`
|
||||
// Rev string `json:"rev"`
|
||||
// StarLabel int64 `json:"starLabel"`
|
||||
}
|
||||
|
||||
func (c *Cloud189Folder) GetSize() int64 { return 0 }
|
||||
func (c *Cloud189Folder) GetName() string { return c.Name }
|
||||
func (c *Cloud189Folder) ModTime() time.Time {
|
||||
if c.parseTime == nil {
|
||||
c.parseTime = MustParseTime(c.LastOpTime)
|
||||
}
|
||||
return *c.parseTime
|
||||
}
|
||||
func (c *Cloud189Folder) IsDir() bool { return true }
|
||||
func (c *Cloud189Folder) GetID() string { return fmt.Sprint(c.ID) }
|
||||
func (c *Cloud189Folder) GetPath() string { return "" }
|
||||
func (c *Cloud189Folder) GetSize() int64 { return 0 }
|
||||
func (c *Cloud189Folder) GetName() string { return c.Name }
|
||||
func (c *Cloud189Folder) ModTime() time.Time { return time.Time(c.LastOpTime) }
|
||||
func (c *Cloud189Folder) IsDir() bool { return true }
|
||||
func (c *Cloud189Folder) GetID() string { return string(c.ID) }
|
||||
func (c *Cloud189Folder) GetPath() string { return "" }
|
||||
|
||||
type Cloud189FilesResp struct {
|
||||
//ResCode int `json:"res_code"`
|
||||
|
@ -284,15 +271,60 @@ func (r *GetUploadFileStatusResp) GetSize() int64 {
|
|||
return r.DataSize + r.Size
|
||||
}
|
||||
|
||||
type CommitUploadFileResp struct {
|
||||
type CommitMultiUploadFileResp struct {
|
||||
File struct {
|
||||
UserFileID String `json:"userFileId"`
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
FileMd5 string `json:"fileMd5"`
|
||||
CreateDate Time `json:"createDate"`
|
||||
} `json:"file"`
|
||||
}
|
||||
|
||||
func (f *CommitMultiUploadFileResp) toFile() *Cloud189File {
|
||||
return &Cloud189File{
|
||||
ID: f.File.UserFileID,
|
||||
Name: f.File.FileName,
|
||||
Size: f.File.FileSize,
|
||||
Md5: f.File.FileMd5,
|
||||
LastOpTime: f.File.CreateDate,
|
||||
CreateDate: f.File.CreateDate,
|
||||
}
|
||||
}
|
||||
|
||||
type OldCommitUploadFileResp struct {
|
||||
XMLName xml.Name `xml:"file"`
|
||||
Id string `xml:"id"`
|
||||
ID String `xml:"id"`
|
||||
Name string `xml:"name"`
|
||||
Size string `xml:"size"`
|
||||
Size int64 `xml:"size"`
|
||||
Md5 string `xml:"md5"`
|
||||
CreateDate string `xml:"createDate"`
|
||||
Rev string `xml:"rev"`
|
||||
UserId string `xml:"userId"`
|
||||
CreateDate Time `xml:"createDate"`
|
||||
}
|
||||
|
||||
func (f *OldCommitUploadFileResp) toFile() *Cloud189File {
|
||||
return &Cloud189File{
|
||||
ID: f.ID,
|
||||
Name: f.Name,
|
||||
Size: f.Size,
|
||||
Md5: f.Md5,
|
||||
CreateDate: f.CreateDate,
|
||||
LastOpTime: f.CreateDate,
|
||||
}
|
||||
}
|
||||
|
||||
type CreateBatchTaskResp struct {
|
||||
TaskID string `json:"taskId"`
|
||||
}
|
||||
|
||||
type BatchTaskStateResp struct {
|
||||
FailedCount int `json:"failedCount"`
|
||||
Process int `json:"process"`
|
||||
SkipCount int `json:"skipCount"`
|
||||
SubTaskCount int `json:"subTaskCount"`
|
||||
SuccessedCount int `json:"successedCount"`
|
||||
SuccessedFileIDList []int64 `json:"successedFileIdList"`
|
||||
TaskID string `json:"taskId"`
|
||||
TaskStatus int `json:"taskStatus"` //1 初始化 2 存在冲突 3 执行中,4 完成
|
||||
}
|
||||
|
||||
/* query 加密参数*/
|
||||
|
|
|
@ -268,7 +268,7 @@ func (y *Cloud189PC) login() (err error) {
|
|||
"validateCode": y.VCode,
|
||||
"captchaToken": param.CaptchaToken,
|
||||
"returnUrl": RETURN_URL,
|
||||
"mailSuffix": "@189.cn",
|
||||
// "mailSuffix": "@189.cn",
|
||||
"dynamicCheck": "FALSE",
|
||||
"clientType": CLIENT_TYPE,
|
||||
"cb_SaveName": "1",
|
||||
|
@ -434,7 +434,8 @@ func (y *Cloud189PC) refreshSession() (err error) {
|
|||
}
|
||||
|
||||
// 普通上传
|
||||
func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (err error) {
|
||||
// 无法上传大小为0的文件
|
||||
func (y *Cloud189PC) StreamUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||
var DEFAULT = partSize(file.GetSize())
|
||||
var count = int(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
|
||||
|
||||
|
@ -457,11 +458,11 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
|
||||
// 初始化上传
|
||||
var initMultiUpload InitMultiUploadResp
|
||||
_, err = y.request(fullUrl+"/initMultiUpload", http.MethodGet, func(req *resty.Request) {
|
||||
_, err := y.request(fullUrl+"/initMultiUpload", http.MethodGet, func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
}, params, &initMultiUpload)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileMd5 := md5.New()
|
||||
|
@ -470,7 +471,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
byteData := bytes.NewBuffer(make([]byte, DEFAULT))
|
||||
for i := 1; i <= count; i++ {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
// 读取块
|
||||
|
@ -478,7 +479,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
silceMd5.Reset()
|
||||
_, err := io.CopyN(io.MultiWriter(fileMd5, silceMd5, byteData), file, DEFAULT)
|
||||
if err != io.EOF && err != io.ErrUnexpectedEOF && err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 计算块md5并进行hex和base64编码
|
||||
|
@ -496,7 +497,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
"uploadFileId": initMultiUpload.Data.UploadFileID,
|
||||
}, &uploadUrl)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 开始上传
|
||||
|
@ -511,7 +512,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
retry.Delay(time.Second),
|
||||
retry.MaxDelay(5*time.Second))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
up(int(i * 100 / count))
|
||||
}
|
||||
|
@ -523,6 +524,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
}
|
||||
|
||||
// 提交上传
|
||||
var resp CommitMultiUploadFileResp
|
||||
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
|
||||
func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
|
@ -533,16 +535,19 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
|||
"lazyCheck": "1",
|
||||
"isLog": "0",
|
||||
"opertype": "3",
|
||||
}, nil)
|
||||
return err
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.toFile(), nil
|
||||
}
|
||||
|
||||
// 快传
|
||||
func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (err error) {
|
||||
func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||
// 需要获取完整文件md5,必须支持 io.Seek
|
||||
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = tempFile.Close()
|
||||
|
@ -559,19 +564,19 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
silceMd5Base64s := make([]string, 0, count)
|
||||
for i := 1; i <= count; i++ {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
silceMd5.Reset()
|
||||
if _, err := io.CopyN(io.MultiWriter(fileMd5, silceMd5), tempFile, DEFAULT); err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
md5Byte := silceMd5.Sum(nil)
|
||||
silceMd5Hexs = append(silceMd5Hexs, strings.ToUpper(hex.EncodeToString(md5Byte)))
|
||||
silceMd5Base64s = append(silceMd5Base64s, fmt.Sprint(i, "-", base64.StdEncoding.EncodeToString(md5Byte)))
|
||||
}
|
||||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fileMd5Hex := strings.ToUpper(hex.EncodeToString(fileMd5.Sum(nil)))
|
||||
|
@ -604,7 +609,7 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
req.SetContext(ctx)
|
||||
}, params, &uploadInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 网盘中不存在该文件,开始上传
|
||||
|
@ -618,18 +623,18 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
"partInfo": strings.Join(silceMd5Base64s, ","),
|
||||
}, &uploadUrls)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, DEFAULT)
|
||||
for i := 1; i <= count; i++ {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
n, err := io.ReadFull(tempFile, buf)
|
||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
uploadData := uploadUrls.UploadUrls[fmt.Sprint("partNumber_", i)]
|
||||
err = retry.Do(func() error {
|
||||
|
@ -641,7 +646,7 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
retry.Delay(time.Second),
|
||||
retry.MaxDelay(5*time.Second))
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
up(int(i * 100 / count))
|
||||
|
@ -649,6 +654,7 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
}
|
||||
|
||||
// 提交
|
||||
var resp CommitMultiUploadFileResp
|
||||
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
|
||||
func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
|
@ -656,15 +662,19 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
|||
"uploadFileId": uploadInfo.Data.UploadFileID,
|
||||
"isLog": "0",
|
||||
"opertype": "3",
|
||||
}, nil)
|
||||
return err
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.toFile(), nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (err error) {
|
||||
// 旧版本上传,家庭云不支持覆盖
|
||||
func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model.FileStreamer, up driver.UpdateProgress) (model.Obj, error) {
|
||||
// 需要获取完整文件md5,必须支持 io.Seek
|
||||
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
_ = tempFile.Close()
|
||||
|
@ -674,10 +684,10 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
|||
// 计算md5
|
||||
fileMd5 := md5.New()
|
||||
if _, err := io.Copy(fileMd5, tempFile); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
fileMd5Hex := strings.ToUpper(hex.EncodeToString(fileMd5.Sum(nil)))
|
||||
|
||||
|
@ -718,14 +728,14 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
|||
}, &uploadInfo)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 网盘中不存在该文件,开始上传
|
||||
status := GetUploadFileStatusResp{CreateUploadFileResp: uploadInfo}
|
||||
for status.Size < file.GetSize() && status.FileDataExists != 1 {
|
||||
if utils.IsCanceled(ctx) {
|
||||
return ctx.Err()
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
header := map[string]string{
|
||||
|
@ -742,7 +752,7 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
|||
|
||||
_, err := y.put(ctx, status.FileUploadUrl, header, true, io.NopCloser(tempFile))
|
||||
if err, ok := err.(*RespErr); ok && err.Code != "InputStreamReadError" {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取断点状态
|
||||
|
@ -760,17 +770,17 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
|||
}
|
||||
}, &status)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := tempFile.Seek(status.GetSize(), io.SeekStart); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
up(int(status.Size / file.GetSize()))
|
||||
}
|
||||
|
||||
// 提交
|
||||
var resp CommitUploadFileResp
|
||||
var resp OldCommitUploadFileResp
|
||||
_, err = y.post(status.FileCommitUrl, func(req *resty.Request) {
|
||||
req.SetContext(ctx)
|
||||
if y.isFamily() {
|
||||
|
@ -788,7 +798,10 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
|||
})
|
||||
}
|
||||
}, &resp)
|
||||
return err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp.toFile(), nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) isFamily() bool {
|
||||
|
@ -829,3 +842,33 @@ func (y *Cloud189PC) getFamilyID() (string, error) {
|
|||
}
|
||||
return fmt.Sprint(infos[0].FamilyID), nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) CheckBatchTask(aType string, taskID string) (*BatchTaskStateResp, error) {
|
||||
var resp BatchTaskStateResp
|
||||
_, err := y.post(API_URL+"/batch/checkBatchTask.action", func(req *resty.Request) {
|
||||
req.SetFormData(map[string]string{
|
||||
"type": aType,
|
||||
"taskId": taskID,
|
||||
})
|
||||
}, &resp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
func (y *Cloud189PC) WaitBatchTask(aType string, taskID string, t time.Duration) error {
|
||||
for {
|
||||
state, err := y.CheckBatchTask(aType, taskID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch state.TaskStatus {
|
||||
case 2:
|
||||
return errors.New("there is a conflict with the target object")
|
||||
case 4:
|
||||
return nil
|
||||
}
|
||||
time.Sleep(t)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue