public function testCollectAsyncFollowersIds() { Co::wait(function () { $this->assertTrue((yield $this->getBot()->forceMutualsAsync())); $this->assertEquals(['UNFOLLOWED: @11', 'FOLLOWED: @1', 'FOLLOWED: @2', 'FOLLOWED: @3', 'FOLLOWED: @7'], $GLOBALS['HARDBOTTER-BUFFER-OUTS']); }); }
public function testAsyncPayloadHttps() { Co::wait(function () { $client = $this->getClient(); (yield $client->requestAsync('GET', 'https://localhost:8081/hello.php')); $this->assertEquals('Hello', $client->getResponse()->getContent()); }); }
/** * Value is recursively resolved, but we never wait it. * This function must be called along with Co::wait(). * @param mixed $value * @param mixed $throw */ public static function async($value, $throw = null) { if (!self::$self) { throw new \BadMethodCallException('Co::async() must be called along with Co::wait(). '); } if ($throw !== null) { $throw = filter_var($throw, FILTER_VALIDATE_BOOLEAN, ['flags' => FILTER_NULL_ON_FAILURE]); if ($throw === null) { throw new \InvalidArgumentException("\$throw must be null or boolean."); } } self::$self->start($value, false, $throw); }
public function testDelayedGroupDoubleAtOnceSecure() { Co::wait($chs = $this->curlsInitWith(10, 'https://localhost:8081/fast_hello.php'), ['concurrency' => 0]); $this->curlsAssert200OK($chs); }
curl_setopt_array($ch, $options); return $ch; } function get_xpath_async($url) { $dom = new \DOMDocument(); @$dom->loadHTML((yield curl_init_with($url))); (yield Co::RETURN_WITH => new \DOMXPath($dom)); } var_dump(Co::wait(['Delay 5 secs' => function () { echo "[Delay] I start to have a pseudo-sleep in this coroutine for about 5 secs\n"; for ($i = 0; $i < 5; ++$i) { (yield Co::DELAY => 1); if ($i < 4) { printf("[Delay] %s\n", str_repeat('.', $i + 1)); } } echo "[Delay] Done!\n"; }, "google.com HTML" => curl_init_with("https://google.com"), "Content-Length of github.com" => function () { echo "[GitHub] I start to request for github.com to calculate Content-Length\n"; $content = (yield curl_init_with("https://github.com")); echo "[GitHub] Done! Now I calculate length of contents\n"; (yield Co::RETURN_WITH => strlen($content)); }, "Save mpyw's Gravatar Image URL to local" => function () { echo "[Gravatar] I start to request for github.com to get Gravatar URL\n"; $xpath = (yield get_xpath_async('https://github.com/mpyw')); $src = $xpath->evaluate('string(//img[contains(@class,"avatar")]/@src)'); echo "[Gravatar] Done! Now I download its data\n"; (yield curl_init_with($src, [CURLOPT_FILE => fopen('/tmp/mpyw.png', 'wb')])); echo "[Gravatar] Done! Saved as /tmp/mpyw.png\n"; }]));
<?php require __DIR__ . '/../../vendor/autoload.php'; use mpyw\Co\Co; use mpyw\Co\CURLException; Co::wait([function () { for ($i = 0; $i < 8; ++$i) { (yield CO::DELAY => 1.1); echo "[A] Timer: {$i}\n"; } }, function () { for ($i = 0; $i < 5; ++$i) { (yield CO::DELAY => 1.7); echo "[B] Timer: {$i}\n"; } }]);
// Wait 7 sec print_time(); $result = Co::wait([curl('/rest', ['id' => 1, 'sleep' => 7]), function () { // Wait 4 sec print_r((yield [curl('/rest', ['id' => 2, 'sleep' => 3]), curl('/rest', ['id' => 3, 'sleep' => 4])])); print_time(); // Wait 2 sec print_r((yield [function () { // Wait 1 sec echo (yield curl('/rest', ['id' => 4, 'sleep' => 1])), "\n"; print_time(); return curl('/rest', ['id' => 5, 'sleep' => 1]); }, function () { // Wait 0 sec echo unwrap((yield CO::SAFE => curl('/invalid'))), "\n"; print_time(); try { // Wait 0 sec (yield curl('/invalid')); } catch (CURLException $e) { echo unwrap($e), "\n"; print_time(); } return ['x' => ['y' => function () { return (yield curl('/rest', ['id' => 6, 'sleep' => 2])); }]]; }])); print_time(); return curl('/rest', ['id' => 7, 'sleep' => 1]); }]); print_r($result); print_time();
public function testGetAsyncHomeTimelineErrorException() { Co::wait(function () { $this->setExpectedException(\RuntimeException::class, 'Error'); $GLOBALS['HARDBOTTER-ERROR-COUNTER'] = 0; (yield $this->getBot()->getAsync('statuses/home_timeline')); }); }
public function testCollectAsyncFollowersIds() { Co::wait(function () { $expected = ['1', '2', '3', '4', '5', '6', '7']; $actual = (yield $this->getBot()->collectAsync('followers/ids', 10, ['count' => 2])); $this->assertEquals($expected, $actual); }); }
<?php require __DIR__ . '/../../vendor/autoload.php'; use mpyw\Co\Co; use mpyw\Co\CURLException; Co::wait(function () { (yield [timer($stop), main($stop)]); }); function curl_init_with(string $url, array $options = []) { $ch = curl_init(); $options = array_replace([CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true], $options); curl_setopt_array($ch, $options); return $ch; } function timer(&$stop) { $ms = 0; while (true) { (yield CO::DELAY => 0.2); if ($stop) { break; } $ms += 200; echo "[Timer]: {$ms} miliseconds passed\n"; } } function main(&$stop) { echo "Started first requests...\n"; var_dump(array_map('strlen', (yield ['Content-Length of github.com' => curl_init_with('https://github.com/mpyw'), 'Content-Length of twitter.com' => curl_init_with('https://twitter.com/mpyw')])));
file_put_contents("{$savedir}/{$basename}{$ext}", $content); echo "Downloaded {$url}, saved as {$savedir}/{$basename}{$ext}\n"; } // Who are you? while (true) { do { if (feof(STDIN)) { exit; } fwrite(STDERR, 'USERNAME: '******'/[^\\w-]++/', '', trim(fgets(STDIN))); } while ($username === ''); if (@file_get_contents("https://github.com/{$username}")) { define('USERNAME', $username); break; } fwrite(STDERR, error_get_last()['message'] . "\n"); } Co::wait(function () { $page = 0; do { $sources = (yield get_github_followers_async(USERNAME, ++$page, $has_more)); Co::async(function () use($sources) { $requests = []; foreach ($sources as $username => $src) { $requests[] = download_image_async($src, $username); } (yield $requests); }); } while ($has_more); }, ['concurrency' => 0, 'pipeline' => true]);
use mpyw\Co\Co; use mpyw\Co\CURLException; if (PHP_SAPI !== 'cli') { header('Content-Type: text/plain; charset=UTF-8', true, 400); echo 'This script is only for php-cli.'; exit(1); } set_time_limit(0); function input($msg, $hidden = false) { echo $msg; $hidden = $hidden && DIRECTORY_SEPARATOR === '/'; $input = $hidden ? `stty -echo; read x; stty echo; printf "\$x"` : trim(fgets(STDIN)); $hidden && fwrite(STDOUT, "\n"); return $input; } Co::wait(function () { $client = new Client(); $crawler = (yield $client->requestAsync('GET', 'https://mobile.twitter.com/login')); $form = $crawler->filter('*[name=commit]')->form(['session[username_or_email]' => input('screen_name: '), 'session[password]' => input('password: '******'GET', 'https://mobile.twitter.com/compose/tweet')); for ($i = 0; $i < 5; ++$i) { $form = $crawler->filter('*[name=commit]')->form(['tweet[text]' => "@tos HAHAHA!! [{$i}] " . mt_rand()]); Co::async($client->submitAsync($form), false); } });
$result = Co::wait([curl('/rest', ['id' => 1, 'sleep' => 5]), function () { // Wait 3 sec print_r(unwrap((yield Co::SAFE => [curl('/rest', ['id' => 2, 'sleep' => 3]), function () { yield; throw new \RuntimeException('01'); }]))); print_time(); // Wait 1 sec print_r(unwrap((yield Co::SAFE => [function () { // Wait 1 sec echo (yield curl('/rest', ['id' => 3, 'sleep' => 1])), "\n"; print_time(); echo unwrap((yield Co::SAFE => function () { yield; throw new \RuntimeException('02'); })) . "\n"; (yield function () { yield; throw new \RuntimeException('03'); }); return 'Unreachable'; }, function () { echo unwrap((yield Co::SAFE => function () { yield; throw new \RuntimeException('04'); })) . "\n"; (yield function () { yield; throw new \RuntimeException('05'); }); return 'Unreachable'; }]))); echo unwrap((yield Co::SAFE => function () { (yield curl('/invalid')); return 'Unreachable'; })) . "\n"; // Wait 1 sec return curl('/rest', ['id' => 4, 'sleep' => 1]); }]);
// Botインスタンスを生成 $client = new Client([$_SERVER['CONSUMER_KEY'], $_SERVER['CONSUMER_SECRET'], $_SERVER['ACCESS_TOKEN'], $_SERVER['ACCESS_TOKEN_SECRET']]); $bot = new Bot($client, __DIR__ . '/stamp.json', 2); // 今回はすべて非同期APIに統一して書きます Co::wait(function () use($bot) { $tasks = []; // メンションを取得 foreach ((yield $bot->getAsync('statuses/mentions_timeline')) as $status) { // パターンマッチングを行い,適合した処理を選択する if (null !== ($task = Bot::match($status->text, ['/おはよう|こんにちは|こんばんは/' => function ($m) use($bot, $status) { return $bot->replyAsync("{$m[0]}!", $status); }, '/何時/' => function ($m) use($bot, $status) { $date = new DateTime('now', new DateTimeZone(getenv('TIMEZONE') ?: 'Asia/Tokyo')); return $bot->replyAsync($date->format('H時i分だよー'), $status); }, '/占い|おみくじ/' => function ($m) use($bot, $status) { $list = ['大吉', '吉', '吉', '中吉', '中吉', '中吉', '小吉', '小吉', '小吉', '末吉', '末吉', '凶']; return $bot->replyAsync('あなたの運勢は' . $list[array_rand($list)] . 'です', $status); }, '/ふぁぼ/' => function ($m) use($status, $bot) { return $bot->favoriteAsync($status); }, '/ホモ/' => function ($m) use($status, $bot) { return $bot->tweetAsync("┌(┌^o^)┐{$status->user->name}┌(┌^o^)┐"); }]))) { // 返り値がタスクの場合,次回以降は反応しないようにマークする $bot->mark($status); // タスクを配列に入れておく $tasks[] = $task; } } // 一気に実行 (yield $tasks); });
public function testReplyAsync() { Co::wait(function () { (yield $this->getBot()->replyAsync('yeah', (object) ['id_str' => '114514', 'user' => (object) ['screen_name' => 'mpyw']])); $this->assertEquals(['REPLIED: @mpyw yeah'], $GLOBALS['HARDBOTTER-BUFFER-OUTS']); }); }
public function testAll() { $a = new DummyCurl('A', 3); $b = new DummyCurl('B', 2); $r = Co::wait(Co::all([$a, $b])); $this->assertEquals('Response[A]', $r[0]); $this->assertEquals('Response[B]', $r[1]); }
public function testDuplicatedBetweenAddAndEnqueue() { $this->setExpectedException(\DomainException::class, 'Duplicated cURL resource or Generator instance found.'); Co::wait([new DummyCurl('A', 2), new DummyCurl('B', 3), new DummyCurl('C', 4), new DummyCurl('C', 5)], ['concurrency' => 3]); }