2020-07-21 22:12:34 +02:00
# IPC
2020-07-23 14:30:56 +02:00
![Build status ](https://github.com/danog/loop/workflows/build/badge.svg )
2020-07-29 23:33:31 +02:00
[![codecov ](https://codecov.io/gh/danog/loop/branch/master/graph/badge.svg )](https://codecov.io/gh/danog/loop)
![License ](https://img.shields.io/badge/license-MIT-blue.svg )
2020-07-21 22:12:34 +02:00
2020-07-24 19:29:14 +02:00
`danog/loop` provides a set of powerful async loop APIs for executing operations periodically or on demand, in background loops a-la threads.
A more flexible and powerful alternative to [AMPHP ](https://amphp.org )'s [repeat ](https://amphp.org/amp/event-loop/api#repeat ) function, allowing dynamically changeable repeat periods, resumes and signaling.
2020-07-21 22:12:34 +02:00
## Installation
```bash
composer require danog/loop
```
2020-07-24 19:24:04 +02:00
## API
* Basic
2020-07-24 19:28:17 +02:00
* [GenericLoop ](#GenericLoop )
* [PeriodicLoop ](#PeriodicLoop )
2020-07-24 19:24:04 +02:00
* Advanced
2020-07-24 19:28:17 +02:00
* [Loop ](#Loop )
* [ResumableLoop ](#ResumableLoop )
* [SignalLoop ](#SignalLoop )
* [ResumableSignalLoop ](#ResumableSignalLoop )
2020-07-21 22:12:34 +02:00
All loop APIs are defined by a set of [interfaces ](https://github.com/danog/loop/tree/master/lib/Interfaces ): however, to use them, you would usually have to extend only one of the [abstract class implementations ](https://github.com/danog/loop/tree/master/lib ).
### Loop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/LoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/Loop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
A basic loop, capable of running in background (asynchronously) the code contained in the `loop` function.
2020-07-24 19:24:04 +02:00
API:
2020-07-21 22:12:34 +02:00
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop;
2020-07-21 22:12:34 +02:00
2020-07-24 19:24:04 +02:00
abstract class Loop
2020-07-21 22:12:34 +02:00
{
2020-07-24 19:24:04 +02:00
abstract public function loop(): \Generator;
abstract public function __toString(): string;
2020-07-21 22:12:34 +02:00
public function start(): bool;
public function isRunning(): bool;
2020-07-24 19:24:04 +02:00
protected function startedLoop(): void;
protected function exitedLoop(): void;
2020-07-21 22:12:34 +02:00
}
```
2020-07-24 19:24:04 +02:00
#### loop()
The `loop` [async coroutine ](https://amphp.org/amp/coroutines/ ) will be run only once, every time the `start` method is called.
#### __toString()
This method should return the loop's name.
It's useful for implementing the [log methods ](#startedLoop ).
#### start()
Asynchronously starts the `loop` methods once in background.
2020-07-21 22:12:34 +02:00
Multiple calls to `start` will be ignored, returning `false` instead of `true` .
2020-07-24 19:24:04 +02:00
#### isRunning()
2020-07-21 22:12:34 +02:00
You can use the `isRunning` method to check if the loop is already running.
2020-07-24 19:24:04 +02:00
#### startedLoop()
Optionally, you can override this method to detect and log when the loop is started.
Make sure to always call the parent `startedLoop()` method to avoid issues.
You can use directly `$this` as loop name when logging, thanks to the custom [__toString ](#__toString ) method.
#### exitedLoop()
Optionally, you can override this method to detect and log when the loop is ended.
Make sure to always call the parent `exitedLoop()` method to avoid issues.
You can use directly `$this` as loop name when logging, thanks to the custom [__toString ](#__toString ) method.
2020-07-21 22:12:34 +02:00
### ResumableLoop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/ResumableLoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/ResumableLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
A way more useful loop that exposes APIs to pause and resume the execution of the loop, both from outside of the loop, and in a cron-like manner from inside of the loop.
```php
namespace danog\Loop;
2020-07-24 19:24:04 +02:00
abstract class ResumableLoop extends Loop
2020-07-21 22:12:34 +02:00
{
2020-07-24 19:24:04 +02:00
public function pause(?int $time = null): Promise;
public function resume(): Promise;
2020-07-21 22:12:34 +02:00
}
```
2020-07-24 19:24:04 +02:00
All methods from [Loop ](#loop ), plus:
#### pause()
Pauses the loop for the specified number of milliseconds, or forever if `null` is provided.
#### resume()
Forcefully resume the loop from the outside.
Returns a promise that is resolved when the loop is paused again.
2020-07-21 22:12:34 +02:00
### SignalLoop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/SignalLoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/SignalLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
Yet another loop interface that exposes APIs to send signals to the loop, useful to force the termination of a loop from the outside, or to send data into it.
```php
namespace danog\Loop;
2020-07-24 19:24:04 +02:00
abstract class SignalLoop extends Loop
2020-07-21 22:12:34 +02:00
{
2020-07-24 19:32:12 +02:00
public function signal($what): void;
2020-07-21 22:12:34 +02:00
public function waitSignal($promise): Promise;
}
```
2020-07-24 19:24:04 +02:00
All methods from [Loop ](#loop ), plus:
#### signal()
Sends a signal to the loop: can be anything, but typically `true` is often used as termination signal.
Signaling can be used as a message exchange mechanism a-la IPC, and can also be used to throw exceptions inside the loop.
#### waitSignal()
Resolve the provided promise or return|throw passed signal.
2020-07-21 22:12:34 +02:00
### ResumableSignalLoop
2020-07-24 19:28:17 +02:00
[Interface ](https://github.com/danog/loop/blob/master/lib/Interfaces/ResumableSignalLoopInterface.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/2.%20Advanced/ResumableSignalLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
This is what you would usually use to build a full async loop.
2020-07-24 19:32:12 +02:00
All loop interfaces and loop implementations are combined into a single class you can extend.
2020-07-21 22:12:34 +02:00
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop;
abstract class ResumableSignalLoop extends SignalLoop, ResumableSignalLoop
2020-07-21 22:12:34 +02:00
{
}
```
2020-07-24 19:24:04 +02:00
The class is actually composited using traits to feature all methods from [SignalLoop ](#SignalLoop ) and [ResumableSignalLoop ](#ResumableSignalLoop ).
2020-07-21 22:12:34 +02:00
### GenericLoop
2020-07-24 19:28:17 +02:00
[Class ](https://github.com/danog/loop/blob/master/lib/Generic/GenericLoop.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/1.%20Basic/GenericLoop.php )
2020-07-24 19:24:04 +02:00
If you want a simpler way to use the `ResumableSignalLoop` , you can use the GenericLoop.
2020-07-21 22:12:34 +02:00
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop\Generic;
class GenericLoop extends ResumableSignalLoop
{
/**
* Stop the loop.
*/
const STOP = -1;
2020-07-21 22:12:34 +02:00
/**
2020-07-24 19:24:04 +02:00
* Pause the loop.
*/
const PAUSE = null;
/**
* Rerun the loop.
*/
const CONTINUE = 0;
/**
* Constructor.
*
* If possible, the callable will be bound to the current instance of the loop.
*
* @param callable $callable Callable to run
* @param string $name Loop name
*/
2020-07-24 19:28:17 +02:00
public function __construct(callable $callable, string $name);
2020-07-24 19:24:04 +02:00
/**
* Report pause, can be overriden for logging.
2020-07-21 22:12:34 +02:00
*
2020-07-24 19:24:04 +02:00
* @param integer $timeout Pause duration, 0 = forever
*
* @return void
2020-07-21 22:12:34 +02:00
*/
2020-07-24 19:24:04 +02:00
protected function reportPause(int $timeout): void;
/**
* Get loop name, provided to constructor.
*
* @return string
*/
public function __toString(): string;
}
2020-07-21 22:12:34 +02:00
```
2020-07-24 19:24:04 +02:00
The callback will be bound to the `GenericLoop` instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can get the loop name by casting `$this` to a string, use the pause/waitSignal methods & so on).
2020-07-21 22:12:34 +02:00
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 the `resume` method is called on the loop object from outside the loop)
* `GenericLoop::CONTINUE` - Return this if you want to rerun the loop without waiting
If the callable does not return anything, the loop will behave is if `GenericLoop::PAUSE` was returned.
### PeriodicLoop
2020-07-24 19:28:17 +02:00
[Class ](https://github.com/danog/loop/blob/master/lib/Generic/PeriodicLoop.php ) - [Example ](https://github.com/danog/loop/blob/master/examples/1.%20Basic/PeriodicLoop.php )
2020-07-24 19:24:04 +02:00
2020-07-21 22:12:34 +02:00
If you simply want to execute an action every N seconds, [PeriodicLoop ](https://github.com/danog/MadelineProto/blob/master/src/danog/MadelineProto/Loop/Generic/PeriodicLoop.php ) is the way to go.
```php
2020-07-24 19:24:04 +02:00
namespace danog\Loop\Generic;
class PeriodicLoop extends ResumableSignalLoop
{
2020-07-21 22:12:34 +02:00
/**
* Constructor.
*
2020-07-24 19:24:04 +02:00
* If possible, the callable will be bound to the current instance of the loop.
*
* @param callable $callback Callback to call
* @param string $name Loop name
* @param ?int $interval Loop interval
2020-07-21 22:12:34 +02:00
*/
2020-07-24 19:28:17 +02:00
public function __construct(callable $callback, string $name, ?int $interval);
2020-07-24 19:24:04 +02:00
/**
* Get name of the loop, passed to the constructor.
*
* @return string
*/
2020-07-24 19:28:17 +02:00
public function __toString(): string;
2020-07-24 19:24:04 +02:00
}
2020-07-21 22:12:34 +02:00
```
2020-07-24 19:24:04 +02:00
`PeriodicLoop` runs a callback at a periodic interval.
2020-07-24 19:34:52 +02:00
The callback will be bound to the `PeriodicLoop` instance: this means that you will be able to use `$this` as if the callback were actually the `loop` function (you can get the loop name by casting `$this` to a string, use the pause/waitSignal methods & so on).
2020-07-29 23:33:31 +02:00
The loop can be stopped from the outside or from the inside by signaling or returning `true` .