2016-12-30 02:16:04 +01:00
|
|
|
<?php
|
2015-12-05 06:50:32 +01:00
|
|
|
|
2016-08-23 23:47:40 +02:00
|
|
|
namespace Amp\Parallel\Sync;
|
2016-08-18 18:04:48 +02:00
|
|
|
|
2017-05-18 09:51:31 +02:00
|
|
|
use Amp\ByteStream\InputStream;
|
|
|
|
use Amp\ByteStream\OutputStream;
|
|
|
|
use Amp\ByteStream\StreamException;
|
|
|
|
use Amp\Promise;
|
2017-12-08 03:49:44 +01:00
|
|
|
use function Amp\call;
|
2015-12-05 06:50:32 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* An asynchronous channel for sending data between threads and processes.
|
|
|
|
*
|
|
|
|
* Supports full duplex read and write.
|
|
|
|
*/
|
2018-10-21 17:54:46 +02:00
|
|
|
final class ChannelledStream implements Channel
|
2018-10-07 16:50:45 +02:00
|
|
|
{
|
2020-02-15 00:33:38 +01:00
|
|
|
/** @var InputStream */
|
2015-12-05 06:50:32 +01:00
|
|
|
private $read;
|
|
|
|
|
2020-02-15 00:33:38 +01:00
|
|
|
/** @var OutputStream */
|
2015-12-05 06:50:32 +01:00
|
|
|
private $write;
|
|
|
|
|
2017-04-16 17:12:42 +02:00
|
|
|
/** @var \SplQueue */
|
|
|
|
private $received;
|
|
|
|
|
2020-02-15 00:33:38 +01:00
|
|
|
/** @var ChannelParser */
|
2017-04-16 17:12:42 +02:00
|
|
|
private $parser;
|
2015-12-05 06:50:32 +01:00
|
|
|
|
|
|
|
/**
|
2017-03-25 07:19:46 +01:00
|
|
|
* Creates a new channel from the given stream objects. Note that $read and $write can be the same object.
|
2015-12-05 06:50:32 +01:00
|
|
|
*
|
2020-02-15 00:33:38 +01:00
|
|
|
* @param InputStream $read
|
|
|
|
* @param OutputStream $write
|
2015-12-05 06:50:32 +01:00
|
|
|
*/
|
2018-10-07 16:50:45 +02:00
|
|
|
public function __construct(InputStream $read, OutputStream $write)
|
|
|
|
{
|
2015-12-05 06:50:32 +01:00
|
|
|
$this->read = $read;
|
2017-03-25 07:19:46 +01:00
|
|
|
$this->write = $write;
|
2017-04-16 17:12:42 +02:00
|
|
|
$this->received = new \SplQueue;
|
2017-06-08 06:33:13 +02:00
|
|
|
$this->parser = new ChannelParser([$this->received, 'push']);
|
2015-12-05 06:50:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-07 16:50:45 +02:00
|
|
|
public function send($data): Promise
|
|
|
|
{
|
2019-08-28 01:14:56 +02:00
|
|
|
return call(function () use ($data): \Generator {
|
2017-12-08 03:49:44 +01:00
|
|
|
try {
|
|
|
|
return yield $this->write->write($this->parser->encode($data));
|
|
|
|
} catch (StreamException $exception) {
|
2018-10-25 05:49:01 +02:00
|
|
|
throw new ChannelException("Sending on the channel failed. Did the context die?", 0, $exception);
|
2017-12-08 03:49:44 +01:00
|
|
|
}
|
|
|
|
});
|
2015-12-05 06:50:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* {@inheritdoc}
|
|
|
|
*/
|
2018-10-07 16:50:45 +02:00
|
|
|
public function receive(): Promise
|
|
|
|
{
|
2019-08-28 01:14:56 +02:00
|
|
|
return call(function (): \Generator {
|
2017-12-08 03:49:44 +01:00
|
|
|
while ($this->received->isEmpty()) {
|
|
|
|
try {
|
2017-12-10 20:54:11 +01:00
|
|
|
$chunk = yield $this->read->read();
|
2017-12-08 03:49:44 +01:00
|
|
|
} catch (StreamException $exception) {
|
2018-10-25 05:49:01 +02:00
|
|
|
throw new ChannelException("Reading from the channel failed. Did the context die?", 0, $exception);
|
2017-12-08 03:49:44 +01:00
|
|
|
}
|
2017-12-10 20:54:11 +01:00
|
|
|
|
|
|
|
if ($chunk === null) {
|
|
|
|
throw new ChannelException("The channel closed unexpectedly. Did the context die?");
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->parser->push($chunk);
|
2017-04-16 17:12:42 +02:00
|
|
|
}
|
2015-12-05 06:50:32 +01:00
|
|
|
|
2017-12-08 03:49:44 +01:00
|
|
|
return $this->received->shift();
|
|
|
|
});
|
2015-12-05 06:50:32 +01:00
|
|
|
}
|
|
|
|
}
|