@@ -2,18 +2,25 @@ package alidrive
22
33import (
44 "bytes"
5+ "crypto/sha1"
6+ "encoding/base64"
7+ "encoding/hex"
58 "errors"
69 "fmt"
10+ "io"
11+ "io/ioutil"
12+ "math"
13+ "math/big"
14+ "net/http"
15+ "os"
16+ "path/filepath"
17+
718 "github.com/Xhofe/alist/conf"
819 "github.com/Xhofe/alist/drivers/base"
920 "github.com/Xhofe/alist/model"
1021 "github.com/Xhofe/alist/utils"
1122 "github.com/robfig/cron/v3"
1223 log "github.com/sirupsen/logrus"
13- "io"
14- "math"
15- "net/http"
16- "path/filepath"
1724)
1825
1926type AliDrive struct {}
@@ -376,48 +383,55 @@ type UploadResp struct {
376383 PartInfoList []struct {
377384 UploadUrl string `json:"upload_url"`
378385 } `json:"part_info_list"`
386+
387+ RapidUpload bool `json:"rapid_upload"`
379388}
380389
381390func (driver AliDrive ) Upload (file * model.FileStream , account * model.Account ) error {
382391 if file == nil {
383392 return base .ErrEmptyFile
384393 }
385- const DEFAULT uint64 = 10485760
394+ const DEFAULT int64 = 10485760
386395 var count = int64 (math .Ceil (float64 (file .GetSize ()) / float64 (DEFAULT )))
387- var finish uint64 = 0
388396 parentFile , err := driver .File (file .ParentPath , account )
389397 if err != nil {
390398 return err
391399 }
392400 if ! parentFile .IsDir () {
393401 return base .ErrNotFolder
394402 }
395- var resp UploadResp
396- var e AliRespError
397- partInfoList := make ([]base.Json , 0 )
403+
404+ partInfoList := make ([]base.Json , 0 , count )
398405 var i int64
399406 for i = 0 ; i < count ; i ++ {
400407 partInfoList = append (partInfoList , base.Json {
401408 "part_number" : i + 1 ,
402409 })
403410 }
404- _ , err = aliClient .R ().SetResult (& resp ).SetError (& e ).
405- SetHeader ("authorization" , "Bearer\t " + account .AccessToken ).
406- SetBody (base.Json {
407- "check_name_mode" : "auto_rename" ,
408- // content_hash
409- "content_hash_name" : "none" ,
410- "drive_id" : account .DriveId ,
411- "name" : file .GetFileName (),
412- "parent_file_id" : parentFile .Id ,
413- "part_info_list" : partInfoList ,
414- //proof_code
415- "proof_version" : "v1" ,
416- "size" : file .GetSize (),
417- "type" : "file" ,
418- }).Post ("https://api.aliyundrive.com/adrive/v2/file/createWithFolders" ) // /v2/file/create_with_proof
419- //log.Debugf("%+v\n%+v", resp, e)
420- if e .Code != "" {
411+
412+ buf := make ([]byte , 1024 )
413+ n , _ := file .Read (buf [:])
414+ reqBody := base.Json {
415+ "check_name_mode" : "auto_rename" ,
416+ "drive_id" : account .DriveId ,
417+ "name" : file .GetFileName (),
418+ "parent_file_id" : parentFile .Id ,
419+ "part_info_list" : partInfoList ,
420+ "size" : file .GetSize (),
421+ "type" : "file" ,
422+ "pre_hash" : utils .GetSHA1Encode (string (buf [:n ])),
423+ }
424+ fileReader := io .MultiReader (bytes .NewReader (buf [:n ]), file .File )
425+
426+ var resp UploadResp
427+ var e AliRespError
428+ client := aliClient .R ().SetResult (& resp ).SetError (& e ).SetHeader ("authorization" , "Bearer\t " + account .AccessToken ).SetBody (reqBody )
429+
430+ _ , err = client .Post ("https://api.aliyundrive.com/adrive/v2/file/createWithFolders" )
431+ if err != nil {
432+ return err
433+ }
434+ if e .Code != "" && e .Code != "PreHashMatched" {
421435 if e .Code == "AccessTokenInvalid" {
422436 err = driver .RefreshToken (account )
423437 if err != nil {
@@ -429,26 +443,59 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
429443 }
430444 return fmt .Errorf ("%s" , e .Message )
431445 }
432- var byteSize uint64
433- for i = 0 ; i < count ; i ++ {
434- byteSize = file . GetSize () - finish
435- if DEFAULT < byteSize {
436- byteSize = DEFAULT
446+
447+ if e . Code == "PreHashMatched" {
448+ tempFile , err := ioutil . TempFile ( conf . Conf . TempDir , "file-*" )
449+ if err != nil {
450+ return err
437451 }
438- log .Debugf ("%d,%d" , byteSize , finish )
439- byteData := make ([]byte , byteSize )
440- n , err := io .ReadFull (file , byteData )
441- //n, err := file.Read(byteData)
442- //byteData, err := io.ReadAll(file)
443- //n := len(byteData)
444- log .Debug (err , n )
452+
453+ defer tempFile .Close ()
454+ defer os .Remove (tempFile .Name ())
455+
456+ delete (reqBody , "pre_hash" )
457+ h := sha1 .New ()
458+ if _ , err = io .Copy (tempFile , io .TeeReader (fileReader , h )); err != nil {
459+ return err
460+ }
461+ reqBody ["content_hash" ] = hex .EncodeToString (h .Sum (nil ))
462+ reqBody ["content_hash_name" ] = "sha1"
463+ reqBody ["proof_version" ] = "v1"
464+
465+ /*
466+ js 隐性转换太坑不知道有没有bug
467+ var n = e.access_token,
468+ r = new BigNumber('0x'.concat(md5(n).slice(0, 16))),
469+ i = new BigNumber(t.file.size),
470+ o = i ? r.mod(i) : new gt.BigNumber(0);
471+ (t.file.slice(o.toNumber(), Math.min(o.plus(8).toNumber(), t.file.size)))
472+ */
473+ r , _ := new (big.Int ).SetString (utils .GetMD5Encode (account .AccessToken )[:16 ], 16 )
474+ i := new (big.Int ).SetUint64 (file .Size )
475+ o := r .Mod (r , i )
476+ n , _ = io .NewSectionReader (tempFile , o .Int64 (), 8 ).Read (buf [:8 ])
477+ reqBody ["proof_code" ] = base64 .StdEncoding .EncodeToString (buf [:n ])
478+
479+ _ , err = client .Post ("https://api.aliyundrive.com/adrive/v2/file/createWithFolders" )
445480 if err != nil {
446481 return err
447482 }
483+ if e .Code != "" && e .Code != "PreHashMatched" {
484+ return fmt .Errorf ("%s" , e .Message )
485+ }
448486
449- finish += uint64 (n )
487+ if resp .RapidUpload {
488+ return nil
489+ }
450490
451- req , err := http .NewRequest ("PUT" , resp .PartInfoList [i ].UploadUrl , bytes .NewBuffer (byteData ))
491+ if _ , err = tempFile .Seek (0 , io .SeekStart ); err != nil {
492+ return err
493+ }
494+ fileReader = tempFile
495+ }
496+
497+ for i = 0 ; i < count ; i ++ {
498+ req , err := http .NewRequest ("PUT" , resp .PartInfoList [i ].UploadUrl , io .LimitReader (fileReader , DEFAULT ))
452499 if err != nil {
453500 return err
454501 }
@@ -473,6 +520,9 @@ func (driver AliDrive) Upload(file *model.FileStream, account *model.Account) er
473520 "file_id" : resp .FileId ,
474521 "upload_id" : resp .UploadId ,
475522 }).Post ("https://api.aliyundrive.com/v2/file/complete" )
523+ if err != nil {
524+ return err
525+ }
476526 if e .Code != "" {
477527 //if e.Code == "AccessTokenInvalid" {
478528 // err = driver.RefreshToken(account)
0 commit comments