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

118 lines
3.1 KiB
PHP
Raw Normal View History

2015-12-05 06:50:32 +01:00
<?php
2016-08-18 18:04:48 +02:00
namespace Amp\Concurrent\Sync;
2016-08-19 00:36:58 +02:00
use Amp\Concurrent\{ ChannelException, SerializationException };
2016-08-18 18:04:48 +02:00
use Amp\Coroutine;
use Amp\Stream\Stream;
use Interop\Async\Awaitable;
2015-12-05 06:50:32 +01:00
/**
* An asynchronous channel for sending data between threads and processes.
*
* Supports full duplex read and write.
*/
2016-08-18 18:04:48 +02:00
class ChannelledStream implements Channel {
const HEADER_LENGTH = 5;
2015-12-05 06:50:32 +01:00
/**
2016-08-18 18:04:48 +02:00
* @var \Amp\Stream\Stream
2015-12-05 06:50:32 +01:00
*/
private $read;
/**
2016-08-18 18:04:48 +02:00
* @var \Amp\Stream\Stream
2015-12-05 06:50:32 +01:00
*/
private $write;
/**
* @var \Closure
*/
private $errorHandler;
/**
* Creates a new channel instance.
*
2016-08-18 18:04:48 +02:00
* @param \Amp\Stream\Stream $read
* @param \Amp\Stream\Stream|null $write
2015-12-05 06:50:32 +01:00
*/
2016-08-18 18:04:48 +02:00
public function __construct(Stream $read, Stream $write = null) {
2015-12-05 06:50:32 +01:00
if (null === $write) {
$this->write = $read;
} else {
$this->write = $write;
}
$this->read = $read;
2016-08-18 18:04:48 +02:00
$this->errorHandler = static function ($errno, $errstr) {
throw new ChannelException(\sprintf('Received corrupted data. Errno: %d; %s', $errno, $errstr));
2015-12-05 06:50:32 +01:00
};
}
/**
* {@inheritdoc}
*/
2016-08-18 18:04:48 +02:00
public function send($data): Awaitable {
return new Coroutine($this->doSend($data));
}
public function doSend($data): \Generator {
2015-12-05 06:50:32 +01:00
// Serialize the data to send into the channel.
try {
2016-08-18 18:04:48 +02:00
$serialized = \serialize($data);
2016-01-23 07:00:56 +01:00
} catch (\Throwable $exception) {
2016-01-23 18:20:58 +01:00
throw new SerializationException(
2016-08-18 18:04:48 +02:00
"The given data cannot be sent because it is not serializable.", $exception
2015-12-05 06:50:32 +01:00
);
}
2016-08-18 18:04:48 +02:00
$length = \strlen($serialized);
2015-12-05 06:50:32 +01:00
try {
2016-08-18 18:04:48 +02:00
yield $this->write->write(\pack("CL", 0, $length) . $serialized);
2016-01-23 18:29:22 +01:00
} catch (\Throwable $exception) {
2016-08-18 18:04:48 +02:00
throw new ChannelException("Sending on the channel failed. Did the context die?", $exception);
2015-12-05 06:50:32 +01:00
}
2016-08-18 18:04:48 +02:00
2016-01-23 07:00:56 +01:00
return $length;
2015-12-05 06:50:32 +01:00
}
/**
* {@inheritdoc}
*/
2016-08-18 18:04:48 +02:00
public function receive(): Awaitable {
return new Coroutine($this->doReceive());
}
public function doReceive(): \Generator {
2015-12-05 06:50:32 +01:00
try {
2016-08-18 18:04:48 +02:00
// Read the message length first to determine how much needs to be read from the stream.
$buffer = yield $this->read->read(self::HEADER_LENGTH);
$data = \unpack("Cprefix/Llength", $buffer);
2015-12-05 07:54:15 +01:00
2016-08-18 18:04:48 +02:00
if ($data["prefix"] !== 0) {
throw new ChannelException("Invalid header received");
2015-12-05 07:54:15 +01:00
}
2016-08-18 18:04:48 +02:00
$buffer = yield $this->read->read($data["length"]);
2016-01-23 18:29:22 +01:00
} catch (\Throwable $exception) {
2016-08-18 18:04:48 +02:00
throw new ChannelException("Reading from the channel failed. Did the context die?", $exception);
2015-12-05 06:50:32 +01:00
}
2016-08-18 18:04:48 +02:00
\set_error_handler($this->errorHandler);
2015-12-05 06:50:32 +01:00
// Attempt to unserialize the received data.
try {
2016-08-18 18:04:48 +02:00
$data = \unserialize($buffer);
2016-01-23 07:00:56 +01:00
} catch (\Throwable $exception) {
2016-08-18 18:04:48 +02:00
throw new SerializationException("Exception thrown when unserializing data", $exception);
2015-12-05 06:50:32 +01:00
} finally {
2016-08-18 18:04:48 +02:00
\restore_error_handler();
2015-12-05 06:50:32 +01:00
}
2016-01-23 07:00:56 +01:00
return $data;
2015-12-05 06:50:32 +01:00
}
}