2020-07-21 18:06:19 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generic loop.
|
|
|
|
*
|
|
|
|
* @author Daniil Gentili <daniil@daniil.it>
|
|
|
|
* @copyright 2016-2020 Daniil Gentili <daniil@daniil.it>
|
|
|
|
* @license https://opensource.org/licenses/MIT MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace danog\Loop\Generic;
|
|
|
|
|
|
|
|
use Amp\Promise;
|
2020-07-21 21:45:22 +02:00
|
|
|
use danog\Loop\ResumableSignalLoop;
|
2020-07-21 18:06:19 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Generic loop, runs single callable.
|
|
|
|
*
|
|
|
|
* The return value of the callable can be:
|
|
|
|
* * A number - the loop will be paused for the specified number of seconds
|
|
|
|
* * GenericLoop::STOP - The loop will stop
|
|
|
|
* * GenericLoop::PAUSE - The loop will pause forever (or until loop is `resumed()`
|
|
|
|
* from outside the loop)
|
|
|
|
* * GenericLoop::CONTINUE - Return this if you want to rerun the loop immediately
|
|
|
|
*
|
|
|
|
* If the callable does not return anything,
|
|
|
|
* the loop will behave is if GenericLoop::PAUSE was returned.
|
|
|
|
*
|
|
|
|
* The loop can be stopped from the outside by signaling `true`.
|
|
|
|
*
|
2020-07-22 18:18:57 +02:00
|
|
|
* @template T as int|null
|
2020-07-21 18:06:19 +02:00
|
|
|
* @template TGenerator as \Generator<mixed,Promise|array<array-key,Promise>,mixed,Promise<T>|T>
|
|
|
|
* @template TPromise as Promise<T>
|
|
|
|
*
|
|
|
|
* @template TCallable as T|TPromise|TGenerator
|
|
|
|
*
|
|
|
|
* @author Daniil Gentili <daniil@daniil.it>
|
|
|
|
*/
|
|
|
|
class GenericLoop extends ResumableSignalLoop
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Stop the loop.
|
|
|
|
*/
|
|
|
|
const STOP = -1;
|
|
|
|
/**
|
|
|
|
* Pause the loop.
|
|
|
|
*/
|
|
|
|
const PAUSE = null;
|
|
|
|
/**
|
|
|
|
* Rerun the loop.
|
|
|
|
*/
|
|
|
|
const CONTINUE = 0;
|
|
|
|
/**
|
|
|
|
* Callable.
|
|
|
|
*
|
|
|
|
* @var callable
|
|
|
|
*
|
|
|
|
* @psalm-var callable():TCallable
|
|
|
|
*/
|
|
|
|
protected $callable;
|
|
|
|
/**
|
|
|
|
* Loop name.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $name;
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
|
|
|
* @param callable $callable Callable to run
|
|
|
|
* @param string $name Loop name
|
|
|
|
*
|
|
|
|
* @psalm-param callable():TCallable $callable Callable to run
|
|
|
|
*/
|
|
|
|
public function __construct(callable $callable, string $name)
|
|
|
|
{
|
|
|
|
$this->callable = $callable;
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Loop implementation.
|
|
|
|
*
|
|
|
|
* @return \Generator
|
|
|
|
*/
|
|
|
|
public function loop(): \Generator
|
|
|
|
{
|
|
|
|
$callable = $this->callable;
|
|
|
|
while (true) {
|
2020-07-23 14:18:33 +02:00
|
|
|
/** @psalm-var ?int|TGenerator|TPromise */
|
2020-07-21 18:06:19 +02:00
|
|
|
$timeout = $callable();
|
|
|
|
if ($timeout instanceof \Generator) {
|
2020-07-23 14:18:33 +02:00
|
|
|
/** @psalm-var ?int */
|
2020-07-21 18:06:19 +02:00
|
|
|
$timeout = yield from $timeout;
|
|
|
|
} elseif ($timeout instanceof Promise) {
|
2020-07-23 14:18:33 +02:00
|
|
|
/** @psalm-var ?int */
|
2020-07-21 18:06:19 +02:00
|
|
|
$timeout = yield $timeout;
|
|
|
|
}
|
|
|
|
if ($timeout === self::PAUSE) {
|
|
|
|
$this->reportPause(0);
|
|
|
|
} elseif ($timeout > 0) {
|
|
|
|
$this->reportPause($timeout);
|
|
|
|
}
|
|
|
|
/** @psalm-suppress MixedArgument */
|
|
|
|
if ($timeout === self::STOP || yield $this->waitSignal($this->pause($timeout))) {
|
2020-07-23 17:03:53 +02:00
|
|
|
break;
|
2020-07-21 18:06:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Report pause, can be overriden for logging.
|
|
|
|
*
|
|
|
|
* @param integer $timeout Pause duration, 0 = forever
|
|
|
|
*
|
|
|
|
* @return void
|
2020-07-23 17:05:15 +02:00
|
|
|
*
|
2020-07-23 17:03:53 +02:00
|
|
|
* @codeCoverageIgnore
|
2020-07-21 18:06:19 +02:00
|
|
|
*/
|
|
|
|
protected function reportPause(int $timeout): void
|
|
|
|
{
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
* Get loop name.
|
|
|
|
*
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
public function __toString(): string
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
}
|