/** * 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); }); }
/** * 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); } }
/** * 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); }); }; }; }
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); }; }