Simplified codebase in a major refactor before moving to initial Toalett release

This commit is contained in:
2021-01-06 18:11:09 +01:00
parent 4edc6132c4
commit baca5b129e
18 changed files with 448 additions and 409 deletions

View File

@@ -1,17 +0,0 @@
<?php
use JoopSchilder\React\Stream\NonBlockingInput\ReadableNonBlockingInputStream;
use React\EventLoop\Factory;
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/demo_classes.php';
$input = new DemoNonBlockingInput();
$loop = Factory::create();
$stream = new ReadableNonBlockingInputStream($input, $loop);
$stream->on('data', fn() => print('m'));
$stream->on('error', fn() => print('e'));
$stream->on('close', fn() => print('c'));
$loop->addPeriodicTimer(0.2, fn() => print('.'));
$loop->run();

99
examples/classes.php Normal file
View File

@@ -0,0 +1,99 @@
<?php
use Toalett\React\Stream\EndlessTrait;
use Toalett\React\Stream\Source;
final class WillThrowExceptionAfter4Seconds implements Source
{
use EndlessTrait;
private const EMISSION_INTERVAL = 1.0;
private const SECONDS_BEFORE_EMITTING_ERROR = 4.0;
private float $lastEmission = 0;
private float $openedAt = 0;
public function open(): void
{
$this->openedAt = microtime(true);
}
public function select(): ?float
{
$now = microtime(true);
if ($now - $this->openedAt > self::SECONDS_BEFORE_EMITTING_ERROR) {
throw new RuntimeException('An error has occured!');
}
if ($now - $this->lastEmission > self::EMISSION_INTERVAL) {
$this->lastEmission = $now;
return $now;
}
return null;
}
}
final class Joker implements Source
{
use EndlessTrait;
private float $deadline = 0;
private array $jokes = [
'What did the Buddhist ask the hot dog vendor? - Make me one with everything.',
'You know why you never see elephants hiding up in trees? - Because theyre really good at it.',
'What is red and smells like blue paint? - Red paint.',
'A dyslexic man walks into a bra.',
'Where does the General keep his armies? - In his sleevies!',
'What do you call bears with no ears? - B',
'Why dont blind people skydive? - Because it scares the crap out of their dogs.',
];
public function open(): void
{
$this->scheduleNextJoke();
}
public function select(): ?string
{
if (microtime(true) < $this->deadline) {
return null;
}
$this->scheduleNextJoke();
return $this->jokes[array_rand($this->jokes)];
}
private function scheduleNextJoke(): void
{
$delay = mt_rand() / mt_getrandmax(); // somewhere between 0 - 1
$this->deadline = microtime(true) + (5.0 * $delay);
}
}
final class ReachesEofIn5Iterations implements Source
{
private array $buffer = [
'line 1',
'line 2',
'line 3',
'line 4',
'line 5',
];
public function open(): void
{
}
public function select(): ?string
{
return array_shift($this->buffer);
}
public function close(): void
{
}
public function eof(): bool
{
return count($this->buffer) === 0;
}
}

View File

@@ -1,124 +0,0 @@
<?php
use JoopSchilder\React\Stream\NonBlockingInput\NonBlockingInputInterface;
/**
* Class DemoNonBlockingInput
* Provides an implementation of a non-blocking input that generates
* some data every second. After a lifetime of 4 seconds, an exception
* is thrown to show how the stream handles exceptions from the input.
*/
final class DemoNonBlockingInput implements NonBlockingInputInterface
{
private const DATA_AVAILABLE_INTERVAL_S = 1.0;
private const ERROR_AFTER_S = 4.0;
private float $lastEmission = 0;
private float $initialEmission = 0;
public function open(): void
{
$this->initialEmission = microtime(true);
}
public function select(): ?object
{
$now = microtime(true);
if ($now - $this->initialEmission > self::ERROR_AFTER_S) {
throw new Exception('Oh no!');
}
if ($now - $this->lastEmission > self::DATA_AVAILABLE_INTERVAL_S) {
$this->lastEmission = $now;
return new stdClass();
}
return null;
}
public function close(): void
{
}
}
/**
* Class Joke
* Used as a payload for the DemoJokeGenerator.
* @see DemoJokeGenerator
*/
final class Joke
{
private string $joke;
public function __construct(string $joke)
{
$this->joke = $joke;
}
public function __toString()
{
return $this->joke;
}
}
/**
* Class DemoJokeGenerator
* Generates a random joke at a random interval (0 - 2 seconds).
*/
final class DemoJokeGenerator implements NonBlockingInputInterface
{
private float $lastEmission = 0;
private float $deadline = 0;
private array $jokes = [
'What did the Buddhist ask the hot dog vendor? - Make me one with everything.',
'You know why you never see elephants hiding up in trees? - Because theyre really good at it.',
'What is red and smells like blue paint? - Red paint.',
'A dyslexic man walks into a bra.',
'Where does the General keep his armies? - In his sleevies!',
'What do you call bears with no ears? - B',
'Why dont blind people skydive? - Because it scares the crap out of their dogs.',
];
private function scheduleNextJoke()
{
$this->lastEmission = microtime(true);
$delay = mt_rand() / mt_getrandmax();
$this->deadline = $this->lastEmission + (2.0 * $delay);
}
public function open(): void
{
$this->scheduleNextJoke();
}
public function select(): ?object
{
$now = microtime(true);
if ($now > $this->deadline) {
$this->scheduleNextJoke();
return new Joke($this->jokes[array_rand($this->jokes)]);
}
return null;
}
public function close(): void
{
}
}

View File

@@ -0,0 +1,29 @@
<?php
use React\EventLoop\Factory;
use Toalett\React\Stream\StreamAdapter;
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/classes.php';
$loop = Factory::create();
$stream = new StreamAdapter(new ReachesEofIn5Iterations(), $loop, 0.1);
$stream->on('data', fn(string $s) => printf('Data received: %s.%s', $s, PHP_EOL));
$stream->on('end', fn() => print('Stream reached eof.' . PHP_EOL));
$stream->on('close', fn() => print('Stream closed.' . PHP_EOL));
print(<<<EOF
This program demonstrates an example of a source that reaches EOF after 5 lines.
The stream adapter reads eagerly from the source: data is emitted as long as
select() on the source returns a non-null value. This means that all lines from
the source in this example ar read at once. If you want the adapter to read
at most one unit (message) from the source, you should probably be using a
periodic timer directly, or use time mechanics as used by the other examples.
EOF
);
$loop->run();

View File

@@ -0,0 +1,25 @@
<?php
use React\EventLoop\Factory;
use Toalett\React\Stream\StreamAdapter;
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/classes.php';
$loop = Factory::create();
$loop->addPeriodicTimer(0.2, fn() => print('.'));
$stream = new StreamAdapter(new WillThrowExceptionAfter4Seconds(), $loop);
$stream->on('data', fn() => print('Data received.' . PHP_EOL));
$stream->on('error', fn(Throwable $t) => print('Error: ' . $t->getMessage() . PHP_EOL));
$stream->on('close', fn() => print('Stream closed.' . PHP_EOL));
print(<<<EOF
This program demonstrates an example of a source that fails after 4 seconds.
Press CTRL+C to stop.
EOF
);
$loop->run();

View File

@@ -0,0 +1,23 @@
<?php
use React\EventLoop\Factory;
use Toalett\React\Stream\StreamAdapter;
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/classes.php';
$loop = Factory::create();
$stream = new StreamAdapter(new Joker(), $loop);
$stream->on('data', fn(string $joke) => print($joke . PHP_EOL));
print(<<<EOF
This program demonstrates an example of an endless source.
The stream presents a joke at random intervals (0.0 - 5.0 seconds).
Press CTRL+C to stop.
EOF
);
$loop->run();

View File

@@ -1,16 +0,0 @@
<?php
use JoopSchilder\React\Stream\NonBlockingInput\ReadableNonBlockingInputStream;
use React\EventLoop\Factory;
require_once __DIR__ . '/../vendor/autoload.php';
require_once __DIR__ . '/demo_classes.php';
$input = new DemoJokeGenerator();
$loop = Factory::create();
$stream = new ReadableNonBlockingInputStream($input, $loop);
$stream->on('data', fn(Joke $joke) => print($joke . PHP_EOL));
$loop->addPeriodicTimer(0.2, fn() => print('.' . PHP_EOL));
$loop->run();