Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Progress Tracker for MultipartUploader & MultipartCopy #2699

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
b2d70f6
multipart uploader method
cintiashamsu Apr 17, 2023
51f7574
update displayProgress method
cintiashamsu Apr 17, 2023
5cb12d5
removed comments
cintiashamsu Apr 17, 2023
ebd06c4
added ability to display progressBar for MultipartUpload and Multipar…
cintiashamsu Apr 19, 2023
6dc3597
Update UploadState.php
cintiashamsu Apr 19, 2023
7f05ff1
Update AbstractUploader.php
cintiashamsu Apr 19, 2023
657ab9a
MultipartUploader and MultipartCopy now sends total size directly to …
cintiashamsu Apr 19, 2023
89c9513
Update UploadStateTest.php
cintiashamsu Apr 24, 2023
d68597c
Added assert using expectOutputString and structure for data provider
cintiashamsu Apr 24, 2023
99738f8
added two tests
cintiashamsu Apr 26, 2023
604df58
Update UploadState.php
cintiashamsu Apr 26, 2023
12e328d
Update UploadStateTest.php
cintiashamsu Apr 28, 2023
e42ab91
Update UploadStateTest.php
cintiashamsu May 1, 2023
470627a
Combine progressThresholds and progressBar into one array
cintiashamsu May 1, 2023
8cfe7e9
Updated displayProgress to use progressBar
cintiashamsu May 1, 2023
9ade473
Update UploadState.php
cintiashamsu May 2, 2023
74e7938
added exceptions for non-int arguments
cintiashamsu May 3, 2023
5eded67
Added unit tests for failed upload and type checking
cintiashamsu May 3, 2023
735c9c4
Added config option
cintiashamsu May 5, 2023
cff396a
added config option to multipartUploader and multipartCopy
cintiashamsu May 10, 2023
776cc4d
added another parameter to markPartAsUploaded for possible Glacier su…
cintiashamsu May 15, 2023
465fc61
added descriptions for methods, cleaned up tests
cintiashamsu May 24, 2023
e2d4e81
PHPUnit Polyfills on UploadStateTest
cintiashamsu May 26, 2023
1a0a580
removed array_key_first to support php 5.5
cintiashamsu May 26, 2023
eee6a67
dev guide description added
cintiashamsu May 30, 2023
1156b75
added method setDisplayProgress, changelog
cintiashamsu Jun 9, 2023
da296ce
$displayProgress not declared dynamically
cintiashamsu Jun 9, 2023
9ea4f20
line-wrap in upload state
cintiashamsu Jun 10, 2023
102f26d
Merge branch 'aws:master' into new-feature
cintiashamsu Jun 10, 2023
367bc01
=== comparison operator
cintiashamsu Jun 27, 2023
d81c87b
Update MultipartUploaderTest.php
cintiashamsu Jun 27, 2023
39b1044
displayprogress set in multipartuploader/copy
cintiashamsu Jun 27, 2023
362ae07
Merge branch 'master' into new-feature
stobrien89 Jun 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/nextrelease/feature-progress-tracker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[
{
"type": "enhancement",
"category": "S3",
"description": "'track_upload' configuration option added for MultipartUpload and MultipartCopy"
}
]
11 changes: 10 additions & 1 deletion src/Multipart/AbstractUploadManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ abstract class AbstractUploadManager implements Promise\PromisorInterface
/** @var UploadState State used to manage the upload. */
protected $state;

/** @var bool Configuration used to indicate if upload progress will be displayed. */
protected $displayProgress;

/**
* @param Client $client
* @param array $config
Expand All @@ -59,6 +62,12 @@ public function __construct(Client $client, array $config = [])
$this->info = $this->loadUploadWorkflowInfo();
$this->config = $config + self::$defaultConfig;
$this->state = $this->determineState();

if (isset($config['display_progress'])
&& is_bool($config['display_progress'])
) {
$this->displayProgress = $config['display_progress'];
}
}

/**
Expand Down Expand Up @@ -238,7 +247,7 @@ private function determineState(): UploadState
}
$id[$param] = $this->config[$key];
}
$state = new UploadState($id);
$state = new UploadState($id, $this->config);
$state->setPartSize($this->determinePartSize());

return $state;
Expand Down
3 changes: 3 additions & 0 deletions src/Multipart/AbstractUploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ abstract class AbstractUploader extends AbstractUploadManager
/** @var Stream Source of the data to be uploaded. */
protected $source;

/** @var bool Configuration used to indicate if upload progress will be displayed. */
protected $displayProgress;

/**
* @param Client $client
* @param mixed $source
Expand Down
75 changes: 72 additions & 3 deletions src/Multipart/UploadState.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ class UploadState
const INITIATED = 1;
const COMPLETED = 2;

private $progressBar = [
"Transfer initiated...\n| | 0.0%\n",
"|== | 12.5%\n",
"|===== | 25.0%\n",
"|======= | 37.5%\n",
"|========== | 50.0%\n",
"|============ | 62.5%\n",
"|=============== | 75.0%\n",
"|================= | 87.5%\n",
"|====================| 100.0%\nTransfer complete!\n"
];

/** @var array Params used to identity the upload. */
private $id;

Expand All @@ -25,12 +37,24 @@ class UploadState
/** @var int Identifies the status the upload. */
private $status = self::CREATED;

/** @var array Thresholds for progress of the upload. */
private $progressThresholds = [];

/** @var boolean Determines status for tracking the upload */
private $displayProgress = false;

/**
* @param array $id Params used to identity the upload.
*/
public function __construct(array $id)
public function __construct(array $id, array $config = [])
{
$this->id = $id;

if (isset($config['display_progress'])
&& is_bool($config['display_progress'])
) {
$this->displayProgress = $config['display_progress'];
}
}

/**
Expand All @@ -45,7 +69,7 @@ public function getId()
}

/**
* Set's the "upload_id", or 3rd part of the upload's ID. This typically
* Sets the "upload_id", or 3rd part of the upload's ID. This typically
* only needs to be done after initiating an upload.
*
* @param string $key The param key of the upload_id.
Expand Down Expand Up @@ -76,6 +100,52 @@ public function setPartSize($partSize)
$this->partSize = $partSize;
}

/**
* Sets the 1/8th thresholds array. $totalSize is only sent if
* 'track_upload' is true.
*
* @param $totalSize numeric Size of object to upload.
*
* @return array
*/
public function setProgressThresholds($totalSize): array
{
if(!is_numeric($totalSize)) {
throw new \InvalidArgumentException(
'The total size of the upload must be a number.'
);
}

$this->progressThresholds[0] = 0;
for ($i = 1; $i <= 8; $i++) {
$this->progressThresholds[] = round($totalSize * ($i / 8));
}
return $this->progressThresholds;
}

/**
* Prints progress of upload.
*
* @param $totalUploaded numeric Size of upload so far.
*/
public function getDisplayProgress($totalUploaded): void
{
if (!is_numeric($totalUploaded)) {
throw new \InvalidArgumentException(
'The size of the bytes being uploaded must be a number.'
);
}

if ($this->displayProgress) {
while (!empty($this->progressBar)
&& $totalUploaded >= $this->progressThresholds[0]
) {
echo array_shift($this->progressBar);
stobrien89 marked this conversation as resolved.
Show resolved Hide resolved
array_shift($this->progressThresholds);
}
}
}

/**
* Marks a part as being uploaded.
*
Expand Down Expand Up @@ -108,7 +178,6 @@ public function hasPartBeenUploaded($partNumber)
public function getUploadedParts()
{
ksort($this->uploadedParts);

return $this->uploadedParts;
}

Expand Down
9 changes: 8 additions & 1 deletion src/S3/MultipartCopy.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class MultipartCopy extends AbstractUploadManager
* options are ignored.
* - source_metadata: (Aws\ResultInterface) An object that represents the
* result of executing a HeadObject command on the copy source.
* - display_progress: (boolean) Set true to track status in 1/8th increments
* for upload.
*
* @param S3ClientInterface $client Client used for the upload.
* @param string|array $source Location of the data to be copied (in the
Expand All @@ -75,6 +77,12 @@ public function __construct(
$client,
array_change_key_case($config) + ['source_metadata' => null]
);

if ($this->displayProgress) {
$this->getState()->setProgressThresholds(
$this->sourceMetadata["ContentLength"]
);
}
}

/**
Expand Down Expand Up @@ -238,5 +246,4 @@ private function getInputSource($inputSource)
$sourceBuilder .= ltrim(rawurldecode($inputSource), '/');
return $sourceBuilder;
}

}
6 changes: 6 additions & 0 deletions src/S3/MultipartUploader.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class MultipartUploader extends AbstractUploader
* of the multipart upload and that is used to resume a previous upload.
* When this option is provided, the `bucket`, `key`, and `part_size`
* options are ignored.
* - track_upload: (boolean) Set true to track status in 1/8th increments
* for upload.
*
* @param S3ClientInterface $client Client used for the upload.
* @param mixed $source Source of the data to upload.
Expand All @@ -70,6 +72,10 @@ public function __construct(
'key' => null,
'exception_class' => S3MultipartUploadException::class,
]);

if ($this->displayProgress) {
$this->getState()->setProgressThresholds($this->source->getSize());
}
}

protected function loadUploadWorkflowInfo()
Expand Down
9 changes: 9 additions & 0 deletions src/S3/MultipartUploadingTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

trait MultipartUploadingTrait
{
private $uploadedBytes = 0;

/**
* Creates an UploadState object for a multipart upload by querying the
* service for the specified upload's information.
Expand Down Expand Up @@ -59,6 +61,13 @@ protected function handleResult(CommandInterface $command, ResultInterface $resu
$partData[$checksumMemberName] = $result[$checksumMemberName];
}
$this->getState()->markPartAsUploaded($command['PartNumber'], $partData);

// Updates counter for uploaded bytes.
$this->uploadedBytes += $command["ContentLength"];
// Sends uploaded bytes to progress tracker if getDisplayProgress set
if ($this->displayProgress) {
$this->getState()->getDisplayProgress($this->uploadedBytes);
}
}

abstract protected function extractETag(ResultInterface $result);
Expand Down
Loading