/** * Read the next frame. * * @recoil-coroutine * * @return IncomingFrame The value read from the channel. * @throws ChannelClosedException The channel has been closed. */ public function read() : Generator { if ($this->stream === null) { throw ChannelClosedException::channelClosed(); } $buffer = ''; $required = 0; try { feed: $frame = $this->parser->feed($buffer, $required); } catch (RecoilAmqpException $e) { assert(Debug::dumpException('#' . (int) $this->stream, $e)); throw $e; } if ($frame === null) { // @todo handle stream close and throw channel closed exception $buffer = (yield Recoil::read($this->stream, $required)); if ($buffer === '') { \fclose($this->stream); $this->stream = null; throw ChannelClosedException::channelClosed(); } assert(Debug::dumpIncomingHex('#' . (int) $this->stream, $buffer)); goto feed; } assert(Debug::dumpIncomingFrame('#' . (int) $this->stream, $frame)); return $frame; }