55use Qcloud \Cos \Exception \CosException ;
66use GuzzleHttp \Pool ;
77
8+ use function GuzzleHttp \Promise \rejection_for ;
9+
810class MultipartUpload {
911 const MIN_PART_SIZE = 1048576 ;
1012 const MAX_PART_SIZE = 5368709120 ;
@@ -16,6 +18,9 @@ class MultipartUpload {
1618 private $ partSize ;
1719 private $ parts ;
1820 private $ body ;
21+ private $ progress ;
22+ private $ totolSize ;
23+ private $ uploadedSize ;
1924
2025 public function __construct ($ client , $ body , $ options = array ()) {
2126 $ minPartSize = $ options ['PartSize ' ];
@@ -25,8 +30,13 @@ public function __construct($client, $body, $options = array()) {
2530 $ this ->options = $ options ;
2631 $ this ->partSize = $ this ->calculatePartSize ($ minPartSize );
2732 $ this ->concurrency = isset ($ options ['Concurrency ' ]) ? $ options ['Concurrency ' ] : 10 ;
33+ $ this ->progress = isset ($ options ['Progress ' ]) ? $ options ['Progress ' ] : function ($ totolSize , $ uploadedSize ) {};
2834 $ this ->parts = [];
2935 $ this ->partNumberList = [];
36+ $ this ->uploadedSize = 0 ;
37+ $ this ->totolSize = $ this ->body ->getSize ();
38+ $ this ->needMd5 = isset ($ options ['ContentMD5 ' ]) ? $ options ['ContentMD5 ' ] : true ;
39+ $ this ->retry = isset ($ options ['Retry ' ]) ? $ options ['Retry ' ] : 3 ;
3040 }
3141 public function performUploading () {
3242 $ uploadId = $ this ->initiateMultipartUpload ();
@@ -48,45 +58,60 @@ public function uploadParts($uploadId) {
4858 $ uploadRequests = function ($ uploadId ) {
4959 $ partNumber = 1 ;
5060 $ index = 1 ;
61+ $ offset = 0 ;
62+ $ partSize = 0 ;
5163 for ( ; ; $ partNumber ++) {
5264 if ($ this ->body ->eof ()) {
5365 break ;
5466 }
5567 $ body = $ this ->body ->read ($ this ->partSize );
68+ $ partSize = $ this ->partSize ;
69+ if ($ offset + $ this ->partSize >= $ this ->totolSize ) {
70+ $ partSize = $ this ->totolSize - $ offset ;
71+ }
72+ $ offset += $ partSize ;
5673 if (empty ($ body )) {
5774 break ;
5875 }
5976 if (isset ($ this ->parts [$ partNumber ])) {
6077 continue ;
6178 }
62- $ this ->partNumberList [$ index ] = $ partNumber ;
79+ $ this ->partNumberList [$ index ]['PartNumber ' ] = $ partNumber ;
80+ $ this ->partNumberList [$ index ]['PartSize ' ] = $ partSize ;
6381 $ params = array (
6482 'Bucket ' => $ this ->options ['Bucket ' ],
6583 'Key ' => $ this ->options ['Key ' ],
6684 'UploadId ' => $ uploadId ,
6785 'PartNumber ' => $ partNumber ,
68- 'Body ' => $ body
86+ 'Body ' => $ body ,
87+ 'ContentMD5 ' => $ this ->needMd5
6988 );
70- if (!isset ($ this ->parts [$ partNumber ])) {
89+ if ($ this ->needMd5 == false ) {
90+ unset($ params ["ContentMD5 " ]);
91+ }
92+ if (!isset ($ this ->parts [$ partNumber ])) {
7193 $ command = $ this ->client ->getCommand ('uploadPart ' , $ params );
7294 $ request = $ this ->client ->commandToRequestTransformer ($ command );
7395 $ index ++;
7496 yield $ request ;
7597 }
7698 }
77- };
99+ };
78100 $ pool = new Pool ($ this ->client ->httpClient , $ uploadRequests ($ uploadId ), [
79101 'concurrency ' => $ this ->concurrency ,
80102 'fulfilled ' => function ($ response , $ index ) {
81103 $ index = $ index + 1 ;
82- $ partNumber = $ this ->partNumberList [$ index ];
104+ $ partNumber = $ this ->partNumberList [$ index ]['PartNumber ' ];
105+ $ partSize = $ this ->partNumberList [$ index ]['PartSize ' ];
83106 $ etag = $ response ->getHeaders ()["ETag " ][0 ];
84107 $ part = array ('PartNumber ' => $ partNumber , 'ETag ' => $ etag );
85108 $ this ->parts [$ partNumber ] = $ part ;
109+ $ this ->uploadedSize += $ partSize ;
110+ call_user_func_array ($ this ->progress , [$ this ->totolSize , $ this ->uploadedSize ]);
86111 },
87112
88113 'rejected ' => function ($ reason , $ index ) {
89- throw ( $ reason );
114+ printf ( " part [%d] upload failed, reason: %s \n" , $ index , $ reason );
90115 }
91116 ]);
92117 $ promise = $ pool ->promise ();
0 commit comments