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"
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/alist-org/alist/v3/drivers/base"
|
"github.com/alist-org/alist/v3/drivers/base"
|
||||||
"github.com/alist-org/alist/v3/internal/driver"
|
"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/internal/model"
|
||||||
"github.com/alist-org/alist/v3/pkg/utils"
|
"github.com/alist-org/alist/v3/pkg/utils"
|
||||||
"github.com/go-resty/resty/v2"
|
"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
|
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
|
fullUrl := API_URL
|
||||||
if y.isFamily() {
|
if y.isFamily() {
|
||||||
fullUrl += "/family/file"
|
fullUrl += "/family/file"
|
||||||
}
|
}
|
||||||
fullUrl += "/createFolder.action"
|
fullUrl += "/createFolder.action"
|
||||||
|
|
||||||
|
var newFolder Cloud189Folder
|
||||||
_, err := y.post(fullUrl, func(req *resty.Request) {
|
_, err := y.post(fullUrl, func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
req.SetQueryParams(map[string]string{
|
req.SetQueryParams(map[string]string{
|
||||||
|
@ -158,11 +161,15 @@ func (y *Cloud189PC) MakeDir(ctx context.Context, parentDir model.Obj, dirName s
|
||||||
"parentFolderId": parentDir.GetID(),
|
"parentFolderId": parentDir.GetID(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, &newFolder)
|
||||||
return err
|
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) {
|
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
req.SetFormData(map[string]string{
|
req.SetFormData(map[string]string{
|
||||||
|
@ -182,11 +189,17 @@ func (y *Cloud189PC) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||||
"familyId": y.FamilyID,
|
"familyId": y.FamilyID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, &resp)
|
||||||
return err
|
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)
|
queryParam := make(map[string]string)
|
||||||
fullUrl := API_URL
|
fullUrl := API_URL
|
||||||
method := http.MethodPost
|
method := http.MethodPost
|
||||||
|
@ -195,23 +208,34 @@ func (y *Cloud189PC) Rename(ctx context.Context, srcObj model.Obj, newName strin
|
||||||
method = http.MethodGet
|
method = http.MethodGet
|
||||||
queryParam["familyId"] = y.FamilyID
|
queryParam["familyId"] = y.FamilyID
|
||||||
}
|
}
|
||||||
if srcObj.IsDir() {
|
|
||||||
fullUrl += "/renameFolder.action"
|
var newObj model.Obj
|
||||||
queryParam["folderId"] = srcObj.GetID()
|
switch f := srcObj.(type) {
|
||||||
queryParam["destFolderName"] = newName
|
case *Cloud189File:
|
||||||
} else {
|
|
||||||
fullUrl += "/renameFile.action"
|
fullUrl += "/renameFile.action"
|
||||||
queryParam["fileId"] = srcObj.GetID()
|
queryParam["fileId"] = srcObj.GetID()
|
||||||
queryParam["destFileName"] = newName
|
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) {
|
_, err := y.request(fullUrl, method, func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx).SetQueryParams(queryParam)
|
||||||
req.SetQueryParams(queryParam)
|
}, nil, newObj)
|
||||||
}, nil, nil)
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
|
}
|
||||||
|
return newObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Cloud189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
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) {
|
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
req.SetFormData(map[string]string{
|
req.SetFormData(map[string]string{
|
||||||
|
@ -232,11 +256,15 @@ func (y *Cloud189PC) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
|
||||||
"familyId": y.FamilyID,
|
"familyId": y.FamilyID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, &resp)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return y.WaitBatchTask("COPY", resp.TaskID, time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Cloud189PC) Remove(ctx context.Context, obj model.Obj) error {
|
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) {
|
_, err := y.post(API_URL+"/batch/createBatchTask.action", func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
req.SetFormData(map[string]string{
|
req.SetFormData(map[string]string{
|
||||||
|
@ -256,19 +284,26 @@ func (y *Cloud189PC) Remove(ctx context.Context, obj model.Obj) error {
|
||||||
"familyId": y.FamilyID,
|
"familyId": y.FamilyID,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, nil)
|
}, &resp)
|
||||||
return err
|
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 {
|
switch y.UploadMethod {
|
||||||
case "stream":
|
|
||||||
return y.CommonUpload(ctx, dstDir, stream, up)
|
|
||||||
case "old":
|
case "old":
|
||||||
return y.OldUpload(ctx, dstDir, stream, up)
|
return y.OldUpload(ctx, dstDir, stream, up)
|
||||||
case "rapid":
|
case "rapid":
|
||||||
return y.FastUpload(ctx, dstDir, stream, up)
|
return y.FastUpload(ctx, dstDir, stream, up)
|
||||||
|
case "stream":
|
||||||
|
if stream.GetSize() == 0 {
|
||||||
|
return y.FastUpload(ctx, dstDir, stream, up)
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
default:
|
default:
|
||||||
return y.CommonUpload(ctx, dstDir, stream, up)
|
return y.StreamUpload(ctx, dstDir, stream, up)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -83,6 +84,55 @@ func MustParseTime(str string) *time.Time {
|
||||||
return &lastOpTime
|
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 {
|
func toFamilyOrderBy(o string) string {
|
||||||
switch o {
|
switch o {
|
||||||
case "filename":
|
case "filename":
|
||||||
|
@ -122,10 +172,6 @@ func MustString(str string, err error) string {
|
||||||
return str
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
func MustToBytes(b []byte, err error) []byte {
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func BoolToNumber(b bool) int {
|
func BoolToNumber(b bool) int {
|
||||||
if b {
|
if b {
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -151,8 +151,13 @@ type FamilyInfoResp struct {
|
||||||
/*文件部分*/
|
/*文件部分*/
|
||||||
// 文件
|
// 文件
|
||||||
type Cloud189File struct {
|
type Cloud189File struct {
|
||||||
CreateDate string `json:"createDate"`
|
ID String `json:"id"`
|
||||||
FileCata int64 `json:"fileCata"`
|
Name string `json:"name"`
|
||||||
|
Size int64 `json:"size"`
|
||||||
|
Md5 string `json:"md5"`
|
||||||
|
|
||||||
|
LastOpTime Time `json:"lastOpTime"`
|
||||||
|
CreateDate Time `json:"createDate"`
|
||||||
Icon struct {
|
Icon struct {
|
||||||
//iconOption 5
|
//iconOption 5
|
||||||
SmallUrl string `json:"smallUrl"`
|
SmallUrl string `json:"smallUrl"`
|
||||||
|
@ -162,62 +167,44 @@ type Cloud189File struct {
|
||||||
Max600 string `json:"max600"`
|
Max600 string `json:"max600"`
|
||||||
MediumURL string `json:"mediumUrl"`
|
MediumURL string `json:"mediumUrl"`
|
||||||
} `json:"icon"`
|
} `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) GetSize() int64 { return c.Size }
|
||||||
func (c *Cloud189File) GetName() string { return c.Name }
|
func (c *Cloud189File) GetName() string { return c.Name }
|
||||||
func (c *Cloud189File) ModTime() time.Time {
|
func (c *Cloud189File) ModTime() time.Time { return time.Time(c.LastOpTime) }
|
||||||
if c.parseTime == nil {
|
func (c *Cloud189File) IsDir() bool { return false }
|
||||||
c.parseTime = MustParseTime(c.LastOpTime)
|
func (c *Cloud189File) GetID() string { return string(c.ID) }
|
||||||
}
|
func (c *Cloud189File) GetPath() string { return "" }
|
||||||
return *c.parseTime
|
func (c *Cloud189File) Thumb() string { return c.Icon.SmallUrl }
|
||||||
}
|
|
||||||
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 }
|
|
||||||
|
|
||||||
// 文件夹
|
// 文件夹
|
||||||
type Cloud189Folder struct {
|
type Cloud189Folder struct {
|
||||||
ID int64 `json:"id"`
|
ID String `json:"id"`
|
||||||
ParentID int64 `json:"parentId"`
|
ParentID int64 `json:"parentId"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
|
||||||
FileCata int64 `json:"fileCata"`
|
LastOpTime Time `json:"lastOpTime"`
|
||||||
FileCount int64 `json:"fileCount"`
|
CreateDate Time `json:"createDate"`
|
||||||
|
|
||||||
LastOpTime string `json:"lastOpTime"`
|
// FileListSize int64 `json:"fileListSize"`
|
||||||
CreateDate string `json:"createDate"`
|
// FileCount int64 `json:"fileCount"`
|
||||||
|
// FileCata int64 `json:"fileCata"`
|
||||||
FileListSize int64 `json:"fileListSize"`
|
// Rev string `json:"rev"`
|
||||||
Rev string `json:"rev"`
|
// StarLabel int64 `json:"starLabel"`
|
||||||
StarLabel int64 `json:"starLabel"`
|
|
||||||
|
|
||||||
parseTime *time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cloud189Folder) GetSize() int64 { return 0 }
|
func (c *Cloud189Folder) GetSize() int64 { return 0 }
|
||||||
func (c *Cloud189Folder) GetName() string { return c.Name }
|
func (c *Cloud189Folder) GetName() string { return c.Name }
|
||||||
func (c *Cloud189Folder) ModTime() time.Time {
|
func (c *Cloud189Folder) ModTime() time.Time { return time.Time(c.LastOpTime) }
|
||||||
if c.parseTime == nil {
|
func (c *Cloud189Folder) IsDir() bool { return true }
|
||||||
c.parseTime = MustParseTime(c.LastOpTime)
|
func (c *Cloud189Folder) GetID() string { return string(c.ID) }
|
||||||
}
|
func (c *Cloud189Folder) GetPath() string { return "" }
|
||||||
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 "" }
|
|
||||||
|
|
||||||
type Cloud189FilesResp struct {
|
type Cloud189FilesResp struct {
|
||||||
//ResCode int `json:"res_code"`
|
//ResCode int `json:"res_code"`
|
||||||
|
@ -284,15 +271,60 @@ func (r *GetUploadFileStatusResp) GetSize() int64 {
|
||||||
return r.DataSize + r.Size
|
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"`
|
XMLName xml.Name `xml:"file"`
|
||||||
Id string `xml:"id"`
|
ID String `xml:"id"`
|
||||||
Name string `xml:"name"`
|
Name string `xml:"name"`
|
||||||
Size string `xml:"size"`
|
Size int64 `xml:"size"`
|
||||||
Md5 string `xml:"md5"`
|
Md5 string `xml:"md5"`
|
||||||
CreateDate string `xml:"createDate"`
|
CreateDate Time `xml:"createDate"`
|
||||||
Rev string `xml:"rev"`
|
}
|
||||||
UserId string `xml:"userId"`
|
|
||||||
|
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 加密参数*/
|
/* query 加密参数*/
|
||||||
|
|
|
@ -268,7 +268,7 @@ func (y *Cloud189PC) login() (err error) {
|
||||||
"validateCode": y.VCode,
|
"validateCode": y.VCode,
|
||||||
"captchaToken": param.CaptchaToken,
|
"captchaToken": param.CaptchaToken,
|
||||||
"returnUrl": RETURN_URL,
|
"returnUrl": RETURN_URL,
|
||||||
"mailSuffix": "@189.cn",
|
// "mailSuffix": "@189.cn",
|
||||||
"dynamicCheck": "FALSE",
|
"dynamicCheck": "FALSE",
|
||||||
"clientType": CLIENT_TYPE,
|
"clientType": CLIENT_TYPE,
|
||||||
"cb_SaveName": "1",
|
"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 DEFAULT = partSize(file.GetSize())
|
||||||
var count = int(math.Ceil(float64(file.GetSize()) / float64(DEFAULT)))
|
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
|
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)
|
req.SetContext(ctx)
|
||||||
}, params, &initMultiUpload)
|
}, params, &initMultiUpload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileMd5 := md5.New()
|
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))
|
byteData := bytes.NewBuffer(make([]byte, DEFAULT))
|
||||||
for i := 1; i <= count; i++ {
|
for i := 1; i <= count; i++ {
|
||||||
if utils.IsCanceled(ctx) {
|
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()
|
silceMd5.Reset()
|
||||||
_, err := io.CopyN(io.MultiWriter(fileMd5, silceMd5, byteData), file, DEFAULT)
|
_, err := io.CopyN(io.MultiWriter(fileMd5, silceMd5, byteData), file, DEFAULT)
|
||||||
if err != io.EOF && err != io.ErrUnexpectedEOF && err != nil {
|
if err != io.EOF && err != io.ErrUnexpectedEOF && err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算块md5并进行hex和base64编码
|
// 计算块md5并进行hex和base64编码
|
||||||
|
@ -496,7 +497,7 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
||||||
"uploadFileId": initMultiUpload.Data.UploadFileID,
|
"uploadFileId": initMultiUpload.Data.UploadFileID,
|
||||||
}, &uploadUrl)
|
}, &uploadUrl)
|
||||||
if err != nil {
|
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.Delay(time.Second),
|
||||||
retry.MaxDelay(5*time.Second))
|
retry.MaxDelay(5*time.Second))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
up(int(i * 100 / count))
|
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,
|
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
|
||||||
func(req *resty.Request) {
|
func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
|
@ -533,16 +535,19 @@ func (y *Cloud189PC) CommonUpload(ctx context.Context, dstDir model.Obj, file mo
|
||||||
"lazyCheck": "1",
|
"lazyCheck": "1",
|
||||||
"isLog": "0",
|
"isLog": "0",
|
||||||
"opertype": "3",
|
"opertype": "3",
|
||||||
}, nil)
|
}, &resp)
|
||||||
return err
|
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
|
// 需要获取完整文件md5,必须支持 io.Seek
|
||||||
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = tempFile.Close()
|
_ = tempFile.Close()
|
||||||
|
@ -559,19 +564,19 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
||||||
silceMd5Base64s := make([]string, 0, count)
|
silceMd5Base64s := make([]string, 0, count)
|
||||||
for i := 1; i <= count; i++ {
|
for i := 1; i <= count; i++ {
|
||||||
if utils.IsCanceled(ctx) {
|
if utils.IsCanceled(ctx) {
|
||||||
return ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
silceMd5.Reset()
|
silceMd5.Reset()
|
||||||
if _, err := io.CopyN(io.MultiWriter(fileMd5, silceMd5), tempFile, DEFAULT); err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
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)
|
md5Byte := silceMd5.Sum(nil)
|
||||||
silceMd5Hexs = append(silceMd5Hexs, strings.ToUpper(hex.EncodeToString(md5Byte)))
|
silceMd5Hexs = append(silceMd5Hexs, strings.ToUpper(hex.EncodeToString(md5Byte)))
|
||||||
silceMd5Base64s = append(silceMd5Base64s, fmt.Sprint(i, "-", base64.StdEncoding.EncodeToString(md5Byte)))
|
silceMd5Base64s = append(silceMd5Base64s, fmt.Sprint(i, "-", base64.StdEncoding.EncodeToString(md5Byte)))
|
||||||
}
|
}
|
||||||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fileMd5Hex := strings.ToUpper(hex.EncodeToString(fileMd5.Sum(nil)))
|
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)
|
req.SetContext(ctx)
|
||||||
}, params, &uploadInfo)
|
}, params, &uploadInfo)
|
||||||
if err != nil {
|
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, ","),
|
"partInfo": strings.Join(silceMd5Base64s, ","),
|
||||||
}, &uploadUrls)
|
}, &uploadUrls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := make([]byte, DEFAULT)
|
buf := make([]byte, DEFAULT)
|
||||||
for i := 1; i <= count; i++ {
|
for i := 1; i <= count; i++ {
|
||||||
if utils.IsCanceled(ctx) {
|
if utils.IsCanceled(ctx) {
|
||||||
return ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
n, err := io.ReadFull(tempFile, buf)
|
n, err := io.ReadFull(tempFile, buf)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
uploadData := uploadUrls.UploadUrls[fmt.Sprint("partNumber_", i)]
|
uploadData := uploadUrls.UploadUrls[fmt.Sprint("partNumber_", i)]
|
||||||
err = retry.Do(func() error {
|
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.Delay(time.Second),
|
||||||
retry.MaxDelay(5*time.Second))
|
retry.MaxDelay(5*time.Second))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
up(int(i * 100 / count))
|
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,
|
_, err = y.request(fullUrl+"/commitMultiUploadFile", http.MethodGet,
|
||||||
func(req *resty.Request) {
|
func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
|
@ -656,15 +662,19 @@ func (y *Cloud189PC) FastUpload(ctx context.Context, dstDir model.Obj, file mode
|
||||||
"uploadFileId": uploadInfo.Data.UploadFileID,
|
"uploadFileId": uploadInfo.Data.UploadFileID,
|
||||||
"isLog": "0",
|
"isLog": "0",
|
||||||
"opertype": "3",
|
"opertype": "3",
|
||||||
}, nil)
|
}, &resp)
|
||||||
return err
|
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
|
// 需要获取完整文件md5,必须支持 io.Seek
|
||||||
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
tempFile, err := utils.CreateTempFile(file.GetReadCloser())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
_ = tempFile.Close()
|
_ = tempFile.Close()
|
||||||
|
@ -674,10 +684,10 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
||||||
// 计算md5
|
// 计算md5
|
||||||
fileMd5 := md5.New()
|
fileMd5 := md5.New()
|
||||||
if _, err := io.Copy(fileMd5, tempFile); err != nil {
|
if _, err := io.Copy(fileMd5, tempFile); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
if _, err = tempFile.Seek(0, io.SeekStart); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
fileMd5Hex := strings.ToUpper(hex.EncodeToString(fileMd5.Sum(nil)))
|
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)
|
}, &uploadInfo)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 网盘中不存在该文件,开始上传
|
// 网盘中不存在该文件,开始上传
|
||||||
status := GetUploadFileStatusResp{CreateUploadFileResp: uploadInfo}
|
status := GetUploadFileStatusResp{CreateUploadFileResp: uploadInfo}
|
||||||
for status.Size < file.GetSize() && status.FileDataExists != 1 {
|
for status.Size < file.GetSize() && status.FileDataExists != 1 {
|
||||||
if utils.IsCanceled(ctx) {
|
if utils.IsCanceled(ctx) {
|
||||||
return ctx.Err()
|
return nil, ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
header := map[string]string{
|
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))
|
_, err := y.put(ctx, status.FileUploadUrl, header, true, io.NopCloser(tempFile))
|
||||||
if err, ok := err.(*RespErr); ok && err.Code != "InputStreamReadError" {
|
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)
|
}, &status)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := tempFile.Seek(status.GetSize(), io.SeekStart); err != nil {
|
if _, err := tempFile.Seek(status.GetSize(), io.SeekStart); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
up(int(status.Size / file.GetSize()))
|
up(int(status.Size / file.GetSize()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提交
|
// 提交
|
||||||
var resp CommitUploadFileResp
|
var resp OldCommitUploadFileResp
|
||||||
_, err = y.post(status.FileCommitUrl, func(req *resty.Request) {
|
_, err = y.post(status.FileCommitUrl, func(req *resty.Request) {
|
||||||
req.SetContext(ctx)
|
req.SetContext(ctx)
|
||||||
if y.isFamily() {
|
if y.isFamily() {
|
||||||
|
@ -788,7 +798,10 @@ func (y *Cloud189PC) OldUpload(ctx context.Context, dstDir model.Obj, file model
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, &resp)
|
}, &resp)
|
||||||
return err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.toFile(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (y *Cloud189PC) isFamily() bool {
|
func (y *Cloud189PC) isFamily() bool {
|
||||||
|
@ -829,3 +842,33 @@ func (y *Cloud189PC) getFamilyID() (string, error) {
|
||||||
}
|
}
|
||||||
return fmt.Sprint(infos[0].FamilyID), nil
|
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