public function search(Command $command) : \Generator { if (!$command->hasParameters()) { return $this->chatClient->postReply($command, 'Mhm, I need a film title you want me to look for.'); } $search = $command->getText(); $message = (yield $this->chatClient->postMessage($command->getRoom(), sprintf('_Looking for \'%s\' for you…_', $search))); $params = $this->buildTitleSearchParams($search); // Send it out. /** @var HttpResponse $response */ $response = (yield $this->httpClient->request(sprintf('%s?%s', self::OMDB_API_ENDPOINT, http_build_query($params)))); /** @var \stdClass $data */ $data = @json_decode($response->getBody()); if (!$data || $data->Response === 'False') { return $this->chatClient->postMessage($command->getRoom(), 'I couldn\'t find anything for that title.'); } $searchResults = []; foreach ($data->Search as $searchResult) { $searchResults[$searchResult->imdbID] = $searchResult; } // Only pick the top 3 results if needed. $searchResults = array_slice($searchResults, 0, 3, true); /** @var PostedMessage $chatMessage */ (yield $this->chatClient->editMessage($message, $this->formatSearchResults($searchResults))); $requests = []; // Send out multiple http requests to get film descriptions and ratings. foreach ($searchResults as $id => $searchResult) { $requests[$id] = sprintf('%s?%s', self::OMDB_API_ENDPOINT, http_build_query($this->buildTitleDescParams($id))); } // Wait until all requests are done, allow failures. $allRequests = \Amp\some($this->httpClient->requestMulti($requests)); list($errors, $responses) = (yield $allRequests); $descriptionResults = []; foreach ($responses as $key => $response) { $responseBody = @json_decode($response->getBody()); if (!$responseBody || $responseBody->Response === 'False') { continue; } $descriptionResults[$key] = $responseBody; } return $this->chatClient->editMessage($message, $this->formatSearchResults($searchResults, $descriptionResults)); }
function __doResolve($name, array $types, $options) { static $state; $state = $state ?: (yield \Amp\resolve(__init())); if (empty($types)) { (yield new CoroutineResult([])); return; } assert(array_reduce($types, function ($result, $val) { return $result && \is_int($val); }, true), 'The $types passed to DNS functions must all be integers (from \\Amp\\Dns\\Record class)'); $name = \strtolower($name); $result = []; // Check for cache hits if (!isset($options["cache"]) || $options["cache"]) { foreach ($types as $k => $type) { $cacheKey = "{$name}#{$type}"; $cacheValue = (yield $state->arrayCache->get($cacheKey)); if ($cacheValue !== null) { $result[$type] = $cacheValue; unset($types[$k]); } } if (empty($types)) { (yield new CoroutineResult($result)); return; } } $timeout = empty($options["timeout"]) ? $state->config["timeout"] : (int) $options["timeout"]; if (empty($options["server"])) { if (empty($state->config["nameservers"])) { throw new ResolutionException("No nameserver specified in system config"); } $uri = "udp://" . $state->config["nameservers"][0]; } else { $uri = __parseCustomServerUri($options["server"]); } foreach ($types as $type) { $promises[] = __doRequest($state, $uri, $name, $type); } try { list(, $resultArr) = (yield \Amp\timeout(\Amp\some($promises), $timeout)); foreach ($resultArr as $value) { $result += $value; } } catch (\Amp\TimeoutException $e) { if (substr($uri, 0, 6) == "tcp://") { throw new TimeoutException("Name resolution timed out for {$name}"); } else { $options["server"] = \preg_replace("#[a-z.]+://#", "tcp://", $uri); (yield new CoroutineResult(\Amp\resolve(__doResolve($name, $types, $options)))); } } catch (ResolutionException $e) { if (empty($result)) { // if we have no cached results throw $e; } } catch (\RuntimeException $e) { // if all promises in Amp\some fail if (empty($result)) { // if we have no cached results throw new ResolutionException("All name resolution requests failed", 0, $e); } } (yield new CoroutineResult($result)); }
<?php require __DIR__ . '/../vendor/autoload.php'; /** * Note that Client::requestMulti() is nothing more than a convenience wrapper * to prevent us from having to call Client::request() several times and store * the resulting promises in an array ourselves. Doing so would have the exact * same effect and all requests would be executed in parallel either way. */ $promises = (new Amp\Artax\Client())->requestMulti(['google' => 'http://www.google.com', 'news' => 'http://news.google.com', 'bing' => 'http://www.bing.com', 'yahoo' => 'https://www.yahoo.com']); // Tolerate errors in some of the requests. If any one of the promises in our array // succeeds then the result is a two-item array of errors and successes. If *none* // of our response promises succeed then this line will throw. $comboPromise = Amp\some($promises); list($errors, $responses) = Amp\wait($comboPromise); // Alternatively we could use the following line to require all of our responses to succeed. If // any one of the response promises resolves as a failure then this line will throw: $comboPromise = Amp\all($promises); $responses = Amp\wait($comboPromise); // Now, let's iterate over the responses to demonstrate that they retain the same keys from // our original call to Amp\Artax\Client::request(): foreach ($responses as $key => $response) { printf("%s | HTTP/%s %d %s\n", $key, $response->getProtocol(), $response->getStatus(), $response->getReason()); }