/**
  * Perform a request and return a promise object (an object
  * implementing then method)
  *
  * @param RequestInterface $request
  * @param array $options
  *
  * @return object|P\PromiseInterface
  */
 public function send(RequestInterface $request, array $options = [])
 {
     $request = $this->preRequest($request, $options);
     $promise = $this->transport->exec($request)->then(function (ResponseInterface $response) use($request, $options, &$promise) {
         $event = $this->responseEvent($request, $response, $options);
         $response = $event->getResponse();
         if (!$this->isResponseOK($response)) {
             return P\rejection_for($event);
         }
         return $response;
     })->then(null, function (ResponseEvent $event) use($options) {
         // options is passed by reference. Use array_merge to ensure
         // opts is a copy and not a reference
         $opts = array_merge([], $options);
         $naReq = $this->getNextRequest($event, $opts);
         if ($naReq) {
             $options['exceptions'] = false;
             return $this->send($naReq, $opts);
         }
         $response = $event->getResponse();
         if ($options['exceptions']) {
             throw new BadApiResponseException($response, $response->getStatusCode(), $response->getReasonPhrase());
         }
         return $response;
     });
     // Add in shutdown queue
     $this->queue->add(function () use($promise) {
         $promise->wait(false);
     });
     return $promise;
 }
 /**
  * Returns a promise that will clean up any references when it completes.
  *
  * @return PromiseInterface
  */
 private function createPromise()
 {
     // Create the promise
     $promise = call_user_func($this->promiseCreator, $this);
     $this->promiseCreator = null;
     // Cleans up the promise state and references.
     $cleanup = function () {
         $this->before = $this->client = $this->queue = null;
     };
     // When done, ensure cleanup and that any remaining are processed.
     return $promise->then(function () use($cleanup) {
         return Promise\promise_for($this->flushQueue())->then($cleanup);
     }, function ($reason) use($cleanup) {
         $cleanup();
         return Promise\rejection_for($reason);
     });
 }
Example #3
0
 /**
  * Transfers the given request and applies request options.
  *
  * The URI of the request is not modified and the request options are used
  * as-is without merging in default options.
  *
  * @param RequestInterface $request
  * @param array            $options
  *
  * @return Promise\PromiseInterface
  */
 private function transfer(RequestInterface $request, array $options)
 {
     // save_to -> sink
     if (isset($options['save_to'])) {
         $options['sink'] = $options['save_to'];
         unset($options['save_to']);
     }
     // exceptions -> http_errors
     if (isset($options['exceptions'])) {
         $options['http_errors'] = $options['exceptions'];
         unset($options['exceptions']);
     }
     $request = $this->applyOptions($request, $options);
     $handler = $options['handler'];
     try {
         return Promise\promise_for($handler($request, $options));
     } catch (\Exception $e) {
         return Promise\rejection_for($e);
     }
 }
Example #4
0
 /**
  * Tracks command and request history using a history container.
  *
  * This is useful for testing.
  *
  * @param History $history History container to store entries.
  *
  * @return callable
  */
 public static function history(History $history)
 {
     return function (callable $handler) use($history) {
         return function (CommandInterface $command, RequestInterface $request = null) use($handler, $history) {
             $ticket = $history->start($command, $request);
             return $handler($command, $request)->then(function ($result) use($history, $ticket) {
                 $history->finish($ticket, $result);
                 return $result;
             }, function ($reason) use($history, $ticket) {
                 $history->finish($ticket, $reason);
                 return Promise\rejection_for($reason);
             });
         };
     };
 }
Example #5
0
 private function createDownloadPromise()
 {
     // Prepare args for ListObjects.
     $listArgs = $this->getS3Args($this->source['path']);
     if (isset($listArgs['Key'])) {
         $listArgs['Prefix'] = $listArgs['Key'] . '/';
         unset($listArgs['Key']);
     }
     // Get the Paginator for ListObjects
     $objects = $this->client->getPaginator('ListObjects', $listArgs);
     // Asynchronously execute the paginator, building command pools to
     // download the objects.
     return $objects->each(function (ResultInterface $result) use($listArgs) {
         $commands = [];
         $prefix = isset($listArgs['Prefix']) ? $listArgs['Prefix'] : null;
         foreach ($result->search('Contents[].Key') as $key) {
             // Skip files on S3 that just mark the existence of a folder.
             if (substr($key, -1, 1) === '/') {
                 continue;
             }
             // Prepare the sink.
             $localKey = $key;
             if ($prefix && strpos($localKey, $prefix) === 0) {
                 $localKey = substr($key, strlen($prefix));
             }
             $sink = $this->destination['path'] . '/' . $localKey;
             // Create the directory if needed.
             $dir = dirname($sink);
             if (!is_dir($dir) && !mkdir($dir, 0777, true)) {
                 return Promise\rejection_for(new \RuntimeException("Could not create dir: {$dir}"));
             }
             // Create the command.
             $commands[] = $this->client->getCommand('GetObject', ['Bucket' => $listArgs['Bucket'], 'Key' => $key, '@http' => ['sink' => $sink]]);
         }
         // Create a GetObject command pool and return the promise.
         return (new Aws\CommandPool($this->client, $commands, ['concurrency' => $this->concurrency, 'before' => $this->before, 'rejected' => function ($reason, $idx, Promise\PromiseInterface $p) {
             $p->reject($reason);
         }]))->promise();
     });
 }
 public static function timer()
 {
     return function (callable $handler) {
         return function (CommandInterface $command, RequestInterface $request = null) use($handler) {
             $start = microtime(true);
             return $handler($command, $request)->then(function (ResultInterface $res) use($start) {
                 if (!isset($res['@metadata'])) {
                     $res['@metadata'] = [];
                 }
                 if (!isset($res['@metadata']['transferStats'])) {
                     $res['@metadata']['transferStats'] = [];
                 }
                 $res['@metadata']['transferStats']['total_time'] = microtime(true) - $start;
                 return $res;
             }, function ($err) use($start) {
                 if ($err instanceof AwsException) {
                     $err->setTransferInfo(['total_time' => microtime(true) - $start] + $err->getTransferInfo());
                 }
                 return Promise\rejection_for($err);
             });
         };
     };
 }
 /**
  * Returns a function which is handled when a request was rejected.
  *
  * @param RequestInterface $request
  *
  * @return Closure
  */
 protected function onFailure(RequestInterface $request)
 {
     return function ($reason) use($request) {
         // Only log a rejected requests if it hasn't already been logged
         if (!$this->logRequests) {
             $this->log($request, null, $reason);
         }
         return Promise\rejection_for($reason);
     };
 }