/** * @inheritdoc * * @param Task $task */ public function handle(Task $task) { $config = $task->getData(); if ($config["driver"] === "mysql") { $config += ["host" => "127.0.0.1", "port" => 3306, "charset" => "utf8", "socket" => null]; } if ($config["remit"]["driver"] === "zeromq") { $config["remit"]["server"] += ["host" => "127.0.0.1"]; $config["remit"]["client"] += ["host" => "127.0.0.1"]; $server = new ZeroMqServer(new InMemoryLocation($config["remit"]["client"]["host"], $config["remit"]["client"]["port"])); $client = new ZeroMqClient(new InMemoryLocation($config["remit"]["server"]["host"], $config["remit"]["server"]["port"])); } $connection = new ExtendedPdo(new PDO($this->newConnectionString($config), $config["username"], $config["password"])); $server->addListener("q", function ($query, $values, $id) use($client, $connection) { $client->emit("r", [$connection->fetchAll($query, $values), $id]); }); $server->addListener("d", function () use($connection, $server, $client) { $client->emit("dd"); try { $connection->disconnect(); } catch (Exception $exception) { // TODO: find an elegant way to deal with this } $server->disconnect(); $client->disconnect(); Loop\stop(); }); Loop\periodic(0, function () use($server) { $server->tick(); }); Loop\run(); }
public function __construct() { $this->queue = new \SplPriorityQueue(); $this->timer = Loop\periodic(1, function () { $time = time(); while (!$this->queue->isEmpty()) { $key = $this->queue->top(); if (isset($this->expire[$key])) { if ($time <= $this->expire[$key]) { break; } unset($this->data[$key], $this->expire[$key], $this->ttl[$key]); } $this->queue->extract(); } if ($this->queue->isEmpty()) { $this->timer->stop(); } }); $this->timer->stop(); $this->timer->unreference(); }
/** * @param array $config */ private function remit(array $config) { if ($config["remit"]["driver"] === "zeromq") { $config["remit"]["server"] += ["host" => "127.0.0.1"]; $config["remit"]["client"] += ["host" => "127.0.0.1"]; $this->server = new ZeroMqServer(new InMemoryLocation($config["remit"]["server"]["host"], $config["remit"]["server"]["port"])); $this->client = new ZeroMqClient(new InMemoryLocation($config["remit"]["client"]["host"], $config["remit"]["client"]["port"])); } $this->server->addListener("r", function ($result, $id) { if (isset($this->deferred[$id])) { $this->deferred[$id]->resolve($result); unset($this->deferred[$id]); } }); $this->server->addListener("e", function ($error, $id) { if (isset($this->deferred[$id])) { $this->deferred[$id]->reject($error); unset($this->deferred[$id]); } }); $this->server->addListener("dd", function () { $this->server->disconnect(); $this->client->disconnect(); }); Loop\periodic(0, function () { $this->server->tick(); }); }
/** * Returns an observable that emits a value every $interval seconds, up to $count times (or indefinitely if $count * is 0). The value emitted is an integer of the number of times the observable emitted a value. * * @param float|int $interval Time interval between emitted values in seconds. * @param int $count Use 0 to emit values indefinitely. * * @return \Icicle\Observable\Observable */ function interval(float $interval, int $count = 0) : Observable { return new Emitter(function (callable $emit) use($interval, $count) : \Generator { if (0 > $count) { throw new InvalidArgumentError('The number of times to emit must be a non-negative value.'); } $start = microtime(true); $i = 0; $delayed = new Delayed(); $timer = Loop\periodic($interval, function () use(&$delayed, &$i) { $delayed->resolve(++$i); $delayed = new Delayed(); }); try { while (0 === $count || $i < $count) { yield from $emit($delayed); } } finally { $timer->stop(); } return microtime(true) - $start; }); }
#!/usr/bin/env php <?php require dirname(__DIR__).'/vendor/autoload.php'; use Icicle\Concurrent\Threading\Thread; use Icicle\Coroutine; use Icicle\Loop; $timer = Loop\periodic(1, function () { static $i; $i = $i ? ++$i : 1; print "Demonstrating how alive the parent is for the {$i}th time.\n"; }); Coroutine\create(function () { // Create a new child thread that does some blocking stuff. $context = Thread::spawn(function () { printf("\$this: %s\n", get_class($this)); printf("Received the following from parent: %s\n", (yield $this->receive())); print "Sleeping for 3 seconds...\n"; sleep(3); // Blocking call in thread. yield $this->send('Data sent from child.'); print "Sleeping for 2 seconds...\n"; sleep(2); // Blocking call in thread. yield 42; });
/** * @param float $interval * @param int $maxSize * @param int $maxFrames * * @return \Icicle\Observable\Observable */ private function createObservable(float $interval, int $maxSize, int $maxFrames) : Observable { return new Emitter(function (callable $emit) use($interval, $maxSize, $maxFrames) : \Generator { /** @var \Icicle\WebSocket\Protocol\Rfc6455Frame[] $frames */ $frames = []; $size = 0; $ping = Loop\periodic($interval, Coroutine\wrap(function () use(&$pong, &$expected) { try { yield from $this->ping($expected = base64_encode(random_bytes(self::PING_DATA_LENGTH))); if (null === $pong) { $pong = Loop\timer($this->timeout, Coroutine\wrap(function () { yield from $this->close(Close::VIOLATION); $this->transporter->close(); })); $pong->unreference(); } else { $pong->again(); } } catch (\Throwable $exception) { $this->transporter->close(); } })); $ping->unreference(); try { while ($this->transporter->isOpen()) { /** @var \Icicle\WebSocket\Protocol\Rfc6455Frame $frame */ $frame = (yield from $this->transporter->read($maxSize - $size)); $ping->again(); switch ($type = $frame->getType()) { case Frame::CLOSE: // Close connection. if (!$this->closed) { // Respond with close frame if one has not been sent. yield from $this->close(Close::NORMAL); } $data = $frame->getData(); if (2 > strlen($data)) { return new Close(Close::NO_STATUS); } $bytes = unpack('ncode', substr($data, 0, 2)); $data = (string) substr($data, 2); if (!preg_match('//u', $data)) { throw new DataException('Invalid UTF-8 data received.'); } return new Close($bytes['code'], $data); case Frame::PING: // Respond with pong frame. yield from $this->pong($frame->getData()); continue; case Frame::PONG: // Cancel timeout set by sending ping frame. // Only stop timer if ping sent and pong data matches ping data. if (null !== $pong && $frame->getData() === $expected) { $pong->stop(); } continue; case Frame::CONTINUATION: $count = count($frames); if (0 === $count) { throw new ProtocolException('Received orphan continuation frame.'); } $frames[] = $frame; $size += $frame->getSize(); if (!$frame->isFinal()) { if ($count + 1 >= $maxFrames) { throw new PolicyException('Too many frames in message.'); } continue; } $data = ''; for ($i = $count; $i >= 0; --$i) { $frame = $frames[$i]; $data = $frame->getData() . $data; } $frames = []; $size = 0; $type = $frame->getType(); if ($type === Frame::TEXT && !preg_match('//u', $data)) { throw new DataException('Invalid UTF-8 data received.'); } yield from $emit(new Message($data, $type === Frame::BINARY)); continue; case Frame::TEXT: case Frame::BINARY: if (!empty($frames)) { throw new ProtocolException('Expected continuation data frame.'); } if (!$frame->isFinal()) { $size = $frame->getSize(); $frames[] = $frame; continue; } $data = $frame->getData(); if ($type === Frame::TEXT && !preg_match('//u', $data)) { throw new DataException('Invalid UTF-8 data received.'); } yield from $emit(new Message($data, $type === Frame::BINARY)); continue; default: throw new ProtocolException('Received unrecognized frame type.'); } } } catch (ConnectionException $exception) { $close = new Close($exception->getReasonCode(), $exception->getMessage()); } catch (SocketException $exception) { $close = new Close(Close::ABNORMAL, $exception->getMessage()); } catch (StreamException $exception) { $close = new Close(Close::ABNORMAL, $exception->getMessage()); } catch (TimeoutException $exception) { $close = new Close(Close::GOING_AWAY, $exception->getMessage()); } finally { $ping->stop(); if (null !== $pong) { $pong->stop(); } } if (!isset($close)) { $close = new Close(Close::ABNORMAL, 'Peer unexpectedly disconnected.'); } if ($this->isOpen()) { yield from $this->close($close->getCode()); } return $close; }); }
use Icicle\Awaitable; use Icicle\Concurrent\Worker\DefaultPool; use Icicle\Coroutine; use Icicle\Examples\Concurrent\BlockingTask; use Icicle\Loop; Coroutine\create(function () { $pool = new DefaultPool(); $pool->start(); $coroutines = []; $coroutines[] = Coroutine\create(function () use($pool) { $url = 'https://google.com'; $result = (yield from $pool->enqueue(new BlockingTask('file_get_contents', $url))); printf("Read from %s: %d bytes\n", $url, strlen($result)); }); $coroutines[] = Coroutine\create(function () use($pool) { $url = 'https://icicle.io'; $result = (yield from $pool->enqueue(new BlockingTask('file_get_contents', $url))); printf("Read from %s: %d bytes\n", $url, strlen($result)); }); $coroutines[] = Coroutine\create(function () use($pool) { $url = 'https://github.com'; $result = (yield from $pool->enqueue(new BlockingTask('file_get_contents', $url))); printf("Read from %s: %d bytes\n", $url, strlen($result)); }); (yield Awaitable\all($coroutines)); return yield from $pool->shutdown(); })->done(); Loop\periodic(0.1, function () { printf(".\n"); })->unreference(); Loop\run();