|
|
|
|
@ -6,6 +6,8 @@
|
|
|
|
|
*/
|
|
|
|
|
namespace OC\Files\ObjectStore;
|
|
|
|
|
|
|
|
|
|
use Aws\Command;
|
|
|
|
|
use Aws\Exception\MultipartUploadException;
|
|
|
|
|
use Aws\S3\Exception\S3MultipartUploadException;
|
|
|
|
|
use Aws\S3\MultipartCopy;
|
|
|
|
|
use Aws\S3\MultipartUploader;
|
|
|
|
|
@ -96,7 +98,9 @@ trait S3ObjectTrait {
|
|
|
|
|
protected function writeSingle(string $urn, StreamInterface $stream, array $metaData): void {
|
|
|
|
|
$mimetype = $metaData['mimetype'] ?? null;
|
|
|
|
|
unset($metaData['mimetype']);
|
|
|
|
|
$this->getConnection()->putObject([
|
|
|
|
|
unset($metaData['size']);
|
|
|
|
|
|
|
|
|
|
$args = [
|
|
|
|
|
'Bucket' => $this->bucket,
|
|
|
|
|
'Key' => $urn,
|
|
|
|
|
'Body' => $stream,
|
|
|
|
|
@ -104,7 +108,13 @@ trait S3ObjectTrait {
|
|
|
|
|
'ContentType' => $mimetype,
|
|
|
|
|
'Metadata' => $this->buildS3Metadata($metaData),
|
|
|
|
|
'StorageClass' => $this->storageClass,
|
|
|
|
|
] + $this->getSSECParameters());
|
|
|
|
|
] + $this->getSSECParameters();
|
|
|
|
|
|
|
|
|
|
if ($size = $stream->getSize()) {
|
|
|
|
|
$args['ContentLength'] = $size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$this->getConnection()->putObject($args);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -119,12 +129,15 @@ trait S3ObjectTrait {
|
|
|
|
|
protected function writeMultiPart(string $urn, StreamInterface $stream, array $metaData): void {
|
|
|
|
|
$mimetype = $metaData['mimetype'] ?? null;
|
|
|
|
|
unset($metaData['mimetype']);
|
|
|
|
|
unset($metaData['size']);
|
|
|
|
|
|
|
|
|
|
$attempts = 0;
|
|
|
|
|
$uploaded = false;
|
|
|
|
|
$concurrency = $this->concurrency;
|
|
|
|
|
$exception = null;
|
|
|
|
|
$state = null;
|
|
|
|
|
$size = $stream->getSize();
|
|
|
|
|
$totalWritten = 0;
|
|
|
|
|
|
|
|
|
|
// retry multipart upload once with concurrency at half on failure
|
|
|
|
|
while (!$uploaded && $attempts <= 1) {
|
|
|
|
|
@ -139,6 +152,15 @@ trait S3ObjectTrait {
|
|
|
|
|
'Metadata' => $this->buildS3Metadata($metaData),
|
|
|
|
|
'StorageClass' => $this->storageClass,
|
|
|
|
|
] + $this->getSSECParameters(),
|
|
|
|
|
'before_upload' => function (Command $command) use (&$totalWritten) {
|
|
|
|
|
$totalWritten += $command['ContentLength'];
|
|
|
|
|
},
|
|
|
|
|
'before_complete' => function ($_command) use (&$totalWritten, $size, &$uploader, &$attempts) {
|
|
|
|
|
if ($size !== null && $totalWritten != $size) {
|
|
|
|
|
$e = new \Exception('Incomplete multi part upload, expected ' . $size . ' bytes, wrote ' . $totalWritten);
|
|
|
|
|
throw new MultipartUploadException($uploader->getState(), $e);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
@ -155,6 +177,9 @@ trait S3ObjectTrait {
|
|
|
|
|
if ($stream->isSeekable()) {
|
|
|
|
|
$stream->rewind();
|
|
|
|
|
}
|
|
|
|
|
} catch (MultipartUploadException $e) {
|
|
|
|
|
$exception = $e;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -180,7 +205,9 @@ trait S3ObjectTrait {
|
|
|
|
|
|
|
|
|
|
public function writeObjectWithMetaData(string $urn, $stream, array $metaData): void {
|
|
|
|
|
$canSeek = fseek($stream, 0, SEEK_CUR) === 0;
|
|
|
|
|
$psrStream = Utils::streamFor($stream);
|
|
|
|
|
$psrStream = Utils::streamFor($stream, [
|
|
|
|
|
'size' => $metaData['size'] ?? null,
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$size = $psrStream->getSize();
|
|
|
|
|
|