/**
  * @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();
 }
Example #2
0
    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();
     });
 }
Example #4
0
 /**
  * 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;
     });
 }
Example #5
0
#!/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;
    });
Example #6
0
 /**
  * @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;
     });
 }
Example #7
0
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();