1
0
mirror of https://github.com/danog/parallel.git synced 2024-12-02 17:52:14 +01:00
parallel/lib/Sync/ChannelledStream.php

82 lines
2.2 KiB
PHP
Raw Normal View History

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;
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-07 16:50:45 +02:00
class ChannelledStream implements Channel
{
/** @var \Amp\ByteStream\InputStream */
2015-12-05 06:50:32 +01:00
private $read;
/** @var \Amp\ByteStream\OutputStream */
2015-12-05 06:50:32 +01:00
private $write;
/** @var \SplQueue */
private $received;
/** @var \Amp\Parser\Parser */
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
*
* @param \Amp\ByteStream\InputStream $read
* @param \Amp\ByteStream\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;
$this->received = new \SplQueue;
$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
{
return call(function () use ($data) {
try {
return yield $this->write->write($this->parser->encode($data));
} catch (StreamException $exception) {
throw new ChannelException("Sending on the channel failed. Did the context die?", $exception);
}
});
2015-12-05 06:50:32 +01:00
}
/**
* {@inheritdoc}
*/
2018-10-07 16:50:45 +02:00
public function receive(): Promise
{
return call(function () {
while ($this->received->isEmpty()) {
try {
$chunk = yield $this->read->read();
} catch (StreamException $exception) {
throw new ChannelException("Reading from the channel failed. Did the context die?", $exception);
}
if ($chunk === null) {
throw new ChannelException("The channel closed unexpectedly. Did the context die?");
}
$this->parser->push($chunk);
}
2015-12-05 06:50:32 +01:00
return $this->received->shift();
});
2015-12-05 06:50:32 +01:00
}
}