@@ -552,7 +552,7 @@ func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
552
552
firstPartInfos = firstPartInfos [:100 ]
553
553
}
554
554
555
- // 获取上传信息和前100个分片的上传地址
555
+ // 创建任务, 获取上传信息和前100个分片的上传地址
556
556
data := base.Json {
557
557
"contentHash" : fullHash ,
558
558
"contentHashAlgorithm" : "SHA256" ,
@@ -572,87 +572,156 @@ func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
572
572
return err
573
573
}
574
574
575
- if resp .Data .Exist || resp .Data .RapidUpload {
575
+ // 判断文件是否已存在
576
+ // resp.Data.Exist: true 已存在同名文件且校验相同,云端不会重复增加文件,无需手动处理冲突
577
+ if resp .Data .Exist {
576
578
return nil
577
579
}
578
580
579
- uploadPartInfos := resp .Data .PartInfos
581
+ // 判断文件是否支持快传
582
+ // resp.Data.RapidUpload: true 支持快传,但此处直接检测是否返回分片的上传地址
583
+ // 快传的情况下同样需要手动处理冲突
584
+ if resp .Data .PartInfos != nil {
585
+ // 读取前100个分片的上传地址
586
+ uploadPartInfos := resp .Data .PartInfos
587
+
588
+ // 获取后续分片的上传地址
589
+ for i := 101 ; i < len (partInfos ); i += 100 {
590
+ end := i + 100
591
+ if end > len (partInfos ) {
592
+ end = len (partInfos )
593
+ }
594
+ batchPartInfos := partInfos [i :end ]
595
+
596
+ moredata := base.Json {
597
+ "fileId" : resp .Data .FileId ,
598
+ "uploadId" : resp .Data .UploadId ,
599
+ "partInfos" : batchPartInfos ,
600
+ "commonAccountInfo" : base.Json {
601
+ "account" : d .Account ,
602
+ "accountType" : 1 ,
603
+ },
604
+ }
605
+ pathname := "/hcy/file/getUploadUrl"
606
+ var moreresp PersonalUploadUrlResp
607
+ _ , err = d .personalPost (pathname , moredata , & moreresp )
608
+ if err != nil {
609
+ return err
610
+ }
611
+ uploadPartInfos = append (uploadPartInfos , moreresp .Data .PartInfos ... )
612
+ }
580
613
581
- // 获取后续分片的上传地址
582
- for i := 101 ; i < len (partInfos ); i += 100 {
583
- end := i + 100
584
- if end > len (partInfos ) {
585
- end = len (partInfos )
614
+ // Progress
615
+ p := driver .NewProgress (stream .GetSize (), up )
616
+
617
+ // 上传所有分片
618
+ for _ , uploadPartInfo := range uploadPartInfos {
619
+ index := uploadPartInfo .PartNumber - 1
620
+ partSize := partInfos [index ].PartSize
621
+ log .Debugf ("[139] uploading part %+v/%+v" , index , len (uploadPartInfos ))
622
+ limitReader := io .LimitReader (stream , partSize )
623
+
624
+ // Update Progress
625
+ r := io .TeeReader (limitReader , p )
626
+
627
+ req , err := http .NewRequest ("PUT" , uploadPartInfo .UploadUrl , r )
628
+ if err != nil {
629
+ return err
630
+ }
631
+ req = req .WithContext (ctx )
632
+ req .Header .Set ("Content-Type" , "application/octet-stream" )
633
+ req .Header .Set ("Content-Length" , fmt .Sprint (partSize ))
634
+ req .Header .Set ("Origin" , "https://yun.139.com" )
635
+ req .Header .Set ("Referer" , "https://yun.139.com/" )
636
+ req .ContentLength = partSize
637
+
638
+ res , err := base .HttpClient .Do (req )
639
+ if err != nil {
640
+ return err
641
+ }
642
+ _ = res .Body .Close ()
643
+ log .Debugf ("[139] uploaded: %+v" , res )
644
+ if res .StatusCode != http .StatusOK {
645
+ return fmt .Errorf ("unexpected status code: %d" , res .StatusCode )
646
+ }
586
647
}
587
- batchPartInfos := partInfos [i :end ]
588
648
589
- moredata := base.Json {
590
- "fileId" : resp .Data .FileId ,
591
- "uploadId" : resp .Data .UploadId ,
592
- "partInfos" : batchPartInfos ,
593
- "commonAccountInfo" : base.Json {
594
- "account" : d .Account ,
595
- "accountType" : 1 ,
596
- },
649
+ data = base.Json {
650
+ "contentHash" : fullHash ,
651
+ "contentHashAlgorithm" : "SHA256" ,
652
+ "fileId" : resp .Data .FileId ,
653
+ "uploadId" : resp .Data .UploadId ,
597
654
}
598
- pathname := "/hcy/file/getUploadUrl"
599
- var moreresp PersonalUploadUrlResp
600
- _ , err = d .personalPost (pathname , moredata , & moreresp )
655
+ _ , err = d .personalPost ("/hcy/file/complete" , data , nil )
601
656
if err != nil {
602
657
return err
603
658
}
604
- uploadPartInfos = append (uploadPartInfos , moreresp .Data .PartInfos ... )
605
659
}
606
660
607
- // Progress
608
- p := driver .NewProgress (stream .GetSize (), up )
609
-
610
- // 上传所有分片
611
- for _ , uploadPartInfo := range uploadPartInfos {
612
- index := uploadPartInfo .PartNumber - 1
613
- partSize := partInfos [index ].PartSize
614
- log .Debugf ("[139] uploading part %+v/%+v" , index , len (uploadPartInfos ))
615
- limitReader := io .LimitReader (stream , partSize )
616
-
617
- // Update Progress
618
- r := io .TeeReader (limitReader , p )
619
-
620
- req , err := http .NewRequest ("PUT" , uploadPartInfo .UploadUrl , r )
661
+ // 处理冲突
662
+ if resp .Data .FileName != stream .GetName () {
663
+ log .Debugf ("[139] conflict detected: %s != %s" , resp .Data .FileName , stream .GetName ())
664
+ // 给服务器一定时间处理数据,避免无法刷新文件列表
665
+ time .Sleep (time .Millisecond * 500 )
666
+ // 刷新并获取文件列表
667
+ files , err := d .List (ctx , dstDir , model.ListArgs {Refresh : true })
621
668
if err != nil {
622
669
return err
623
670
}
624
- req = req .WithContext (ctx )
625
- req .Header .Set ("Content-Type" , "application/octet-stream" )
626
- req .Header .Set ("Content-Length" , fmt .Sprint (partSize ))
627
- req .Header .Set ("Origin" , "https://yun.139.com" )
628
- req .Header .Set ("Referer" , "https://yun.139.com/" )
629
- req .ContentLength = partSize
630
-
631
- res , err := base .HttpClient .Do (req )
632
- if err != nil {
633
- return err
671
+ // 删除旧文件
672
+ for _ , file := range files {
673
+ if file .GetName () == stream .GetName () {
674
+ log .Debugf ("[139] conflict: removing old: %s" , file .GetName ())
675
+ // 删除前重命名旧文件,避免仍旧冲突
676
+ err = d .Rename (ctx , file , stream .GetName ()+ random .String (4 ))
677
+ if err != nil {
678
+ return err
679
+ }
680
+ err = d .Remove (ctx , file )
681
+ if err != nil {
682
+ return err
683
+ }
684
+ break
685
+ }
634
686
}
635
- _ = res .Body .Close ()
636
- log .Debugf ("[139] uploaded: %+v" , res )
637
- if res .StatusCode != http .StatusOK {
638
- return fmt .Errorf ("unexpected status code: %d" , res .StatusCode )
687
+ // 重命名新文件
688
+ for _ , file := range files {
689
+ if file .GetName () == resp .Data .FileName {
690
+ log .Debugf ("[139] conflict: renaming new: %s => %s" , file .GetName (), stream .GetName ())
691
+ err = d .Rename (ctx , file , stream .GetName ())
692
+ if err != nil {
693
+ return err
694
+ }
695
+ break
696
+ }
639
697
}
640
698
}
641
-
642
- data = base.Json {
643
- "contentHash" : fullHash ,
644
- "contentHashAlgorithm" : "SHA256" ,
645
- "fileId" : resp .Data .FileId ,
646
- "uploadId" : resp .Data .UploadId ,
647
- }
648
- _ , err = d .personalPost ("/hcy/file/complete" , data , nil )
649
- if err != nil {
650
- return err
651
- }
652
699
return nil
653
700
case MetaPersonal :
654
701
fallthrough
655
702
case MetaFamily :
703
+ // 处理冲突
704
+ // 获取文件列表
705
+ files , err := d .List (ctx , dstDir , model.ListArgs {})
706
+ if err != nil {
707
+ return err
708
+ }
709
+ // 删除旧文件
710
+ for _ , file := range files {
711
+ if file .GetName () == stream .GetName () {
712
+ log .Debugf ("[139] conflict: removing old: %s" , file .GetName ())
713
+ // 删除前重命名旧文件,避免仍旧冲突
714
+ err = d .Rename (ctx , file , stream .GetName ()+ random .String (4 ))
715
+ if err != nil {
716
+ return err
717
+ }
718
+ err = d .Remove (ctx , file )
719
+ if err != nil {
720
+ return err
721
+ }
722
+ break
723
+ }
724
+ }
656
725
data := base.Json {
657
726
"manualRename" : 2 ,
658
727
"operation" : 0 ,
@@ -688,7 +757,7 @@ func (d *Yun139) Put(ctx context.Context, dstDir model.Obj, stream model.FileStr
688
757
pathname = "/orchestration/familyCloud-rebuild/content/v1.0/getFileUploadURL"
689
758
}
690
759
var resp UploadResp
691
- _ , err : = d .post (pathname , data , & resp )
760
+ _ , err = d .post (pathname , data , & resp )
692
761
if err != nil {
693
762
return err
694
763
}
0 commit comments