/**
  * {@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' => $command['PartNumber'], 'ETag' => $response->getEtag(), '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(MssClientInterface $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('Mss\\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('Mss\\S3\\S3Client')->disableOriginalConstructor()->getMock();
     }
     $state = $this->getMockBuilder('Mss\\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('Mss\\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' => $command['PartNumber'], 'ETag' => $command->getResponse()->getEtag(), 'Size' => (int) $command->getRequest()->getBody()->getContentLength(), 'LastModified' => gmdate(DateFormat::RFC2822))));
             $eventData['command'] = $command;
             // Notify any listeners the the part was uploaded
             $this->dispatch(self::AFTER_PART_UPLOAD, $eventData);
         }
     }
 }