/** * {@inheritdoc} */ protected function transfer() { while (!$this->stopped && !$this->source->isConsumed()) { if ($this->source->getContentLength() && $this->source->isSeekable()) { // If the stream is seekable and the Content-Length known, then stream from the data source $body = new ReadLimitEntityBody($this->source, $this->partSize, $this->source->ftell()); } else { // We need to read the data source into a temporary buffer before streaming $body = EntityBody::factory(); while ($body->getContentLength() < $this->partSize && $body->write($this->source->read(max(1, min(10 * Size::KB, $this->partSize - $body->getContentLength()))))) { } } // @codeCoverageIgnoreStart if ($body->getContentLength() == 0) { break; } // @codeCoverageIgnoreEnd $params = $this->state->getUploadId()->toParams(); $command = $this->client->getCommand('UploadPart', array_replace($params, array('PartNumber' => count($this->state) + 1, 'Body' => $body, 'ContentMD5' => (bool) $this->options['part_md5'], Ua::OPTION => Ua::MULTIPART_UPLOAD))); // Notify observers that the part is about to be uploaded $eventData = $this->getEventData(); $eventData['command'] = $command; $this->dispatch(self::BEFORE_PART_UPLOAD, $eventData); // Allow listeners to stop the transfer if needed if ($this->stopped) { break; } $response = $command->getResponse(); $this->state->addPart(UploadPart::fromArray(array('PartNumber' => count($this->state) + 1, 'ETag' => $response->getHeader('ETag', true), 'Size' => $body->getContentLength(), 'LastModified' => gmdate(DateFormat::RFC2822)))); // Notify observers that the part was uploaded $this->dispatch(self::AFTER_PART_UPLOAD, $eventData); } }
/** * {@inheritdoc} */ public static function fromUploadId(AwsClientInterface $client, UploadIdInterface $uploadId) { $transferState = new self($uploadId); foreach ($client->getIterator('ListParts', $uploadId->toParams()) as $part) { $transferState->addPart(UploadPart::fromArray($part)); } return $transferState; }
public function testBasicOperations() { $date = gmdate(DateFormat::RFC2822); /** @var $part UploadPart */ $part = UploadPart::fromArray(array('PartNumber' => 3, 'ETag' => 'aaa', 'LastModified' => $date, 'Size' => 5)); $this->assertEquals(3, $part->getPartNumber()); $this->assertEquals('aaa', $part->getETag()); $this->assertEquals($date, $part->getLastModified()); $this->assertEquals(5, $part->getSize()); }
public function prepareTransfer($useRealClient = false, $contentLength = AbstractTransfer::MIN_PART_SIZE, $partLength = AbstractTransfer::MIN_PART_SIZE) { $uploadId = $this->getMockBuilder('Aws\\S3\\Model\\MultipartUpload\\UploadId')->setMethods(array('toParams'))->getMock(); $uploadId->expects($this->any())->method('toParams')->will($this->returnValue(array('Bucket' => 'foo', 'Key' => 'bar', 'UploadId' => 'baz'))); $body = $this->getMockBuilder('Guzzle\\Http\\EntityBody')->disableOriginalConstructor()->setMethods(array('getContentLength'))->getMock(); $body->expects($this->any())->method('getContentLength')->will($this->returnValue($contentLength)); if ($useRealClient) { $client = $this->getServiceBuilder()->get('s3', true); } else { $client = $this->getMockBuilder('Aws\\S3\\S3Client')->disableOriginalConstructor()->getMock(); } $state = $this->getMockBuilder('Aws\\S3\\Model\\MultipartUpload\\TransferState')->disableOriginalConstructor()->getMock(); $state->expects($this->any())->method('getUploadId')->will($this->returnValue($uploadId)); $state->expects($this->any())->method('getIterator')->will($this->returnValue(new \ArrayIterator(array(UploadPart::fromArray(array('PartNumber' => 1, 'ETag' => 'aaa', 'LastModified' => gmdate(DateFormat::RFC2822), 'Size' => 5)), UploadPart::fromArray(array('PartNumber' => 2, 'ETag' => 'bbb', 'LastModified' => gmdate(DateFormat::RFC2822), 'Size' => 5)))))); $this->client = $client; $this->transfer = $this->getMockForAbstractClass('Aws\\S3\\Model\\MultipartUpload\\AbstractTransfer', array($client, $state, $body, array('min_part_size' => $partLength))); }
/** * {@inheritdoc} */ protected function transfer() { $totalParts = (int) ceil($this->source->getContentLength() / $this->partSize); $concurrency = min($totalParts, $this->options['concurrency']); $partsToSend = $this->prepareParts($concurrency); $eventData = $this->getEventData(); while (!$this->stopped && count($this->state) < $totalParts) { $currentTotal = count($this->state); $commands = array(); for ($i = 0; $i < $concurrency && $i + $currentTotal < $totalParts; $i++) { // Move the offset to the correct position $partsToSend[$i]->setOffset(($currentTotal + $i) * $this->partSize); // @codeCoverageIgnoreStart if ($partsToSend[$i]->getContentLength() == 0) { break; } // @codeCoverageIgnoreEnd $params = $this->state->getUploadId()->toParams(); $eventData['command'] = $this->client->getCommand('UploadPart', array_replace($params, array('PartNumber' => count($this->state) + 1 + $i, 'Body' => $partsToSend[$i], 'ContentMD5' => (bool) $this->options['part_md5'], Ua::OPTION => Ua::MULTIPART_UPLOAD))); $commands[] = $eventData['command']; // Notify any listeners of the part upload $this->dispatch(self::BEFORE_PART_UPLOAD, $eventData); } // Allow listeners to stop the transfer if needed if ($this->stopped) { break; } // Execute each command, iterate over the results, and add to the transfer state /** @var \Guzzle\Service\Command\OperationCommand $command */ foreach ($this->client->execute($commands) as $command) { $this->state->addPart(UploadPart::fromArray(array('PartNumber' => count($this->state) + 1, 'ETag' => $command->getResponse()->getEtag(), 'Size' => (int) $command->getResponse()->getContentLength(), 'LastModified' => gmdate(DateFormat::RFC2822)))); $eventData['command'] = $command; // Notify any listeners the the part was uploaded $this->dispatch(self::AFTER_PART_UPLOAD, $eventData); } } }