From a31af209cc3702cea549aa905aec36e2eae15bd6 Mon Sep 17 00:00:00 2001 From: foxxorcat <95907542+foxxorcat@users.noreply.github.com> Date: Tue, 11 Jul 2023 22:19:21 +0800 Subject: [PATCH] fix(pikpak): hash calculation and fast upload judgment (#4745 fix #1081) --- drivers/pikpak/driver.go | 54 +++++++++++++++++----------------------- drivers/pikpak/types.go | 20 +++++++++++++++ drivers/pikpak/util.go | 28 +++++++++++++++++++++ 3 files changed, 71 insertions(+), 31 deletions(-) diff --git a/drivers/pikpak/driver.go b/drivers/pikpak/driver.go index c86a8b86..ddaadef0 100644 --- a/drivers/pikpak/driver.go +++ b/drivers/pikpak/driver.go @@ -2,8 +2,6 @@ package pikpak import ( "context" - "crypto/sha1" - "encoding/hex" "fmt" "io" "net/http" @@ -19,7 +17,6 @@ import ( "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3/s3manager" "github.com/go-resty/resty/v2" - jsoniter "github.com/json-iterator/go" log "github.com/sirupsen/logrus" ) @@ -135,9 +132,8 @@ func (d *PikPak) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr _ = tempFile.Close() _ = os.Remove(tempFile.Name()) }() - // cal sha1 - s := sha1.New() - _, err = io.Copy(s, tempFile) + // cal gcid + sha1Str, err := getGcid(tempFile, stream.GetSize()) if err != nil { return err } @@ -145,37 +141,33 @@ func (d *PikPak) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr if err != nil { return err } - sha1Str := hex.EncodeToString(s.Sum(nil)) - data := base.Json{ - "kind": "drive#file", - "name": stream.GetName(), - "size": stream.GetSize(), - "hash": strings.ToUpper(sha1Str), - "upload_type": "UPLOAD_TYPE_RESUMABLE", - "objProvider": base.Json{"provider": "UPLOAD_TYPE_UNKNOWN"}, - "parent_id": dstDir.GetID(), - } + var resp UploadTaskData res, err := d.request("https://api-drive.mypikpak.com/drive/v1/files", http.MethodPost, func(req *resty.Request) { - req.SetBody(data) - }, nil) + req.SetBody(base.Json{ + "kind": "drive#file", + "name": stream.GetName(), + "size": stream.GetSize(), + "hash": strings.ToUpper(sha1Str), + "upload_type": "UPLOAD_TYPE_RESUMABLE", + "objProvider": base.Json{"provider": "UPLOAD_TYPE_UNKNOWN"}, + "parent_id": dstDir.GetID(), + "folder_type": "NORMAL", + }) + }, &resp) if err != nil { return err } - if stream.GetSize() == 0 { + + // 秒传成功 + if resp.Resumable == nil { log.Debugln(string(res)) return nil } - params := jsoniter.Get(res, "resumable").Get("params") - endpoint := params.Get("endpoint").ToString() - endpointS := strings.Split(endpoint, ".") - endpoint = strings.Join(endpointS[1:], ".") - accessKeyId := params.Get("access_key_id").ToString() - accessKeySecret := params.Get("access_key_secret").ToString() - securityToken := params.Get("security_token").ToString() - key := params.Get("key").ToString() - bucket := params.Get("bucket").ToString() + + params := resp.Resumable.Params + endpoint := strings.Join(strings.Split(params.Endpoint, ".")[1:], ".") cfg := &aws.Config{ - Credentials: credentials.NewStaticCredentials(accessKeyId, accessKeySecret, securityToken), + Credentials: credentials.NewStaticCredentials(params.AccessKeyID, params.AccessKeySecret, params.SecurityToken), Region: aws.String("pikpak"), Endpoint: &endpoint, } @@ -185,8 +177,8 @@ func (d *PikPak) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr } uploader := s3manager.NewUploader(ss) input := &s3manager.UploadInput{ - Bucket: &bucket, - Key: &key, + Bucket: ¶ms.Bucket, + Key: ¶ms.Key, Body: tempFile, } _, err = uploader.UploadWithContext(ctx, input) diff --git a/drivers/pikpak/types.go b/drivers/pikpak/types.go index aa534d89..b909cae0 100644 --- a/drivers/pikpak/types.go +++ b/drivers/pikpak/types.go @@ -73,3 +73,23 @@ type Media struct { IsVisible bool `json:"is_visible"` Category string `json:"category"` } + +type UploadTaskData struct { + UploadType string `json:"upload_type"` + //UPLOAD_TYPE_RESUMABLE + Resumable *struct { + Kind string `json:"kind"` + Params struct { + AccessKeyID string `json:"access_key_id"` + AccessKeySecret string `json:"access_key_secret"` + Bucket string `json:"bucket"` + Endpoint string `json:"endpoint"` + Expiration time.Time `json:"expiration"` + Key string `json:"key"` + SecurityToken string `json:"security_token"` + } `json:"params"` + Provider string `json:"provider"` + } `json:"resumable"` + + File File `json:"file"` +} diff --git a/drivers/pikpak/util.go b/drivers/pikpak/util.go index 0ac62cfd..02b988bc 100644 --- a/drivers/pikpak/util.go +++ b/drivers/pikpak/util.go @@ -1,7 +1,10 @@ package pikpak import ( + "crypto/sha1" + "encoding/hex" "errors" + "io" "net/http" "github.com/alist-org/alist/v3/drivers/base" @@ -123,3 +126,28 @@ func (d *PikPak) getFiles(id string) ([]File, error) { } return res, nil } + +func getGcid(r io.Reader, size int64) (string, error) { + calcBlockSize := func(j int64) int64 { + var psize int64 = 0x40000 + for float64(j)/float64(psize) > 0x200 && psize < 0x200000 { + psize = psize << 1 + } + return psize + } + + hash1 := sha1.New() + hash2 := sha1.New() + readSize := calcBlockSize(size) + for { + hash2.Reset() + if n, err := io.CopyN(hash2, r, readSize); err != nil && n == 0 { + if err != io.EOF { + return "", err + } + break + } + hash1.Write(hash2.Sum(nil)) + } + return hex.EncodeToString(hash1.Sum(nil)), nil +}